import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/router'; import { AppProps } from 'next/app'; import { Toaster } from 'react-hot-toast'; import { User } from '@supabase/supabase-js'; import useClientMount from '../utils/useClientMount'; import ErrorBoundary from '../components/ErrorBoundary'; import '../styles/globals.css'; // 自定义用户类型,用于 JWT 认证 interface CustomUser { id: string; email: string; name: string; userType: string; phone?: string; avatarUrl?: string; } export default function App({ Component, pageProps }: AppProps) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [navigationInProgress, setNavigationInProgress] = useState(false); const isClient = useClientMount(); const router = useRouter(); const navigationTimeoutRef = useRef(null); // 防抖路由跳转函数 const navigateWithDebounce = (path: string) => { if (navigationInProgress) return; setNavigationInProgress(true); // 清除之前的定时器 if (navigationTimeoutRef.current) { clearTimeout(navigationTimeoutRef.current); } // 设置新的定时器 navigationTimeoutRef.current = setTimeout(() => { router.push(path).finally(() => { setNavigationInProgress(false); }); }, 100); // 100ms 防抖延迟 }; // 检查 JWT 令牌的有效性 const checkJWTAuth = async () => { try { const token = localStorage.getItem('adminToken'); if (!token) { return null; } // 验证令牌 const response = await fetch('/api/auth/verify-token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); if (response.ok) { const data = await response.json(); return data.user; } else { // 令牌无效,清除本地存储 localStorage.removeItem('adminToken'); return null; } } catch (error) { console.error('Token verification error:', error); localStorage.removeItem('adminToken'); return null; } }; useEffect(() => { // 只在客户端执行 if (!isClient) return; // 检查是否为演示模式 const isDemoMode = !process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL === 'https://demo.supabase.co' || process.env.NEXT_PUBLIC_SUPABASE_URL === ''; const checkUser = async () => { try { // 使用自定义 JWT 认证检查 const jwtUser = await checkJWTAuth(); if (jwtUser) { setUser(jwtUser); // 如果当前在登录页面且已经认证,重定向到仪表板 if (router.pathname === '/auth/login') { navigateWithDebounce('/dashboard'); } } else { setUser(null); // 如果在需要认证的页面但未登录,重定向到登录页 const protectedRoutes = ['/dashboard', '/admin', '/settings']; const isProtectedRoute = protectedRoutes.some(route => router.pathname.startsWith(route) ); if (isProtectedRoute) { navigateWithDebounce('/auth/login'); } } } catch (error) { console.error('Auth check error:', error); setUser(null); } finally { setLoading(false); } }; checkUser(); // 监听路由变化,重新检查认证状态 const handleRouteChange = () => { checkUser(); }; router.events.on('routeChangeComplete', handleRouteChange); return () => { router.events.off('routeChangeComplete', handleRouteChange); // 清理定时器 if (navigationTimeoutRef.current) { clearTimeout(navigationTimeoutRef.current); } }; }, [router, isClient]); // 在客户端挂载之前,显示最小化的 loading 状态以避免水合错误 if (!isClient) { return (
); } // 显示加载状态 if (loading) { return (
); } return (
); }