import { useCallback, memo } from 'react'; import { Layout, Avatar, Space, Dropdown, Tooltip, theme } from 'antd'; import { HomeOutlined, UserOutlined, SafetyOutlined, ApartmentOutlined, SettingOutlined, MenuFoldOutlined, MenuUnfoldOutlined, PartitionOutlined, LogoutOutlined, MessageOutlined, SearchOutlined, BulbOutlined, BulbFilled, } from '@ant-design/icons'; import { useNavigate, useLocation } from 'react-router-dom'; import { useAppStore } from '../stores/app'; import { useAuthStore } from '../stores/auth'; import NotificationPanel from '../components/NotificationPanel'; const { Header, Sider, Content, Footer } = Layout; interface MenuItem { key: string; icon: React.ReactNode; label: string; } const mainMenuItems: MenuItem[] = [ { key: '/', icon: , label: '工作台' }, { key: '/users', icon: , label: '用户管理' }, { key: '/roles', icon: , label: '权限管理' }, { key: '/organizations', icon: , label: '组织架构' }, ]; const bizMenuItems: MenuItem[] = [ { key: '/workflow', icon: , label: '工作流' }, { key: '/messages', icon: , label: '消息中心' }, ]; const sysMenuItems: MenuItem[] = [ { key: '/settings', icon: , label: '系统设置' }, ]; const routeTitleMap: Record = { '/': '工作台', '/users': '用户管理', '/roles': '权限管理', '/organizations': '组织架构', '/workflow': '工作流', '/messages': '消息中心', '/settings': '系统设置', }; // 侧边栏菜单项 - 提取为独立组件避免重复渲染 const SidebarMenuItem = memo(function SidebarMenuItem({ item, isActive, collapsed, onClick, }: { item: MenuItem; isActive: boolean; collapsed: boolean; onClick: () => void; }) { return (
{item.icon} {!collapsed && {item.label}}
); }); export default function MainLayout({ children }: { children: React.ReactNode }) { const { sidebarCollapsed, toggleSidebar, theme: themeMode, setTheme } = useAppStore(); const { user, logout } = useAuthStore(); const { token } = theme.useToken(); const navigate = useNavigate(); const location = useLocation(); const currentPath = location.pathname || '/'; const handleLogout = useCallback(async () => { await logout(); navigate('/login'); }, [logout, navigate]); const userMenuItems = [ { key: 'profile', icon: , label: user?.display_name || user?.username || '用户', disabled: true, }, { type: 'divider' as const }, { key: 'logout', icon: , label: '退出登录', danger: true, onClick: handleLogout, }, ]; const sidebarWidth = sidebarCollapsed ? 72 : 240; const isDark = themeMode === 'dark'; return ( {/* 现代深色侧边栏 */} {/* Logo 区域 */}
navigate('/')}>
E
{!sidebarCollapsed && ( ERP Platform )}
{/* 菜单组:基础模块 */} {!sidebarCollapsed &&
基础模块
}
{mainMenuItems.map((item) => ( navigate(item.key)} /> ))}
{/* 菜单组:业务模块 */} {!sidebarCollapsed &&
业务模块
}
{bizMenuItems.map((item) => ( navigate(item.key)} /> ))}
{/* 菜单组:系统 */} {!sidebarCollapsed &&
系统
}
{sysMenuItems.map((item) => ( navigate(item.key)} /> ))}
{/* 右侧主区域 */} {/* 顶部导航栏 */}
{/* 左侧:折叠按钮 + 标题 */}
{sidebarCollapsed ? : }
{routeTitleMap[currentPath] || '页面'}
{/* 右侧:搜索 + 通知 + 主题切换 + 用户 */}
setTheme(isDark ? 'light' : 'dark')}> {isDark ? : }
{(user?.display_name?.[0] || user?.username?.[0] || 'U').toUpperCase()} {!sidebarCollapsed && ( {user?.display_name || user?.username || 'User'} )}
{/* 内容区域 */} {children} {/* 底部 */}
); }