2025-12-20 11:18:59 +00:00
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
|
import { Layout, Menu, Badge, message } from 'antd'
|
|
|
|
|
import { useNavigate, useLocation } from 'react-router-dom'
|
|
|
|
|
import {
|
|
|
|
|
DashboardOutlined,
|
|
|
|
|
DesktopOutlined,
|
|
|
|
|
GlobalOutlined,
|
|
|
|
|
CloudServerOutlined,
|
|
|
|
|
UserOutlined,
|
|
|
|
|
AppstoreOutlined,
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
BlockOutlined,
|
|
|
|
|
FolderOutlined,
|
|
|
|
|
FileTextOutlined,
|
2025-12-23 05:02:10 +00:00
|
|
|
SafetyOutlined,
|
|
|
|
|
TeamOutlined,
|
2025-12-20 11:18:59 +00:00
|
|
|
} from '@ant-design/icons'
|
|
|
|
|
import { getUserMenus } from '@/api/menu'
|
|
|
|
|
import './AppSider.css'
|
|
|
|
|
|
|
|
|
|
const { Sider } = Layout
|
|
|
|
|
|
|
|
|
|
// 图标映射
|
|
|
|
|
const iconMap = {
|
|
|
|
|
DashboardOutlined,
|
|
|
|
|
DesktopOutlined,
|
|
|
|
|
GlobalOutlined,
|
|
|
|
|
CloudServerOutlined,
|
|
|
|
|
UserOutlined,
|
|
|
|
|
AppstoreOutlined,
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
BlockOutlined,
|
|
|
|
|
FolderOutlined,
|
|
|
|
|
FileTextOutlined,
|
2025-12-23 05:02:10 +00:00
|
|
|
SafetyOutlined,
|
|
|
|
|
TeamOutlined,
|
2025-12-20 11:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function AppSider({ collapsed, onToggle }) {
|
|
|
|
|
const navigate = useNavigate()
|
|
|
|
|
const location = useLocation()
|
|
|
|
|
const [openKeys, setOpenKeys] = useState([])
|
|
|
|
|
const [menuData, setMenuData] = useState([])
|
|
|
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
|
|
|
|
|
|
// 加载菜单数据
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
loadMenus()
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
const loadMenus = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await getUserMenus()
|
|
|
|
|
if (res.data) {
|
|
|
|
|
setMenuData(res.data)
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Load menus error:', error)
|
|
|
|
|
message.error('加载菜单失败')
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据当前路径获取应该打开的父菜单
|
|
|
|
|
const getDefaultOpenKeys = () => {
|
|
|
|
|
const path = location.pathname
|
|
|
|
|
for (const item of menuData) {
|
|
|
|
|
if (item.children) {
|
|
|
|
|
const hasChild = item.children.some((c) => c.path === path)
|
|
|
|
|
if (hasChild) {
|
|
|
|
|
return [item.menu_code]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-29 12:53:50 +00:00
|
|
|
// 监听菜单数据加载完成,初始化打开的父菜单
|
2025-12-20 11:18:59 +00:00
|
|
|
useEffect(() => {
|
2025-12-29 12:53:50 +00:00
|
|
|
if (menuData.length > 0 && openKeys.length === 0) {
|
2025-12-20 11:18:59 +00:00
|
|
|
const defaultKeys = getDefaultOpenKeys()
|
|
|
|
|
setOpenKeys(defaultKeys)
|
|
|
|
|
}
|
2025-12-29 12:53:50 +00:00
|
|
|
}, [menuData])
|
2025-12-20 11:18:59 +00:00
|
|
|
|
|
|
|
|
const handleMenuClick = ({ key }) => {
|
|
|
|
|
// 查找对应的路径
|
|
|
|
|
for (const item of menuData) {
|
|
|
|
|
if (item.menu_code === key && item.path) {
|
|
|
|
|
navigate(item.path)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (item.children) {
|
|
|
|
|
const child = item.children.find((c) => c.menu_code === key)
|
|
|
|
|
if (child && child.path) {
|
|
|
|
|
navigate(child.path)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleOpenChange = (keys) => {
|
|
|
|
|
setOpenKeys(keys)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前选中的菜单项
|
|
|
|
|
const getSelectedKey = () => {
|
|
|
|
|
const path = location.pathname
|
|
|
|
|
for (const item of menuData) {
|
|
|
|
|
if (item.path === path) return item.menu_code
|
|
|
|
|
if (item.children) {
|
|
|
|
|
const child = item.children.find((c) => c.path === path)
|
|
|
|
|
if (child) return child.menu_code
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成菜单项配置
|
|
|
|
|
const getMenuItems = () => {
|
|
|
|
|
return menuData.map((item) => {
|
|
|
|
|
const IconComponent = iconMap[item.icon]
|
|
|
|
|
const icon = IconComponent ? <IconComponent /> : null
|
|
|
|
|
|
|
|
|
|
// 如果有子菜单
|
|
|
|
|
if (item.children && item.children.length > 0) {
|
|
|
|
|
return {
|
|
|
|
|
key: item.menu_code,
|
|
|
|
|
icon: icon,
|
|
|
|
|
label: item.menu_name,
|
|
|
|
|
popupClassName: 'sider-submenu-popup',
|
|
|
|
|
children: item.children.map((child) => ({
|
|
|
|
|
key: child.menu_code,
|
|
|
|
|
label: child.menu_name,
|
|
|
|
|
})),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 普通菜单项
|
|
|
|
|
return {
|
|
|
|
|
key: item.menu_code,
|
|
|
|
|
icon: icon,
|
|
|
|
|
label: item.menu_name,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Sider
|
|
|
|
|
className="app-sider"
|
|
|
|
|
collapsed={collapsed}
|
|
|
|
|
width={200}
|
|
|
|
|
collapsedWidth={64}
|
|
|
|
|
trigger={null}
|
|
|
|
|
>
|
|
|
|
|
{/* 菜单 */}
|
|
|
|
|
<Menu
|
|
|
|
|
mode="inline"
|
|
|
|
|
selectedKeys={[getSelectedKey()]}
|
|
|
|
|
openKeys={collapsed ? [] : openKeys}
|
|
|
|
|
onOpenChange={handleOpenChange}
|
|
|
|
|
onClick={handleMenuClick}
|
|
|
|
|
className="sider-menu"
|
|
|
|
|
items={getMenuItems()}
|
|
|
|
|
/>
|
|
|
|
|
</Sider>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default AppSider
|