| | |
| | | "use client"; |
| | | |
| | | import { ReactNode, useState, useEffect } from 'react'; |
| | | import { usePathname } from 'next/navigation'; |
| | | import Navbar from './Navbar'; |
| | | import Image from 'next/image'; |
| | | import ApiService from '@/utils/api'; |
| | | |
| | | export default function ClientLayoutContent({ children }: { children: React.ReactNode }) { |
| | | // 使用客户端钩子检查路径 |
| | | 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(); |
| | | |
| | | // 判断当前页面 |
| | | const isLoginPage = pathname === '/login'; |
| | | |
| | | if (isLoginPage) { |
| | | return <>{children}</>; |
| | | } |
| | | |
| | | return ( |
| | | <> |
| | | <Navbar /> |
| | | <main className="min-h-screen bg-gradient-to-b from-[var(--ai-surface)] to-white pt-16"> |
| | | {children} |
| | | </main> |
| | | <footer className="bg-gradient-to-br from-[var(--ai-primary)] to-[var(--ai-dark)] text-white py-10"> |
| | | <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| | | <div className="mb-8 flex justify-center flex-col items-center"> |
| | | <div className="relative w-16 h-16 mb-3"> |
| | | <Image |
| | | src="/images/logo.jpg" |
| | | alt="帷幄君成Logo" |
| | | width={64} |
| | | height={64} |
| | | className="object-contain" |
| | | priority |
| | | /> |
| | | </div> |
| | | <div className="text-xl font-bold">帷幄君成</div> |
| | | <div className="text-sm text-gray-300 mt-1">智能物流解决方案</div> |
| | | </div> |
| | | <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> |
| | | <div> |
| | | <h3 className="text-lg font-semibold mb-4 text-[#F5A800]">关于我们</h3> |
| | | <ul className="space-y-2"> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">公司介绍</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">联系方式</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">加入我们</li> |
| | | </ul> |
| | | </div> |
| | | <div> |
| | | <h3 className="text-lg font-semibold mb-4 text-[#F5A800]">产品服务</h3> |
| | | <ul className="space-y-2"> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">数字员工</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">智能客服</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">物流解决方案</li> |
| | | </ul> |
| | | </div> |
| | | <div> |
| | | <h3 className="text-lg font-semibold mb-4 text-[#F5A800]">帮助中心</h3> |
| | | <ul className="space-y-2"> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">使用指南</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">常见问题</li> |
| | | <li className="hover:text-[#F5A800] transition-colors cursor-pointer">技术支持</li> |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | <div className="mt-8 pt-8 border-t border-opacity-20 border-[#F5A800] text-center"> |
| | | <div className="flex items-center justify-center mb-4"> |
| | | <span className="inline-block w-2 h-2 bg-[#00A0E9] rounded-full mr-2 animate-pulse"></span> |
| | | <span className="inline-block w-2 h-2 bg-[#5D54A4] rounded-full mx-2 animate-pulse delay-300"></span> |
| | | <span className="inline-block w-2 h-2 bg-[#F5A800] rounded-full ml-2 animate-pulse delay-500"></span> |
| | | </div> |
| | | <p>© 2024 帷幄君成. All rights reserved.</p> |
| | | </div> |
| | | const isRegisterPage = pathname === '/register'; |
| | | const isHomePage = pathname === '/'; |
| | | const isAIScenePage = pathname === '/ai-scene'; |
| | | const isAISceneChatPage = pathname.startsWith('/ai-scene/chat'); |
| | | const isChatPage = pathname === '/chat'; // 添加聊天页面判断 |
| | | const isSupplyChainChatPage = pathname === '/supply-chain-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(() => { |
| | | if (hasError) { |
| | | console.error("渲染错误被捕获:可能是JSX结构不正确导致的水合错误"); |
| | | } |
| | | }, [hasError]); |
| | | |
| | | // 错误处理函数 |
| | | const handleError = () => { |
| | | setHasError(true); |
| | | return ( |
| | | <div className="min-h-screen bg-[#0A1033] text-white p-8"> |
| | | <div className="max-w-lg mx-auto mt-20 bg-red-900/30 p-6 rounded-lg border border-red-500"> |
| | | <h2 className="text-xl font-bold text-red-400 mb-4">页面渲染错误</h2> |
| | | <p className="text-white mb-4">页面代码中可能存在JSX结构错误,请检查标签闭合是否正确。</p> |
| | | <p className="text-gray-300 text-sm">具体错误: 可能是motion.div标签未正确闭合或嵌套层级有问题</p> |
| | | </div> |
| | | </footer> |
| | | </> |
| | | </div> |
| | | ); |
| | | }; |
| | | |
| | | // 加载状态的基础布局 |
| | | 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> |
| | | ); |
| | | |
| | | // 主要内容布局 |
| | | const mainLayout = ( |
| | | <div className="animate-fadeIn"> |
| | | <div className="flex flex-col min-h-screen"> |
| | | {!isLoginPage && !isRegisterPage && <Navbar />} |
| | | <main className={`flex-1 ${isHomePage || isAIScenePage ? '' : 'bg-gradient-to-b from-[var(--ai-surface)] to-white'} pt-0 mt-0`}> |
| | | {children} |
| | | </main> |
| | | {!isLoginPage && !isRegisterPage && !isAISceneChatPage && !isChatPage && !isSupplyChainChatPage && ( |
| | | <footer className="relative z-20 bg-gradient-to-br from-[#0A1033] via-[#1E2B63] to-[#131C41] text-white py-10 overflow-hidden"> |
| | | {/* 科技感动态背景元素 */} |
| | | <div className="absolute inset-0 overflow-hidden pointer-events-none"> |
| | | {/* 网格底纹 */} |
| | | <div className="absolute inset-0 opacity-5" |
| | | style={{ |
| | | backgroundImage: 'radial-gradient(circle, rgba(106, 219, 255, 0.3) 1px, transparent 1px)', |
| | | backgroundSize: '20px 20px' |
| | | }}> |
| | | </div> |
| | | |
| | | {/* 水平光线 */} |
| | | <div className="absolute top-1/2 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-[#6ADBFF]/40 to-transparent transform -translate-y-1/2"></div> |
| | | |
| | | {/* 垂直光线 */} |
| | | <div className="absolute left-1/4 top-0 bottom-0 w-[1px] bg-gradient-to-b from-transparent via-[#5E72EB]/30 to-transparent"></div> |
| | | <div className="absolute left-3/4 top-0 bottom-0 w-[1px] bg-gradient-to-b from-transparent via-[#FF6A88]/30 to-transparent"></div> |
| | | |
| | | {/* 量子粒子点 - 使用条件渲染 */} |
| | | {isClient && ( |
| | | <> |
| | | <div className="absolute top-[20%] left-[10%] w-1 h-1 rounded-full bg-[#6ADBFF]/60 animate-pulse"></div> |
| | | <div className="absolute top-[70%] left-[90%] w-1.5 h-1.5 rounded-full bg-[#FF6A88]/60 animate-pulse" style={{animationDelay: '1.5s'}}></div> |
| | | <div className="absolute top-[40%] left-[60%] w-1 h-1 rounded-full bg-[#5E72EB]/60 animate-pulse" style={{animationDelay: '0.8s'}}></div> |
| | | </> |
| | | )} |
| | | |
| | | {/* 底部波浪线 */} |
| | | <div className="absolute bottom-0 w-full h-8 opacity-10"> |
| | | <svg className="w-full h-full" viewBox="0 0 1200 30" preserveAspectRatio="none"> |
| | | <path d="M0,10 Q150,20 300,10 T600,10 T900,10 T1200,10 V30 H0 Z" fill="url(#footerGradient)"></path> |
| | | <defs> |
| | | <linearGradient id="footerGradient" x1="0%" y1="0%" x2="100%" y2="0%"> |
| | | <stop offset="0%" stopColor="#6ADBFF" /> |
| | | <stop offset="50%" stopColor="#5E72EB" /> |
| | | <stop offset="100%" stopColor="#FF6A88" /> |
| | | </linearGradient> |
| | | </defs> |
| | | </svg> |
| | | </div> |
| | | </div> |
| | | |
| | | <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10"> |
| | | <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> |
| | | <div className="backdrop-blur-sm bg-white/5 rounded-lg p-6 border border-[#6ADBFF]/10 transition-transform hover:scale-[1.02] hover:shadow-[0_0_15px_rgba(106,219,255,0.2)]"> |
| | | <h3 className="text-lg font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-[#6ADBFF] to-[#F5A800]">关于我们</h3> |
| | | <ul className="space-y-3"> |
| | | <li className="hover:text-[#6ADBFF] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#6ADBFF] rounded-full mr-2 opacity-70"></span> |
| | | 公司介绍 |
| | | </li> |
| | | <li className="hover:text-[#6ADBFF] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#6ADBFF] rounded-full mr-2 opacity-70"></span> |
| | | 联系方式 |
| | | </li> |
| | | <li className="hover:text-[#6ADBFF] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#6ADBFF] rounded-full mr-2 opacity-70"></span> |
| | | 加入我们 |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div className="backdrop-blur-sm bg-white/5 rounded-lg p-6 border border-[#5E72EB]/10 transition-transform hover:scale-[1.02] hover:shadow-[0_0_15px_rgba(94,114,235,0.2)]"> |
| | | <h3 className="text-lg font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-[#5E72EB] to-[#F5A800]">产品服务</h3> |
| | | <ul className="space-y-3"> |
| | | <li className="hover:text-[#5E72EB] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#5E72EB] rounded-full mr-2 opacity-70"></span> |
| | | 数字员工 |
| | | </li> |
| | | <li className="hover:text-[#5E72EB] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#5E72EB] rounded-full mr-2 opacity-70"></span> |
| | | 智能客服 |
| | | </li> |
| | | <li className="hover:text-[#5E72EB] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#5E72EB] rounded-full mr-2 opacity-70"></span> |
| | | APS解决方案 |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div className="backdrop-blur-sm bg-white/5 rounded-lg p-6 border border-[#FF6A88]/10 transition-transform hover:scale-[1.02] hover:shadow-[0_0_15px_rgba(255,106,136,0.2)]"> |
| | | <h3 className="text-lg font-semibold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-[#FF6A88] to-[#F5A800]">帮助中心</h3> |
| | | <ul className="space-y-3"> |
| | | <li className="hover:text-[#FF6A88] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#FF6A88] rounded-full mr-2 opacity-70"></span> |
| | | 使用指南 |
| | | </li> |
| | | <li className="hover:text-[#FF6A88] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#FF6A88] rounded-full mr-2 opacity-70"></span> |
| | | 常见问题 |
| | | </li> |
| | | <li className="hover:text-[#FF6A88] transition-colors cursor-pointer flex items-center"> |
| | | <span className="inline-block w-1.5 h-1.5 bg-[#FF6A88] rounded-full mr-2 opacity-70"></span> |
| | | 技术支持 |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | |
| | | <div className="mt-10 pt-6 border-t border-[#6ADBFF]/10 text-center relative"> |
| | | {/* 量子连接特效 */} |
| | | <div className="absolute top-0 left-1/3 right-1/3 h-[1px]"> |
| | | <div className="relative w-full h-full"> |
| | | <div className="absolute inset-0 bg-gradient-to-r from-transparent via-[#6ADBFF] to-transparent"></div> |
| | | <div className="absolute top-0 left-1/2 h-6 w-[1px] -translate-x-1/2 -translate-y-1/2 bg-gradient-to-b from-[#6ADBFF] to-transparent opacity-70"></div> |
| | | </div> |
| | | </div> |
| | | |
| | | {/* 底部脉冲指示器 */} |
| | | <div className="flex items-center justify-center mb-4"> |
| | | <span className="inline-block w-2 h-2 bg-[#6ADBFF] rounded-full mr-3 animate-pulse"></span> |
| | | <span className="inline-block w-2 h-2 bg-[#5E72EB] rounded-full mx-3 animate-pulse" style={{animationDelay: '0.3s'}}></span> |
| | | <span className="inline-block w-2 h-2 bg-[#FF6A88] rounded-full ml-3 animate-pulse" style={{animationDelay: '0.6s'}}></span> |
| | | </div> |
| | | |
| | | <div className="text-sm text-gray-400 flex items-center justify-center gap-2"> |
| | | <span>© 2025 帷幄君成. All rights reserved.</span> |
| | | <span className="text-gray-500">|</span> |
| | | <a |
| | | href="http://beian.miit.gov.cn/" |
| | | target="_blank" |
| | | rel="noopener noreferrer" |
| | | className="hover:text-[#6ADBFF] transition-colors" |
| | | > |
| | | 沪ICP备2025121910号 |
| | | </a> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </footer> |
| | | )} |
| | | </div> |
| | | </div> |
| | | ); |
| | | |
| | | // 服务端渲染时的基础布局 |
| | | if (!isClient) { |
| | | return ( |
| | | <div className="min-h-screen bg-[#0A1033] text-white"> |
| | | <div className="opacity-50"> |
| | | {children} |
| | | </div> |
| | | </div> |
| | | ); |
| | | } |
| | | |
| | | // 处理错误状态 |
| | | if (hasError) { |
| | | return handleError(); |
| | | } |
| | | |
| | | // 处理认证检查状态 |
| | | if (isCheckingAuth && !isLoginPage && !isRegisterPage && !isHomePage) { |
| | | return loadingLayout; |
| | | } |
| | | |
| | | // 处理未认证状态 |
| | | if (!isAuthenticated && !isLoginPage && !isRegisterPage && !isHomePage) { |
| | | return loadingLayout; |
| | | } |
| | | |
| | | // 渲染主要内容 |
| | | return mainLayout; |
| | | } |