From fe116b9d99112ffa59f0df17ad333311d9c1e3cf Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Wed, 27 May 2026 02:19:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E4=BB=A5=E6=98=BE=E7=A4=BA=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E4=B8=AD=E7=9A=84=E8=B0=83=E8=AF=95=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/pages/LoginPage.tsx | 106 ++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/pages/LoginPage.tsx b/frontend/src/app/pages/LoginPage.tsx index 3366ada..535fbb4 100644 --- a/frontend/src/app/pages/LoginPage.tsx +++ b/frontend/src/app/pages/LoginPage.tsx @@ -11,51 +11,135 @@ function isWechatMiniProgram(): boolean { return ua.includes("micromessenger") && ua.includes("miniprogram"); } +// โ”€โ”€โ”€ ๐Ÿž ่ฐƒ่ฏ•ๅŒบๅŸŸ๏ผšๆŽ’ๆŸฅๅŽๅˆ ้™ค โ”€โ”€โ”€ + +interface DebugInfo { + url: string; + ua: string; + isWxMp: boolean; + hasTokenParam: boolean; + tokenPrefix: string; + decodeResult: string; + fetchError: string; + devLoginError: string; + step: string; + tokenInStorage: boolean; +} + +const INIT_DEBUG: DebugInfo = { + url: "", ua: "", isWxMp: false, hasTokenParam: false, + tokenPrefix: "", decodeResult: "", fetchError: "", + devLoginError: "", step: "init", tokenInStorage: false, +}; + +function DebugPanel({ info }: { info: DebugInfo }) { + return ( +
+
๐Ÿž ่ฐƒ่ฏ•ไฟกๆฏ (ๅ…ณ้—ญ้œ€ๅŽปๆމ ?debug=1)
+ + + {Object.entries(info).map(([k, v]) => ( + + + + + ))} + +
{k}{v || (็ฉบ)}
+
+ ); +} + +// โ”€โ”€โ”€ ๐Ÿž ่ฐƒ่ฏ•ๅŒบๅŸŸ็ป“ๆŸ โ”€โ”€โ”€ + export function LoginPage() { const navigate = useNavigate(); const { setTokenAndUser, fetchProfile } = useUser(); const [error, setError] = useState(""); + const [debug] = useState(() => ({ ...INIT_DEBUG })); + + // โ”€โ”€โ”€ ๐Ÿž ่ฐƒ่ฏ•ๆ›ดๆ–ฐๅ‡ฝๆ•ฐ โ”€โ”€โ”€ + const dbg = (patch: Partial) => { + if (debug) Object.assign(debug, patch); + }; + // โ”€โ”€โ”€ ๐Ÿž ่ฐƒ่ฏ•ๆ›ดๆ–ฐ็ป“ๆŸ โ”€โ”€โ”€ useEffect(() => { + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + if (debug) { + debug.url = window.location.href; + debug.ua = navigator.userAgent; + debug.tokenInStorage = !!getToken(); + } + // โ”€โ”€โ”€ ๐Ÿž ็ป“ๆŸ โ”€โ”€โ”€ + // ไผ˜ๅ…ˆไฝฟ็”จ URL ไธญ็š„ token๏ผˆๅฐ็จ‹ๅบไผ ๅ‚๏ผ‰ const params = new URLSearchParams(window.location.search); const tokenFromUrl = params.get('token'); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + dbg({ step: "check-url-token", hasTokenParam: !!tokenFromUrl, tokenPrefix: tokenFromUrl ? tokenFromUrl.substring(0, 30) + "..." : "" }); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + if (tokenFromUrl) { // token ๅ˜ไบ†ๅฐฑๆ›ดๆ–ฐๅญ˜ๅ‚จ const oldToken = getToken(); if (tokenFromUrl !== oldToken) { - const payload = decodeToken(tokenFromUrl); - setTokenAndUser(tokenFromUrl, { - id: String(payload.uid), - openid: payload.openid, - phone: payload.phone, - }); + try { + const payload = decodeToken(tokenFromUrl); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + dbg({ step: "decode-ok", decodeResult: `uid=${payload.uid}, openid=${payload.openid?.substring(0,15)}..., phone=${payload.phone}` }); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + setTokenAndUser(tokenFromUrl, { + id: String(payload.uid), + openid: payload.openid, + phone: payload.phone, + }); + } catch (e: any) { + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + dbg({ step: "decode-fail", decodeResult: `่งฃๆžๅคฑ่ดฅ: ${e?.message || e}` }); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + setError("Token ่งฃๆžๅคฑ่ดฅ: " + (e?.message || "ๆ ผๅผ้”™่ฏฏ")); + return; + } } else { // token ๆฒกๅ˜๏ผŒ็กฎไฟ localStorage ๆœ‰ๆ•ฐๆฎ saveToken(tokenFromUrl); } - // ๆ‹‰ๅ–ๅญ•ๆœŸๆ•ฐๆฎ๏ผŒ่ฟ›ๅ…ฅ้ฆ–้กตๆˆ– onboarding + // ๆ‹‰ๅ–็”จๆˆทๆ•ฐๆฎ๏ผŒ่ฟ›ๅ…ฅ้ฆ–้กตๆˆ– onboarding + dbg({ step: "fetch-profile" }); fetchProfile().then((dto) => { + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + dbg({ step: "fetch-ok", fetchError: `is_onboarded=${dto?.is_onboarded}` }); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true }); - }).catch(() => { + }).catch((e: any) => { + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ + dbg({ step: "fetch-fail", fetchError: `${e?.message || e}` }); + // โ”€โ”€โ”€ ๐Ÿž โ”€โ”€โ”€ setError("็™ปๅฝ•ๅทฒๅคฑๆ•ˆ๏ผŒ่ฏทๅœจๅฐ็จ‹ๅบ้‡ๆ–ฐ่ฟ›ๅ…ฅ"); }); return; } // ๅฐ็จ‹ๅบ็Žฏๅขƒไฝ†ๆฒกๆœ‰ token โ†’ ้€š็Ÿฅๅฐ็จ‹ๅบไผ ้€’ + dbg({ step: "check-wx-mp", isWxMp: isWechatMiniProgram() }); if (isWechatMiniProgram()) { try { (window as any).wx?.miniProgram?.postMessage({ type: "NEED_TOKEN" }); - } catch { /* ignore */ } + dbg({ step: "wx-postMessage-done" }); + } catch (e: any) { + dbg({ step: "wx-postMessage-error", fetchError: `${e?.message || e}` }); + } setError("ๆญฃๅœจ่Žทๅ–็™ปๅฝ•ไฟกๆฏ..."); return; } // ๆต่งˆๅ™จๅผ€ๅ‘็Žฏๅขƒ โ†’ ่‡ชๅŠจไฝฟ็”จๆต‹่ฏ•่ดฆๅท + dbg({ step: "dev-login" }); devLogin().then((res) => { + dbg({ step: "dev-login-ok" }); setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, @@ -65,12 +149,14 @@ export function LoginPage() { navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true }); }); }).catch((err) => { + dbg({ step: "dev-login-fail", devLoginError: err?.message || String(err) }); setError(err?.message || "็™ปๅฝ•ๅคฑ่ดฅ๏ผŒ่ฏทๅˆทๆ–ฐ้‡่ฏ•"); }); }, []); // eslint-disable-line react-hooks/exhaustive-deps return ( -
+
+ {debug && }