fix(mini-user): persist bind-phone session and stop login bounce
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Phone bind discarded the new JWT after account merge, so the next page 401'd back to login. Also harden 401 race, location deny cache, unpaid repay CTA, and finishLoginNavigate.
This commit is contained in:
@@ -66,8 +66,15 @@ export default function LoginPage() {
|
||||
setCompleteMode(null);
|
||||
return;
|
||||
}
|
||||
// 完善资料场景才拉 profile;普通登录勿抢跑 /auth/me,避免旧 token 401 与短信登录竞态
|
||||
if (!needPhone && !needWechat) {
|
||||
setCompleteMode(null);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
fetchUserProfile()
|
||||
.then((me) => {
|
||||
if (cancelled) return;
|
||||
if (needPhone && !me.phoneVerified) {
|
||||
setCompleteMode('phone');
|
||||
return;
|
||||
@@ -76,13 +83,14 @@ export default function LoginPage() {
|
||||
setCompleteMode('wechat');
|
||||
return;
|
||||
}
|
||||
if (needPhone || needWechat) {
|
||||
finishLoginNavigate(returnTo);
|
||||
return;
|
||||
}
|
||||
setCompleteMode(null);
|
||||
finishLoginNavigate(returnTo);
|
||||
})
|
||||
.catch(() => setCompleteMode(null));
|
||||
.catch(() => {
|
||||
if (!cancelled) setCompleteMode(null);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [needPhone, needWechat, returnTo]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -103,6 +111,7 @@ export default function LoginPage() {
|
||||
data: SessionPayload | WechatLoginResult,
|
||||
phone?: string,
|
||||
wxInfo?: MiniWechatProfile | null,
|
||||
successToast = '登录成功',
|
||||
) {
|
||||
if (!data.accessToken) return;
|
||||
if (phone) saveUserPhone(phone);
|
||||
@@ -116,7 +125,7 @@ export default function LoginPage() {
|
||||
.then((me) => resolveDefaultUserPhone(me))
|
||||
.catch(() => {});
|
||||
}
|
||||
toast('登录成功', 'success');
|
||||
toast(successToast, 'success');
|
||||
finishLoginNavigate(returnTo);
|
||||
}
|
||||
|
||||
@@ -188,19 +197,26 @@ export default function LoginPage() {
|
||||
return;
|
||||
}
|
||||
if (completeMode === 'phone' && isLoggedIn()) {
|
||||
await request('/auth/phone/bind', {
|
||||
// bind 返回新 session(合并账号后旧 guest JWT 立刻失效),必须落盘后再离开
|
||||
const data = await request<SessionPayload>('/auth/phone/bind', {
|
||||
method: 'POST',
|
||||
data: { phone: normalized, code: code.trim() },
|
||||
});
|
||||
saveUserPhone(normalized);
|
||||
toast('手机号验证成功', 'success');
|
||||
finishLoginNavigate(returnTo);
|
||||
if (!data?.accessToken) {
|
||||
setMsg('手机号验证成功但会话未返回,请重新登录');
|
||||
return;
|
||||
}
|
||||
applySessionAndLeave(data, normalized, null, '手机号验证成功');
|
||||
return;
|
||||
}
|
||||
const data = await request<SessionPayload>('/auth/login/sms', {
|
||||
method: 'POST',
|
||||
data: { phone: normalized, code: code.trim() },
|
||||
});
|
||||
if (!data?.accessToken) {
|
||||
setMsg('登录成功但未返回令牌,请重试');
|
||||
return;
|
||||
}
|
||||
applySessionAndLeave(data, normalized);
|
||||
} catch (e) {
|
||||
setMsg(e instanceof Error ? e.message : '登录失败');
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import { useRouter, useShareAppMessage, useShareTimeline } from '@tarojs/taro';
|
||||
import Taro, { useRouter, useShareAppMessage, useShareTimeline } from '@tarojs/taro';
|
||||
import PageShell from '../../components/PageShell';
|
||||
import SubPageHeader from '../../components/SubPageHeader';
|
||||
import ShareNavButton from '../../components/ShareNavButton';
|
||||
import WechatShareReady from '../../components/WechatShareReady';
|
||||
import { request, toast } from '../../lib/api';
|
||||
import { buildPayUrl } from '../../lib/checkout-nav';
|
||||
import {
|
||||
DEFAULT_SHARE_DESC,
|
||||
DEFAULT_SHARE_TITLE,
|
||||
@@ -21,6 +22,19 @@ type OrderDetail = {
|
||||
qty?: number;
|
||||
addressSnapshot?: string;
|
||||
createdAt?: string;
|
||||
originOrderId?: string | null;
|
||||
};
|
||||
|
||||
const STATUS_LABELS: Record<string, string> = {
|
||||
PENDING_PAY: '待付款',
|
||||
PENDING_SHIP: '待发货',
|
||||
OUT_WAREHOUSE: '出库中',
|
||||
SHIPPING: '配送中',
|
||||
PENDING_RECEIVE: '待签收',
|
||||
COMPLETED: '已完成',
|
||||
CANCELLED: '已取消',
|
||||
REFUNDING: '退款中',
|
||||
REFUNDED: '已退款',
|
||||
};
|
||||
|
||||
export default function OrderDetailPage() {
|
||||
@@ -35,6 +49,8 @@ export default function OrderDetailPage() {
|
||||
.catch((e) => toast(e instanceof Error ? e.message : '加载失败'));
|
||||
}, [orderId]);
|
||||
|
||||
const canPay = !!order && order.status === 'PENDING_PAY' && !order.originOrderId;
|
||||
|
||||
const sharePayload = useMemo(
|
||||
() => ({
|
||||
title: order?.productName
|
||||
@@ -52,8 +68,13 @@ export default function OrderDetailPage() {
|
||||
query: orderId ? `id=${orderId}` : '',
|
||||
}));
|
||||
|
||||
function goPay() {
|
||||
if (!order) return;
|
||||
Taro.navigateTo({ url: buildPayUrl({ orderId: order.id }) });
|
||||
}
|
||||
|
||||
return (
|
||||
<PageShell variant="sub" className="order-detail-page">
|
||||
<PageShell variant="sub" className={`order-detail-page${canPay ? ' order-detail-page--with-pay' : ''}`}>
|
||||
<WechatShareReady payload={sharePayload} />
|
||||
<SubPageHeader
|
||||
title="订单详情"
|
||||
@@ -66,7 +87,9 @@ export default function OrderDetailPage() {
|
||||
<>
|
||||
<View className="order-card">
|
||||
<Text className="order-card-title">订单状态</Text>
|
||||
<Text className="order-list-status">{order.status || '处理中'}</Text>
|
||||
<Text className="order-list-status">
|
||||
{STATUS_LABELS[order.status || ''] || order.status || '处理中'}
|
||||
</Text>
|
||||
</View>
|
||||
<View className="order-card">
|
||||
<Text className="order-card-title">商品信息</Text>
|
||||
@@ -103,6 +126,20 @@ export default function OrderDetailPage() {
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{canPay && order && (
|
||||
<View className="pay-bar order-detail-pay-bar">
|
||||
<View className="order-confirm-total">
|
||||
<Text className="order-confirm-total-label">待支付</Text>
|
||||
<Text className="order-confirm-total-value">
|
||||
¥{Number(order.payAmount ?? 0).toFixed(2)}
|
||||
</Text>
|
||||
</View>
|
||||
<View className="order-confirm-submit" onClick={goPay}>
|
||||
去付款
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user