From 150dafc72f9098f88bf3f38db9f27e2daa8105e6 Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Wed, 27 May 2026 20:19:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=9F=E4=B8=80=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20debug.ts=EF=BC=8CVITE=5FDEBUG=20=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E5=8F=98=E9=87=8F=E6=8E=A7=E5=88=B6=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E6=98=BE=E9=9A=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 services/debug.ts: isDebug()/debugLog()/getDebugLogs() - .env 中 VITE_DEBUG=true 开启调试,false 关闭 - LoginPage 使用 debugLog() 记录登录流程 - ProfilePage 通过 isDebug() 控制调试面板显隐 - .env.example 同步更新 --- frontend/.env.example | 2 ++ frontend/src/app/pages/LoginPage.tsx | 38 ++++++++++++++++++-------- frontend/src/app/pages/ProfilePage.tsx | 18 +++++++++++- frontend/src/app/services/debug.ts | 31 +++++++++++++++++++++ 4 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 frontend/src/app/services/debug.ts diff --git a/frontend/.env.example b/frontend/.env.example index e979412..42d7cf0 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,2 +1,4 @@ VITE_API_PREFIX=/app_03/api VITE_UPLOADS_PREFIX=/uploads +# 调试模式:true=开启日志和调试面板,false=关闭 +VITE_DEBUG=true diff --git a/frontend/src/app/pages/LoginPage.tsx b/frontend/src/app/pages/LoginPage.tsx index 3775df7..b339675 100644 --- a/frontend/src/app/pages/LoginPage.tsx +++ b/frontend/src/app/pages/LoginPage.tsx @@ -3,7 +3,8 @@ import { useNavigate } from "react-router"; import { motion } from "motion/react"; import { Heart } from "lucide-react"; import { useUser } from "../context/UserContext"; -import { devLogin, createDummyToken, getToken } from "../services/api"; +import { devLogin, createDummyToken } from "../services/api"; +import { debugLog, clearDebugLogs } from "../services/debug"; export function LoginPage() { const navigate = useNavigate(); @@ -11,34 +12,49 @@ export function LoginPage() { const [error, setError] = useState(""); useEffect(() => { - const params = new URLSearchParams(window.location.search); + clearDebugLogs(); + + const params = new URLSearchParams(window.location.search); + debugLog(`URL: ${window.location.href.substring(0, 100)}`); + debugLog(`search: ${window.location.search}`); - // URL 参数 uid/openid/phone 直接构建本地 token 登录 const openidParam = params.get('openid'); - if (openidParam) { + if (openidParam && openidParam.trim()) { const uid = parseInt(params.get('uid') || '0'); const phone = params.get('phone') || ''; const token = createDummyToken(uid, openidParam, phone); + debugLog(`dummy token: ${token.substring(0, 50)}...`); + + try { + const payload = JSON.parse(atob(token.split('.')[1])); + debugLog(`payload: uid=${payload.uid}, openid=${payload.openid}, phone=${payload.phone}`); + } catch (e: any) { + debugLog(`decode error: ${e.message}`); + } + setTokenAndUser(token, { id: String(uid), openid: openidParam, phone }); + debugLog(`setTokenAndUser: id=${uid}, openid=${openidParam}, phone=${phone}`); + fetchProfile().then((dto) => { + if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}, onboarded=${dto.is_onboarded}`); navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true }); - }).catch(() => { + }).catch((e: any) => { + debugLog(`fetchProfile error: ${e?.message}`); setError("登录已失效,请在小程序重新进入"); }); return; } - // 浏览器开发环境 → dev-login + debugLog(`no openid param (val=${openidParam || '(empty)'}), fallback to dev-login`); devLogin().then((res) => { - setTokenAndUser(res.token, { - id: res.user_id, - openid: res.openid, - phone: res.mobile, - }); + debugLog(`dev-login: openid=${res.openid}, phone=${res.mobile}`); + setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile }); fetchProfile().then((dto) => { + if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}`); navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true }); }); }).catch((err) => { + debugLog(`dev-login error: ${err?.message}`); setError(err?.message || "登录失败,请刷新重试"); }); }, []); // eslint-disable-line react-hooks/exhaustive-deps diff --git a/frontend/src/app/pages/ProfilePage.tsx b/frontend/src/app/pages/ProfilePage.tsx index d022f13..df5a785 100644 --- a/frontend/src/app/pages/ProfilePage.tsx +++ b/frontend/src/app/pages/ProfilePage.tsx @@ -24,6 +24,7 @@ import { Button } from "../components/ui/button"; import { Card } from "../components/ui/card"; import { Badge } from "../components/ui/badge"; import { useUser, getPregnancyStage } from "../context/UserContext"; +import { isDebug, getDebugLogs } from "../services/debug"; interface UserInfo { name: string; @@ -187,8 +188,23 @@ export function ProfilePage() { ); + // 🐞 调试面板(VITE_DEBUG=true 时显示) + const [debugLog] = useState(() => isDebug() ? getDebugLogs() : []); + const [showDebug, setShowDebug] = useState(false); + return ( -
+
+ {/* 🐞 调试面板 */} + {debugLog.length > 0 && ( +
+ + {showDebug && debugLog.map((line, i) => ( +
{line}
+ ))} +
+ )} {/* 顶部导航 */}
diff --git a/frontend/src/app/services/debug.ts b/frontend/src/app/services/debug.ts new file mode 100644 index 0000000..c88ca13 --- /dev/null +++ b/frontend/src/app/services/debug.ts @@ -0,0 +1,31 @@ +/** 调试工具 — VITE_DEBUG 环境变量统一控制 */ + +const _env = (import.meta as any).env || {}; +const IS_DEBUG = _env.VITE_DEBUG === '1' || _env.VITE_DEBUG === 'true'; + +const logs: string[] = []; + +export function isDebug(): boolean { + return IS_DEBUG; +} + +export function debugLog(msg: string): void { + if (!IS_DEBUG) return; + const line = `[${new Date().toISOString().slice(11, 19)}] ${msg}`; + logs.push(line); + localStorage.setItem('debug_log', JSON.stringify(logs)); +} + +export function getDebugLogs(): string[] { + try { + const raw = localStorage.getItem('debug_log'); + return raw ? JSON.parse(raw) : []; + } catch { + return []; + } +} + +export function clearDebugLogs(): void { + logs.length = 0; + localStorage.removeItem('debug_log'); +}