diff --git a/apps/h5-user/src/components/PhoneVerifySheet.tsx b/apps/h5-user/src/components/PhoneVerifySheet.tsx index 9bfc2c5..1cb2032 100644 --- a/apps/h5-user/src/components/PhoneVerifySheet.tsx +++ b/apps/h5-user/src/components/PhoneVerifySheet.tsx @@ -4,11 +4,18 @@ import { normalizePhoneInput, validateMobilePhone } from '../lib/phone'; type PhoneVerifySheetProps = { open: boolean; + /** 打开时预填手机号(如收货地址中的手机号) */ + defaultPhone?: string; onClose: () => void; onSuccess: () => void; }; -export default function PhoneVerifySheet({ open, onClose, onSuccess }: PhoneVerifySheetProps) { +export default function PhoneVerifySheet({ + open, + defaultPhone, + onClose, + onSuccess, +}: PhoneVerifySheetProps) { const [phone, setPhone] = useState(''); const [code, setCode] = useState(''); const [msg, setMsg] = useState(''); @@ -21,8 +28,15 @@ export default function PhoneVerifySheet({ open, onClose, onSuccess }: PhoneVeri setCode(''); setMsg(''); setCodeCooldown(0); + return; } - }, [open]); + if (defaultPhone) { + const normalized = normalizePhoneInput(defaultPhone); + if (validateMobilePhone(normalized).ok) { + setPhone(normalized); + } + } + }, [open, defaultPhone]); async function sendCode() { const phoneCheck = validateMobilePhone(phone); diff --git a/apps/h5-user/src/lib/api.ts b/apps/h5-user/src/lib/api.ts index 9c9ab86..bc7ddde 100644 --- a/apps/h5-user/src/lib/api.ts +++ b/apps/h5-user/src/lib/api.ts @@ -56,6 +56,15 @@ export function isLoggedIn() { return !!localStorage.getItem(ACCESS_TOKEN); } +const AUTH_RECOVERY_EXEMPT_PATHS = ['/auth/session/bootstrap', '/auth/token/refresh']; + +async function recoverSession(): Promise { + const refreshed = await refreshSession(); + if (refreshed) return refreshed; + clearAuth(); + return bootstrapSession(); +} + async function rawRequest( path: string, options: RequestInit = {}, @@ -79,12 +88,34 @@ async function rawRequest( return json.data as T; } +async function requestWithAuthRetry( + path: string, + options: RequestInit = {}, + retried = false, +): Promise { + try { + return await rawRequest(path, options); + } catch (e) { + const err = e as Error & { status?: number }; + const canRecover = + err.status === 401 && + !retried && + !AUTH_RECOVERY_EXEMPT_PATHS.some((p) => path.startsWith(p)); + if (!canRecover) throw e; + await recoverSession(); + return requestWithAuthRetry(path, options, true); + } +} + export async function request( _clientApp: string, path: string, options: RequestInit = {}, ): Promise { - return rawRequest(path, options); + if (!isLoggedIn() && !AUTH_RECOVERY_EXEMPT_PATHS.some((p) => path.startsWith(p))) { + await bootstrapSession(); + } + return requestWithAuthRetry(path, options); } export async function bootstrapSession(): Promise { @@ -145,7 +176,10 @@ export async function ensureSession(): Promise { } export async function bindPhone(phone: string, code: string): Promise { - const data = await rawRequest('/auth/phone/bind', { + if (!isLoggedIn()) { + await bootstrapSession(); + } + const data = await requestWithAuthRetry('/auth/phone/bind', { method: 'POST', body: JSON.stringify({ phone, code }), }); diff --git a/apps/h5-user/src/pages/AddressEditPage.tsx b/apps/h5-user/src/pages/AddressEditPage.tsx index f8f4207..8967412 100644 --- a/apps/h5-user/src/pages/AddressEditPage.tsx +++ b/apps/h5-user/src/pages/AddressEditPage.tsx @@ -92,6 +92,8 @@ export default function AddressEditPage() { }); } navigate(buildAddressListUrl(checkoutCtx)); + } catch (e) { + setError(e instanceof Error ? e.message : '保存失败'); } finally { setSaving(false); } diff --git a/apps/h5-user/src/pages/OrderConfirmPage.tsx b/apps/h5-user/src/pages/OrderConfirmPage.tsx index d0abbe2..ebb74f9 100644 --- a/apps/h5-user/src/pages/OrderConfirmPage.tsx +++ b/apps/h5-user/src/pages/OrderConfirmPage.tsx @@ -329,6 +329,7 @@ export default function OrderConfirmPage() { { setShowPhoneVerify(false); setPendingSubmit(false);