| | |
| | | import { ReactNode, useState, useEffect } from 'react'; |
| | | import { usePathname } from 'next/navigation'; |
| | | import Navbar from './Navbar'; |
| | | import ApiService from '@/utils/api'; |
| | | |
| | | interface ClientLayoutContentProps { |
| | | children: ReactNode; |
| | |
| | | export default function ClientLayoutContent({ children }: ClientLayoutContentProps) { |
| | | const [isClient, setIsClient] = useState(false); |
| | | const [hasError, setHasError] = useState(false); |
| | | const [isCheckingAuth, setIsCheckingAuth] = useState(true); |
| | | const [isAuthenticated, setIsAuthenticated] = useState(false); |
| | | const pathname = usePathname(); |
| | | |
| | | useEffect(() => { |
| | | setIsClient(true); |
| | | }, []); |
| | | |
| | | // 判断当前页面 |
| | | const isLoginPage = pathname === '/login'; |
| | |
| | | const isHomePage = pathname === '/'; |
| | | const isAIScenePage = pathname === '/ai-scene'; |
| | | const isAISceneChatPage = pathname.startsWith('/ai-scene/chat'); |
| | | |
| | | // 设置客户端状态 |
| | | useEffect(() => { |
| | | setIsClient(true); |
| | | }, []); |
| | | |
| | | // 检查登录状态 |
| | | useEffect(() => { |
| | | const checkLoginStatus = async () => { |
| | | // 如果是公开页面,不需要检查登录状态 |
| | | if (isLoginPage || isRegisterPage || isHomePage) { |
| | | setIsCheckingAuth(false); |
| | | setIsAuthenticated(true); // 公开页面视为已认证 |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | const response = await ApiService.get('/users/info'); |
| | | if (response.code === 200) { |
| | | setIsAuthenticated(true); |
| | | } else { |
| | | window.location.href = '/login'; |
| | | return; |
| | | } |
| | | } catch (error) { |
| | | window.location.href = '/login'; |
| | | return; |
| | | } finally { |
| | | setIsCheckingAuth(false); |
| | | } |
| | | }; |
| | | |
| | | if (isClient) { |
| | | checkLoginStatus(); |
| | | } |
| | | }, [isClient, pathname, isLoginPage, isRegisterPage, isHomePage]); |
| | | |
| | | // 添加错误捕获 |
| | | useEffect(() => { |
| | |
| | | ); |
| | | }; |
| | | |
| | | // 此函数可在特殊情况下用于处理过渡 |
| | | const renderContent = () => { |
| | | if (!isClient) { |
| | | // 服务器端或客户端初始渲染时显示静态内容 |
| | | return ( |
| | | <div className="min-h-screen bg-[#0A1033] text-white"> |
| | | <div className="opacity-50"> |
| | | {/* 静态内容版本,无动画 */} |
| | | {children} |
| | | // 加载状态的基础布局 |
| | | const loadingLayout = ( |
| | | <div className="min-h-screen bg-[#0A1033] flex items-center justify-center"> |
| | | <div className="flex flex-col items-center space-y-4"> |
| | | <div className="w-10 h-10 border-4 border-[#6ADBFF]/30 border-t-[#6ADBFF] rounded-full animate-spin"></div> |
| | | <p className="text-[#6ADBFF]/70 text-sm">正在加载...</p> |
| | | </div> |
| | | </div> |
| | | ); |
| | | } |
| | | |
| | | // 客户端渲染后显示完整内容 |
| | | try { |
| | | return ( |
| | | // 主要内容布局 |
| | | const mainLayout = ( |
| | | <div className="animate-fadeIn"> |
| | | <div className="flex flex-col min-h-screen"> |
| | | {!isLoginPage && !isRegisterPage && <Navbar />} |
| | |
| | | </div> |
| | | </div> |
| | | ); |
| | | } catch (error) { |
| | | console.error("渲染错误:", error); |
| | | |
| | | // 服务端渲染时的基础布局 |
| | | if (!isClient) { |
| | | return ( |
| | | <div className="min-h-screen bg-[#0A1033] text-white"> |
| | | <div className="opacity-50"> |
| | | {children} |
| | | </div> |
| | | </div> |
| | | ); |
| | | } |
| | | |
| | | // 处理错误状态 |
| | | if (hasError) { |
| | | return handleError(); |
| | | } |
| | | }; |
| | | |
| | | return ( |
| | | <> |
| | | {hasError ? handleError() : renderContent()} |
| | | </> |
| | | ); |
| | | // 处理认证检查状态 |
| | | if (isCheckingAuth && !isLoginPage && !isRegisterPage && !isHomePage) { |
| | | return loadingLayout; |
| | | } |
| | | |
| | | // 处理未认证状态 |
| | | if (!isAuthenticated && !isLoginPage && !isRegisterPage && !isHomePage) { |
| | | return loadingLayout; |
| | | } |
| | | |
| | | // 渲染主要内容 |
| | | return mainLayout; |
| | | } |