feat: 添加调试面板以显示登录过程中的调试信息
This commit is contained in:
@@ -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) {
|
||||
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 }}
|
||||
|
||||
Reference in New Issue
Block a user