feat: 添加调试面板以显示登录过程中的调试信息

This commit is contained in:
2026-05-27 02:19:59 +08:00
parent 80904e65d8
commit fe116b9d99

View File

@@ -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 (
<div className="absolute top-0 left-0 right-0 z-50 bg-black/80 text-white text-xs font-mono p-3 text-left max-h-[60vh] overflow-auto">
<div className="font-bold text-yellow-400 mb-1">🐞 调试信息 (关闭需去掉 ?debug=1)</div>
<table className="w-full">
<tbody>
{Object.entries(info).map(([k, v]) => (
<tr key={k} className="border-b border-white/10">
<td className="pr-2 text-gray-400 w-28 align-top whitespace-nowrap">{k}</td>
<td className="break-all text-green-300">{v || <span className="text-gray-500">(空)</span>}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
// ─── 🐞 调试区域结束 ───
export function LoginPage() {
const navigate = useNavigate();
const { setTokenAndUser, fetchProfile } = useUser();
const [error, setError] = useState("");
const [debug] = useState<DebugInfo>(() => ({ ...INIT_DEBUG }));
// ─── 🐞 调试更新函数 ───
const dbg = (patch: Partial<DebugInfo>) => {
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 (
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4">
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4 relative">
{debug && <DebugPanel info={debug} />}
<div className="text-center">
<motion.div
animate={{ rotate: 360 }}