"use client"; import { useCallback, useEffect, useState } from "react"; import { useAuthStore } from "@/lib/stores/auth-store"; import { useRouter } from "next/navigation"; import type { ReactNode } from "react"; import { AppShell } from "@/components/layout/AppShell"; import { LoadingState } from "@/components/shared/StateViews"; /** * 主域壳层:日常对话 / 人物 / 人格 / 记忆 / 轨迹等路由共用 AppShell。 * * 认证状态由 AuthInitializer(根布局)通过 BFF 初始化(user 首屏防闪用 localStorage), * 此布局仅做路由守卫:未认证时重定向到 /login。 */ export default function AppGroupLayout({ children }: { children: ReactNode }) { const router = useRouter(); const isAuthenticated = useAuthStore((s) => s.isAuthenticated); const logout = useAuthStore((s) => s.logout); const [ready, setReady] = useState(false); // 等待 AuthInitializer 完成(给 loadFromBff 机会) useEffect(() => { const timer = setTimeout(() => setReady(true), 100); return () => clearTimeout(timer); }, []); // 认证失败时登出并跳转登录页 const handleAuthError = useCallback(() => { logout(); router.push("/login"); }, [logout, router]); // 全局监听 ApiError "unauthorized"(通过自定义事件) useEffect(() => { const handler = () => handleAuthError(); window.addEventListener("auth:unauthorized", handler); return () => window.removeEventListener("auth:unauthorized", handler); }, [handleAuthError]); useEffect(() => { if (ready && !isAuthenticated) { router.push("/login"); } }, [ready, isAuthenticated, router]); return ( {ready && isAuthenticated ? children : } ); }