import { useEffect } from 'react'; import { Outlet } from 'react-router-dom'; import { cn } from '@/lib/utils'; import { useThemeStore, useUserStore } from '@/store'; import { Sidebar } from './Sidebar'; import { Header } from './Header'; import { Breadcrumb } from './Breadcrumb'; import { userApi } from '@/api'; import type { JsonData } from '@/types/common'; /** * MainLayout - 优化后的主布局组件 * * 优化点: * 1. 使用 CSS 变量 + Tailwind 类替代硬编码的 style 属性 * 2. sidebar 宽度通过 CSS 变量管理,统一协调 * 3. 添加 Breadcrumb 面包屑导航 * 4. 布局过渡动画平滑 * 5. 支持响应式布局 * 6. F3: 页面刷新后自动拉取当前用户权限(RBAC 按钮级控制) */ export function MainLayout() { const { sidebarCollapsed } = useThemeStore(); const token = useUserStore((s) => s.token); const permissions = useUserStore((s) => s.permissions); const setPermissions = useUserStore((s) => s.setPermissions); // 页面刷新后 zustand persist 会恢复 token/user,但 permissions 可能丢失或过期 // 在 MainLayout 挂载时如果 permissions 为 null 则拉取一次 useEffect(() => { if (!token || permissions !== null) return; let cancelled = false; userApi.getMyPermissions() .then((data: JsonData) => { if (cancelled) return; const perms: string[] = data?.permissions ?? []; setPermissions(Array.isArray(perms) ? perms : []); }) .catch(() => { // 拉取失败不阻塞页面,权限保持 null(usePermission 默认放行) if (!cancelled) setPermissions([]); }); return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [token]); return (