From 27b58564e35182be0b0aa0a04cb883da50f872dd Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Wed, 27 May 2026 18:52:45 +0800 Subject: [PATCH] =?UTF-8?q?cleanup:=20=E7=A7=BB=E9=99=A4=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E4=BB=A3=E7=A0=81=EF=BC=88DebugPanel/?= =?UTF-8?q?=E7=BA=A2=E6=A8=AA=E5=B9=85/URL=5FCHECK=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=A1=B5=E7=B2=BE=E7=AE=80=E4=B8=BA=E4=BB=85?= =?UTF-8?q?=20uid/openid/phone=20=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/index.html | 17 --- frontend/src/app/pages/LoginPage.tsx | 182 ++------------------------- 2 files changed, 11 insertions(+), 188 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 60586df..75e76ae 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -9,23 +9,6 @@ - - - -
diff --git a/frontend/src/app/pages/LoginPage.tsx b/frontend/src/app/pages/LoginPage.tsx index b77c1e6..3775df7 100644 --- a/frontend/src/app/pages/LoginPage.tsx +++ b/frontend/src/app/pages/LoginPage.tsx @@ -1,210 +1,50 @@ -import { useEffect, useState, useRef } from "react"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router"; import { motion } from "motion/react"; import { Heart } from "lucide-react"; import { useUser } from "../context/UserContext"; -import { decodeToken, devLogin, createDummyToken, getToken, setToken as saveToken } from "../services/api"; - -/** 判断是否在微信小程序 webview 环境 */ -function isWechatMiniProgram(): boolean { - const ua = navigator.userAgent.toLowerCase(); - 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 }) { - const [initialUrl] = useState(() => (window as any).__INITIAL_URL__ || '(N/A)'); - return ( -
-
🐞 调试信息 (关闭需去掉 ?debug=1)
- - - {Object.entries(info).map(([k, v]) => ( - - - - - ))} - - - - - -
{k}{v === false ? 'false' : v === true ? 'true' : v || (空)}
initialUrl{initialUrl}
-
- ); -} - -// ─── 🐞 调试区域结束 ─── +import { devLogin, createDummyToken, getToken } from "../services/api"; export function LoginPage() { const navigate = useNavigate(); const { setTokenAndUser, fetchProfile } = useUser(); const [error, setError] = useState(""); - const [debug] = useState(() => { - sessionStorage.setItem('debug', '1'); - return { ...INIT_DEBUG }; - }); - const processedRef = useRef(false); // 防止重复处理 - - // ─── 🐞 调试更新函数 ─── - const dbg = (patch: Partial) => { - if (debug) Object.assign(debug, patch); - }; - // ─── 🐞 调试更新结束 ─── - - /** 处理 token:解码 → 登录 → 拉取数据 → 跳转 */ - const processToken = (token: string) => { - if (processedRef.current) return; - processedRef.current = true; - - const oldToken = getToken(); - if (token !== oldToken) { - try { - const payload = decodeToken(token); - dbg({ step: "decode-ok", decodeResult: `uid=${payload.uid}, openid=${payload.openid?.substring(0,15)}..., phone=${payload.phone}` }); - setTokenAndUser(token, { - 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 { - saveToken(token); - } - - dbg({ step: "fetch-profile" }); - fetchProfile().then((dto) => { - dbg({ step: "fetch-ok", fetchError: `is_onboarded=${dto?.is_onboarded}` }); - const target = dto?.is_onboarded ? "/home" : "/onboarding"; - navigate(sessionStorage.getItem('debug') ? target + "?debug=1" : target, { replace: true }); - }).catch((e: any) => { - dbg({ step: "fetch-fail", fetchError: `${e?.message || e}` }); - setError("登录已失效,请在小程序重新进入"); - }); - }; - - // 暴露到全局,供小程序 evaluateJavascript 直接调用 - (window as any).handleInjectedToken = processToken; useEffect(() => { - dbg({ url: window.location.href, ua: navigator.userAgent, tokenInStorage: !!getToken() }); - - // 从 URL 获取 token(query / hash / 注入) const params = new URLSearchParams(window.location.search); - let token = params.get('token'); - if (!token) { - const hash = window.location.hash; - if (hash.startsWith('#token=')) { - token = decodeURIComponent(hash.replace('#token=', '')); - dbg({ step: "token-from-hash", tokenPrefix: token.substring(0, 30) + "..." }); - } - } - - if (!token && (window as any).__INJECTED_TOKEN__) { - token = (window as any).__INJECTED_TOKEN__; - dbg({ step: "token-from-inject", tokenPrefix: token.substring(0, 30) + "..." }); - } - - if (token) { - dbg({ step: "found-token", hasTokenParam: true, tokenPrefix: token.substring(0, 30) + "..." }); - processToken(token); - return; - } - - // 从 URL 参数 uid/openid/phone 直接构建本地 token - const uidParam = params.get('uid'); + // URL 参数 uid/openid/phone 直接构建本地 token 登录 const openidParam = params.get('openid'); if (openidParam) { - const uid = parseInt(uidParam || '0'); + const uid = parseInt(params.get('uid') || '0'); const phone = params.get('phone') || ''; - const dummyToken = createDummyToken(uid, openidParam, phone); - dbg({ step: "params-login", hasTokenParam: true, tokenPrefix: `uid=${uidParam}, openid=${openidParam.substring(0, 15)}...` }); - setTokenAndUser(dummyToken, { id: String(uid), openid: openidParam, phone }); + const token = createDummyToken(uid, openidParam, phone); + setTokenAndUser(token, { id: String(uid), openid: openidParam, phone }); fetchProfile().then((dto) => { - dbg({ step: "params-ok", fetchError: `is_onboarded=${dto?.is_onboarded}` }); - const target = dto?.is_onboarded ? "/home" : "/onboarding"; - navigate(sessionStorage.getItem('debug') ? target + "?debug=1" : target, { replace: true }); - }).catch((e: any) => { - dbg({ step: "params-fail", fetchError: `${e?.message || e}` }); - setError("登录失败: " + (e?.message || "")); + navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true }); + }).catch(() => { + setError("登录已失效,请在小程序重新进入"); }); return; } - // 没有 token → 小程序环境则发 NEED_TOKEN - dbg({ step: "check-wx-mp", isWxMp: isWechatMiniProgram() }); - if (isWechatMiniProgram()) { - try { - (window as any).wx?.miniProgram?.postMessage({ type: "NEED_TOKEN" }); - dbg({ step: "wx-postMessage-done" }); - } catch (e: any) { - dbg({ step: "wx-postMessage-error", fetchError: `${e?.message || e}` }); - } - setError("正在获取登录信息..."); - - // 轮询:等待小程序 evaluateJavascript 注入 token - let attempts = 0; - const timer = setInterval(() => { - const injected = (window as any).__INJECTED_TOKEN__; - if (injected) { - clearInterval(timer); - dbg({ step: "token-polled", tokenPrefix: injected.substring(0, 30) + "..." }); - processToken(injected); - } - attempts++; - if (attempts >= 20) clearInterval(timer); // 最多等 10 秒 - }, 500); - return; - } - // 浏览器开发环境 → dev-login - dbg({ step: "dev-login" }); devLogin().then((res) => { - dbg({ step: "dev-login-ok" }); setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile, }); fetchProfile().then((dto) => { - const target = dto?.is_onboarded ? "/home" : "/onboarding"; - navigate(sessionStorage.getItem('debug') ? target + "?debug=1" : target, { replace: true }); + 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 && } +