cleanup: 移除所有调试代码(DebugPanel/红横幅/URL_CHECK),登录页精简为仅 uid/openid/phone 流程
This commit is contained in:
@@ -9,23 +9,6 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>window.__INITIAL_URL__ = document.URL;</script>
|
||||
<!-- 🐞 原始 URL 验证 -->
|
||||
<div id="url-check" style="display:none" data-url=""></div>
|
||||
<script>
|
||||
var u = document.URL;
|
||||
document.getElementById('url-check').setAttribute('data-url', u);
|
||||
console.log('[URL_CHECK] document.URL:', u);
|
||||
console.log('[URL_CHECK] search:', location.search);
|
||||
console.log('[URL_CHECK] has_token:', location.search.includes('token='));
|
||||
// 如果没 token,在页面顶部写一行红色提示
|
||||
if (!location.search.includes('token=')) {
|
||||
var d = document.createElement('div');
|
||||
d.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:99999;background:red;color:white;padding:10px;font-size:14px;text-align:center';
|
||||
d.textContent = '⚠️ URL无token: search=[' + location.search + '] url=' + u.substring(0, 80);
|
||||
document.body.prepend(d);
|
||||
}
|
||||
</script>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
@@ -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 (
|
||||
<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 === false ? 'false' : v === true ? 'true' : v || <span className="text-gray-500">(空)</span>}</td>
|
||||
</tr>
|
||||
))}
|
||||
<tr className="border-b border-yellow-400/50">
|
||||
<td className="pr-2 text-yellow-400 w-28 align-top whitespace-nowrap font-bold">initialUrl</td>
|
||||
<td className="break-all text-yellow-300">{initialUrl}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─── 🐞 调试区域结束 ───
|
||||
import { devLogin, createDummyToken, getToken } from "../services/api";
|
||||
|
||||
export function LoginPage() {
|
||||
const navigate = useNavigate();
|
||||
const { setTokenAndUser, fetchProfile } = useUser();
|
||||
const [error, setError] = useState("");
|
||||
const [debug] = useState<DebugInfo>(() => {
|
||||
sessionStorage.setItem('debug', '1');
|
||||
return { ...INIT_DEBUG };
|
||||
});
|
||||
const processedRef = useRef(false); // 防止重复处理
|
||||
|
||||
// ─── 🐞 调试更新函数 ───
|
||||
const dbg = (patch: Partial<DebugInfo>) => {
|
||||
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 (
|
||||
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4 relative">
|
||||
{debug && <DebugPanel info={debug} />}
|
||||
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4">
|
||||
<div className="text-center">
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
|
||||
Reference in New Issue
Block a user