feat: move debug overlay to MobileLayout (全局持久显示)

This commit is contained in:
2026-06-25 19:24:00 +08:00
parent e9c578c8d4
commit 9a14a75b42
4 changed files with 29 additions and 22 deletions

View File

@@ -1,14 +1,27 @@
import { Outlet } from "react-router";
import { useUser } from "../context/UserContext";
/**
* H5 移动端全局布局容器
* - max-w-md (448px) 限制最大宽度,大屏居中显示
* - min-h-dvh 使用动态视口高度,解决 Safari 地址栏问题
* - safe-area padding 适配刘海屏/底部手势条
*/
export function MobileLayout() {
const { debugInfo, clearDebug } = useUser();
return (
<div className="max-w-md mx-auto min-h-dvh relative bg-morandi-50 shadow-[0_0_40px_rgba(0,0,0,0.06)]">
{/* 全局调试浮层:所有页面下可见 */}
{debugInfo.length > 0 && (
<div
className="absolute top-0 left-0 right-0 z-50 bg-black/80 text-green-400 text-xs p-3 overflow-auto max-h-[50%] cursor-pointer font-mono"
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all', lineHeight: 1.5 }}
onClick={() => clearDebug()}
>
<div style={{ borderBottom: '1px solid #0f0', paddingBottom: 4, marginBottom: 4, fontWeight: 'bold', fontSize: 14 }}>H5应用调试</div>
{debugInfo.map((msg, i) => (
<div key={i}>{msg}</div>
))}
</div>
)}
<Outlet />
</div>
);

View File

@@ -187,6 +187,9 @@ interface UserContextValue {
setToken: (token: string) => void;
setTokenAndUser: (token: string, info: BasicUserInfo) => void;
fetchProfile: () => Promise<UserProfileDTO | null>;
debugInfo: string[];
addDebug: (msg: string) => void;
clearDebug: () => void;
logout: () => void;
}
@@ -195,6 +198,14 @@ const UserContext = createContext<UserContextValue | null>(null);
export function UserProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<UserProfile>(loadProfile);
const [token, setTokenState] = useState<string | null>(getToken);
const [debugInfo, setDebugInfo] = useState<string[]>([]);
const addDebug = useCallback((msg: string) => {
console.log(msg);
setDebugInfo(prev => [...prev.slice(-20), msg]);
}, []);
const clearDebug = useCallback(() => {
setDebugInfo([]);
}, []);
const setToken = useCallback((newToken: string) => {
// 清理前一个用户的本地数据,防止用户间数据残留
@@ -280,7 +291,7 @@ export function UserProvider({ children }: { children: ReactNode }) {
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<UserContext.Provider value={{ user, token, updateUser, updateUserRemote, setToken, setTokenAndUser, fetchProfile, logout }}>
<UserContext.Provider value={{ user, token, updateUser, updateUserRemote, setToken, setTokenAndUser, fetchProfile, debugInfo, addDebug, clearDebug, logout }}>
{children}
</UserContext.Provider>
);

View File

@@ -10,11 +10,7 @@ export function LoginPage() {
const navigate = useNavigate();
const { setTokenAndUser, fetchProfile } = useUser();
const [error, setError] = useState("");
const [debugInfo, setDebugInfo] = useState<string[]>([]);
const addDebug = (msg: string) => {
console.log(msg);
setDebugInfo(prev => [...prev.slice(-20), msg]);
};
const { addDebug, debugInfo } = useUser();
useEffect(() => {
clearDebugLogs();
@@ -98,19 +94,6 @@ export function LoginPage() {
return (
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4 relative">
{/* 调试浮层:点击可关闭 */}
{debugInfo.length > 0 && (
<div
className="absolute top-0 left-0 right-0 z-50 bg-black/80 text-green-400 text-xs p-3 overflow-auto max-h-[50%] cursor-pointer font-mono"
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all', lineHeight: 1.5 }}
onClick={() => setDebugInfo([])}
>
<div style={{borderBottom:'1px solid #0f0',paddingBottom:4,marginBottom:4,fontWeight:'bold',fontSize:14}}>H5应用调试</div>
{debugInfo.map((msg, i) => (
<div key={i}>{msg}</div>
))}
</div>
)}
<div className="text-center">
<motion.div
animate={{ rotate: 360 }}