import { ProLayout } from '@ant-design/pro-components'; import { Button, Dropdown, Select, Skeleton, message } from 'antd'; import type { MenuProps } from 'antd'; import { Bot, ChevronDown, ClipboardList, Gift, LayoutDashboard, LogOut, MessageSquareMore, MapPinned, Settings, Star, Users, } from 'lucide-react'; import { Outlet, history, useLocation } from '@umijs/max'; import { useEffect, useState } from 'react'; import { apiRequest, getSelectedBotId, jsonOptions, setCsrfToken, setSelectedBotId, } from '@/services/api'; import { BotAccessContext } from '@/contexts/BotAccess'; import type { AdminUser, BotProfile } from '@/types'; const menuItems = [ { path: '/dashboard', name: '概览', icon: }, { path: '/chats', name: '群组管理', icon: }, { path: '/giveaways', name: '抽奖管理', icon: }, { path: '/points', name: '积分管理', icon: }, { path: '/directory', name: '师生与附近', icon: }, { path: '/audit', name: '操作日志', icon: }, { path: '/settings', name: '系统设置', icon: }, ]; export default function AdminLayout() { const location = useLocation(); const [user, setUser] = useState(null); const [bots, setBots] = useState([]); const [selectedBot, setSelectedBot] = useState(getSelectedBotId()); useEffect(() => { apiRequest('/auth/me') .then((current) => { setCsrfToken(current.csrf_token); if (current.must_change_password) { history.replace('/change-password'); return; } setUser(current); }) .catch((error) => message.error(error.message)); }, []); useEffect(() => { const loadBots = () => { apiRequest<{ items: BotProfile[] }>('/bots') .then(({ items }) => { setBots(items); const current = getSelectedBotId(); if (current && items.some((item) => item.bot_id === current)) { setSelectedBot(current); return; } const first = items.find((item) => item.enabled) || items[0]; const next = first?.bot_id || ''; setSelectedBot(next); setSelectedBotId(next); }) .catch(() => setBots([])); }; loadBots(); window.addEventListener('bot-profiles-changed', loadBots); return () => window.removeEventListener('bot-profiles-changed', loadBots); }, []); const selectedProfile = bots.find((item) => item.bot_id === selectedBot) || null; const rolePermissions = selectedProfile?.permissions; const hasPermission = (permission: string) => rolePermissions === undefined || rolePermissions.includes(permission); const hasAnyPermission = (permissions: string[]) => rolePermissions === undefined || permissions.some((permission) => rolePermissions.includes(permission)); const chatPermissions = [ 'chat.profile', 'chat.members', 'chat.permissions', 'chat.announcements', 'chat.invites', 'chat.rules', 'chat.notes', 'automation.manage', ]; const visibleMenuItems = menuItems.filter((item) => { if (item.path === '/chats') return hasAnyPermission(chatPermissions); if (item.path === '/points') return hasPermission('points.manage'); if (item.path === '/giveaways') return hasPermission('giveaways.manage'); if (item.path === '/directory') return hasPermission('teacher_directory.manage'); return true; }); useEffect(() => { if (!selectedProfile) return; const denied = (location.pathname.startsWith('/points') && !hasPermission('points.manage')) || (location.pathname.startsWith('/giveaways') && !hasPermission('giveaways.manage')) || (location.pathname.startsWith('/directory') && !hasPermission('teacher_directory.manage')) || (location.pathname.startsWith('/chats') && !hasAnyPermission(chatPermissions)); if (denied) history.replace('/dashboard'); }, [selectedBot, bots, location.pathname]); const accountMenu: MenuProps['items'] = [ { key: 'settings', icon: , label: '账号设置', onClick: () => history.push('/settings'), }, { key: 'logout', danger: true, icon: , label: '退出登录', onClick: async () => { await apiRequest('/auth/logout', jsonOptions('POST')); sessionStorage.removeItem('admin_csrf'); history.replace('/login'); }, }, ]; if (!user) { return ; } return (