import { useEffect, useMemo, useState } from 'react' import type { ReactNode } from 'react' import { Outlet, useLocation, useNavigate } from 'react-router-dom' import { Layout, Dropdown, Space, Typography, Avatar, Tag, Button, Tooltip, } from 'antd' import { ApiOutlined, AppstoreOutlined, CodeOutlined, DashboardOutlined, DownOutlined, FileTextOutlined, LogoutOutlined, MenuOutlined, OrderedListOutlined, ShopOutlined, TeamOutlined, UserOutlined, WalletOutlined, } from '@ant-design/icons' import { useAuth } from '../store/auth' import type { MenuProps } from 'antd' const { Header, Sider, Content } = Layout interface SidebarChild { key: string label: string path?: string disabled?: boolean } interface SidebarSection { key: string label: string icon: ReactNode path?: string disabled?: boolean children?: SidebarChild[] } const adminSections: SidebarSection[] = [ { key: 'dashboard', label: '工作台', icon: , path: '/', }, { key: 'products', label: '商品管理', icon: , children: [{ key: 'merchant-products', label: '商品列表', path: '/merchant-products' }], }, { key: 'shops', label: '商户管理', icon: , children: [{ key: 'shop-list', label: '平台商户', path: '/platform-merchants' }], }, { key: 'orders', label: '订单管理', icon: , children: [{ key: 'fulfillment-orders', label: '发货订单', path: '/merchant-orders' }], }, { key: 'staff', label: '员工管理', icon: , children: [{ key: 'merchant-members', label: '成员管理', path: '/merchant-members' }], }, { key: 'funds', label: '积分管理', icon: , children: [{ key: 'merchant-wallet', label: '积分明细', path: '/merchant-wallet' }], }, { key: 'open-api', label: '开放 API', icon: , children: [ { key: 'api-keys', label: 'API 密钥', path: '/merchant-api-keys' }, { key: 'api-callbacks', label: '回调订阅', path: '/merchant-callbacks' }, { key: 'api-docs', label: '对接文档', path: '/open-api' }, { key: 'api-debug', label: '调用调试', path: '/api-debug' }, ], }, ] const merchantSections: SidebarSection[] = [ { key: 'dashboard', label: '工作台', icon: , path: '/', }, { key: 'products', label: '商品管理', icon: , children: [{ key: 'merchant-products', label: '商品列表', path: '/merchant-products' }], }, { key: 'orders', label: '订单管理', icon: , children: [{ key: 'fulfillment-orders', label: '发货订单', path: '/merchant-orders' }], }, { key: 'funds', label: '积分管理', icon: , children: [{ key: 'merchant-wallet', label: '积分明细', path: '/merchant-wallet' }], }, { key: 'staff', label: '员工管理', icon: , children: [{ key: 'merchant-members', label: '成员管理', path: '/merchant-members' }], }, { key: 'open-api', label: '开放 API', icon: , children: [ { key: 'api-keys', label: 'API 密钥', path: '/merchant-api-keys' }, { key: 'api-callbacks', label: '回调订阅', path: '/merchant-callbacks' }, ], }, ] function getSelectedKey(pathname: string, search: string) { if (pathname === '/') return 'dashboard' if (pathname.startsWith('/merchant-products')) return 'merchant-products' if (pathname.startsWith('/merchant-orders')) return 'fulfillment-orders' if (pathname.startsWith('/merchant-wallet')) return 'merchant-wallet' if (pathname.startsWith('/merchant-members')) return 'merchant-members' if (pathname.startsWith('/merchant-callbacks')) return 'api-callbacks' if (pathname.startsWith('/merchant-api-keys')) return 'api-keys' if (pathname.startsWith('/merchant-center')) { const tab = new URLSearchParams(search).get('tab') const tabKeys: Record = { products: 'merchant-products', orders: 'fulfillment-orders', wallet: 'merchant-wallet', members: 'merchant-members', callbacks: 'api-callbacks', } return tab ? tabKeys[tab] || 'merchant-products' : 'merchant-products' } if (pathname.startsWith('/open-api')) return 'api-docs' if (pathname.startsWith('/api-debug')) return 'api-debug' if (pathname.startsWith('/platform-merchants')) return 'shop-list' return 'dashboard' } function getInitialOpenKeys(sections: SidebarSection[], selectedKey: string) { return sections .filter((section) => section.children?.some((child) => child.key === selectedKey)) .map((section) => section.key) } export default function MainLayout() { const [collapsed, setCollapsed] = useState(false) const { user, logout, isAdmin } = useAuth() const navigate = useNavigate() const location = useLocation() const isDocsPage = location.pathname.startsWith('/open-api') const sections = useMemo(() => (isAdmin ? adminSections : merchantSections), [isAdmin]) const selectedKey = getSelectedKey(location.pathname, location.search) const [openKeys, setOpenKeys] = useState(() => getInitialOpenKeys(sections, selectedKey)) useEffect(() => { const nextOpenKeys = getInitialOpenKeys(sections, selectedKey) setOpenKeys((current) => Array.from(new Set([...current, ...nextOpenKeys]))) }, [sections, selectedKey]) const toggleSection = (section: SidebarSection) => { if (section.disabled) return if (section.path) { navigate(section.path) return } if (collapsed) { const firstEnabledChild = section.children?.find((child) => child.path && !child.disabled) if (firstEnabledChild?.path) navigate(firstEnabledChild.path) return } setOpenKeys((current) => current.includes(section.key) ? current.filter((key) => key !== section.key) : [...current, section.key], ) } const handleChildClick = (child: SidebarChild) => { if (!child.path || child.disabled) return navigate(child.path) } const userMenu: MenuProps['items'] = [ { key: 'user-info', disabled: true, label: ( {user?.nickname || user?.username} 角色:{isAdmin ? '平台超级管理员' : '商户成员'} ), }, { type: 'divider' }, { key: 'logout', icon: , label: 退出登录, onClick: () => { logout() navigate('/login') }, }, ] return ( S {!collapsed ? Skin Hub : null} {sections.map((section) => { const isOpen = openKeys.includes(section.key) const isSelected = selectedKey === section.key const hasSelectedChild = section.children?.some((child) => child.key === selectedKey) const isParentActive = hasSelectedChild const isSingleActive = isSelected && !section.children?.length return ( toggleSection(section)} title={collapsed ? section.label : undefined} > {section.icon} {!collapsed ? {section.label} : null} {!collapsed && section.children?.length ? ( ) : null} {!collapsed && section.children?.length && isOpen ? ( {section.children.map((child) => ( handleChildClick(child)} disabled={child.disabled} > {child.label} ))} ) : null} ) })} setCollapsed(!collapsed)} aria-label={collapsed ? '展开侧边栏' : '收起侧边栏'} title={collapsed ? '展开侧边栏' : '收起侧边栏'} > {isAdmin && ( } onClick={() => navigate('/open-api')} > API文档 } onClick={() => navigate('/api-debug')} > 接口调试 )} } /> {user?.nickname || user?.username} {isAdmin ? ( 管理员 ) : ( 商户 )} ) }