// ============================================================ // AdminLayout — ProLayout 管理后台布局 // ============================================================ import { Outlet, useNavigate, useLocation } from 'react-router-dom' import ProLayout from '@ant-design/pro-layout' import { DashboardOutlined, TeamOutlined, CloudServerOutlined, ApiOutlined, KeyOutlined, BarChartOutlined, SwapOutlined, SettingOutlined, FileTextOutlined, MessageOutlined, RobotOutlined, LogoutOutlined, } from '@ant-design/icons' import { useAuthStore } from '@/stores/authStore' import { Avatar, Dropdown, message } from 'antd' import type { MenuDataItem } from '@ant-design/pro-layout' const menuConfig: MenuDataItem[] = [ { path: '/', name: '仪表盘', icon: }, { path: '/accounts', name: '账号管理', icon: , permission: 'account:admin' }, { path: '/providers', name: '服务商', icon: , permission: 'provider:manage' }, { path: '/models', name: '模型管理', icon: , permission: 'model:read' }, { path: '/agent-templates', name: 'Agent 模板', icon: , permission: 'model:read' }, { path: '/api-keys', name: 'API 密钥', icon: , permission: 'admin:full' }, { path: '/usage', name: '用量统计', icon: , permission: 'admin:full' }, { path: '/relay', name: '中转任务', icon: , permission: 'relay:use' }, { path: '/config', name: '系统配置', icon: , permission: 'config:read' }, { path: '/prompts', name: '提示词管理', icon: , permission: 'prompt:read' }, { path: '/logs', name: '操作日志', icon: , permission: 'admin:full' }, ] function filterMenuByPermission( items: MenuDataItem[], hasPermission: (p: string) => boolean, ): MenuDataItem[] { return items .filter((item) => !item.permission || hasPermission(item.permission as string)) .map(({ permission, ...rest }) => ({ ...rest, children: rest.children ? filterMenuByPermission(rest.children, hasPermission) : undefined, })) } export default function AdminLayout() { const navigate = useNavigate() const location = useLocation() const { account, hasPermission, logout } = useAuthStore() const menuData = filterMenuByPermission(menuConfig, hasPermission) const handleLogout = () => { logout() message.success('已退出登录') navigate('/login', { replace: true }) } return ( Z} layout="mix" fixSiderbar fixedHeader location={{ pathname: location.pathname }} menuDataRender={() => menuData} menuItemRender={(item, dom) => (
item.path && navigate(item.path)}>{dom}
)} avatarProps={{ src: undefined, title: account?.display_name || account?.username || 'Admin', size: 'small', render: (_, dom) => ( , label: '退出登录', onClick: handleLogout, }, ], }} > {dom} ), }} suppressSiderWhenMenuEmpty contentStyle={{ padding: 24 }} >
) }