/** * AdminLayout - 管理后台布局 * * 布局:侧栏 248px + 顶栏 64px + 内容区 */ import { useState, useEffect } from 'react' import { Layout, Menu, Avatar, Dropdown, Spin, Drawer, Button, type MenuProps } from 'antd' import { DashboardOutlined, SafetyOutlined, FileTextOutlined, ApiOutlined, UserOutlined, MenuFoldOutlined, MenuUnfoldOutlined, MenuOutlined, LogoutOutlined, SettingOutlined, } from '@ant-design/icons' import type { ReactNode } from 'react' import { Outlet, useLocation, useNavigate } from 'react-router-dom' import { useAuth } from '@/app/providers/auth-context' import { useBreadcrumbs } from '@/lib/hooks/useBreadcrumbs' import styles from './AdminLayout.module.css' const { Sider, Header, Content } = Layout // 管理员菜单配置 const adminMenuItems: MenuProps['items'] = [ { key: '/dashboard', icon: , label: '总览', }, { key: 'access-control', icon: , label: '访问控制', children: [ { key: '/users', label: '用户管理' }, { key: '/roles', label: '角色管理' }, { key: '/permissions', label: '权限管理' }, ], }, { key: 'logs', icon: , label: '审计日志', children: [ { key: '/logs/login', label: '登录日志' }, { key: '/logs/operation', label: '操作日志' }, ], }, { key: 'integration', icon: , label: '集成能力', children: [ { key: '/webhooks', label: 'Webhooks' }, { key: '/import-export', label: '导入导出' }, ], }, { key: 'profile', icon: , label: '我的账户', children: [ { key: '/profile', label: '个人资料' }, { key: '/profile/security', label: '安全设置' }, ], }, ] // 非管理员菜单配置(只有 Webhooks 和个人中心) const userMenuItems: MenuProps['items'] = [ { key: '/webhooks', icon: , label: 'Webhooks', }, { key: 'profile', icon: , label: '我的账户', children: [ { key: '/profile', label: '个人资料' }, { key: '/profile/security', label: '安全设置' }, ], }, ] interface AdminLayoutProps { children?: ReactNode } export function AdminLayout({ children }: AdminLayoutProps) { const [collapsed, setCollapsed] = useState(false) const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false) const [isMobile, setIsMobile] = useState(false) const location = useLocation() const navigate = useNavigate() const { user, isAdmin, logout, isLoading } = useAuth() const breadcrumbItems = useBreadcrumbs() // 检测移动端 useEffect(() => { const checkMobile = () => { setIsMobile(window.innerWidth < 768) } checkMobile() window.addEventListener('resize', checkMobile) return () => window.removeEventListener('resize', checkMobile) }, []) // 移动端切换侧边栏 const toggleMobileDrawer = () => { setMobileDrawerOpen(!mobileDrawerOpen) } // 移动端菜单点击后关闭抽屉 const handleMobileMenuClick: MenuProps['onClick'] = (info) => { navigate(info.key) setMobileDrawerOpen(false) } // 根据是否为管理员选择菜单 const menuItems = isAdmin ? adminMenuItems : userMenuItems // 当前选中的菜单 const selectedKeys = [location.pathname] // 当前展开的菜单组(根据路径决定哪个分组展开) const openKeys = collapsed ? [] : [ ...(location.pathname.startsWith('/users') || location.pathname.startsWith('/roles') || location.pathname.startsWith('/permissions') ? ['access-control'] : []), ...(location.pathname.startsWith('/logs') ? ['logs'] : []), ...(location.pathname.startsWith('/webhooks') || location.pathname.startsWith('/import-export') ? ['integration'] : []), ...(location.pathname.startsWith('/profile') ? ['profile'] : []), ] const handleMenuClick: MenuProps['onClick'] = (info) => { navigate(info.key) } // 处理面包屑点击 const handleBreadcrumbClick = (path: string) => { navigate(path) } // 处理登出 const handleLogout = () => { void logout() } // 用户下拉菜单 const userDropdownItems: MenuProps['items'] = [ { key: 'profile', icon: , label: '个人资料', onClick: () => navigate('/profile'), }, { key: 'security', icon: , label: '安全设置', onClick: () => navigate('/profile/security'), }, { type: 'divider' }, { key: 'logout', icon: , label: '退出登录', danger: true, onClick: handleLogout, }, ] // 加载中状态 if (isLoading) { return (
) } return ( {/* 跳过链接 - 便于键盘用户快速跳转到主要内容 */} 跳转到主要内容 {/* 侧边栏 */} {/* Logo 区域 */}
{collapsed ? 'UMS' : '用户管理系统'}
{/* 导航菜单 */} {/* 右侧主体 */} {/* 顶栏 */}
{/* 折叠/菜单按钮 - 移动端显示菜单图标,桌面端显示折叠图标 */} {isMobile ? ( )} {/* 面包屑 */} {breadcrumbItems && breadcrumbItems.length > 0 && (
{breadcrumbItems.map((item, index) => ( {item.path ? ( handleBreadcrumbClick(item.path as string)} > {item.title} ) : ( {item.title} )} {index < breadcrumbItems.length - 1 && ( / )} ))}
)}
{/* 用户信息 */}
} src={user?.avatar || null} style={{ backgroundColor: user?.avatar ? undefined : 'var(--color-primary)' }} /> {user?.nickname || user?.username || '用户'}
{/* 内容区 */} {children || }
{/* 移动端抽屉式导航 */} {collapsed ? 'UMS' : '用户管理系统'} } placement="left" onClose={toggleMobileDrawer} open={mobileDrawerOpen} size="default" className={styles.mobileDrawer} styles={{ body: { padding: 0 } }} > ) }