199 lines
4.5 KiB
TypeScript
199 lines
4.5 KiB
TypeScript
import React from 'react';
|
|
import { useNavigate } from 'react-router';
|
|
import type { MenuProps } from 'antd';
|
|
import {
|
|
UserOutlined,
|
|
DashboardOutlined,
|
|
TeamOutlined,
|
|
SettingOutlined,
|
|
FileOutlined,
|
|
MessageOutlined,
|
|
InfoCircleOutlined,
|
|
BarChartOutlined,
|
|
EnvironmentOutlined,
|
|
MoonOutlined,
|
|
SunOutlined
|
|
} from '@ant-design/icons';
|
|
import { useTheme } from './hooks_sys.tsx';
|
|
|
|
export interface MenuItem {
|
|
key: string;
|
|
label: string;
|
|
icon?: React.ReactNode;
|
|
children?: MenuItem[];
|
|
path?: string;
|
|
permission?: string;
|
|
}
|
|
|
|
/**
|
|
* 菜单搜索 Hook
|
|
* 封装菜单搜索相关逻辑
|
|
*/
|
|
export const useMenuSearch = (menuItems: MenuItem[]) => {
|
|
const [searchText, setSearchText] = React.useState('');
|
|
|
|
// 过滤菜单项
|
|
const filteredMenuItems = React.useMemo(() => {
|
|
if (!searchText) return menuItems;
|
|
|
|
const filterItems = (items: MenuItem[]): MenuItem[] => {
|
|
return items
|
|
.map(item => {
|
|
// 克隆对象避免修改原数据
|
|
const newItem = { ...item };
|
|
if (newItem.children) {
|
|
newItem.children = filterItems(newItem.children);
|
|
}
|
|
return newItem;
|
|
})
|
|
.filter(item => {
|
|
// 保留匹配项或其子项匹配的项
|
|
const match = item.label.toLowerCase().includes(searchText.toLowerCase());
|
|
if (match) return true;
|
|
if (item.children?.length) return true;
|
|
return false;
|
|
});
|
|
};
|
|
|
|
return filterItems(menuItems);
|
|
}, [menuItems, searchText]);
|
|
|
|
// 清除搜索
|
|
const clearSearch = () => {
|
|
setSearchText('');
|
|
};
|
|
|
|
return {
|
|
searchText,
|
|
setSearchText,
|
|
filteredMenuItems,
|
|
clearSearch
|
|
};
|
|
};
|
|
|
|
export const useMenu = () => {
|
|
const { isDark, toggleTheme } = useTheme();
|
|
const navigate = useNavigate();
|
|
const [collapsed, setCollapsed] = React.useState(false);
|
|
const [openKeys, setOpenKeys] = React.useState<string[]>([]);
|
|
|
|
// 基础菜单项配置
|
|
const menuItems: MenuItem[] = [
|
|
{
|
|
key: 'dashboard',
|
|
label: '控制台',
|
|
icon: <DashboardOutlined />,
|
|
path: '/admin/dashboard'
|
|
},
|
|
{
|
|
key: 'users',
|
|
label: '用户管理',
|
|
icon: <TeamOutlined />,
|
|
path: '/admin/users',
|
|
permission: 'user:manage'
|
|
},
|
|
{
|
|
key: 'settings',
|
|
label: '系统设置',
|
|
icon: <SettingOutlined />,
|
|
children: [
|
|
{
|
|
key: 'theme-settings',
|
|
label: '主题设置',
|
|
path: '/admin/theme-settings',
|
|
permission: 'system:settings'
|
|
},
|
|
{
|
|
key: 'system-settings',
|
|
label: '系统配置',
|
|
path: '/admin/settings',
|
|
permission: 'system:settings'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
key: 'content',
|
|
label: '内容管理',
|
|
icon: <FileOutlined />,
|
|
children: [
|
|
{
|
|
key: 'know-info',
|
|
label: '知识库',
|
|
path: '/admin/know-info',
|
|
permission: 'content:manage'
|
|
},
|
|
{
|
|
key: 'file-library',
|
|
label: '文件库',
|
|
path: '/admin/file-library',
|
|
permission: 'content:manage'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
key: 'messages',
|
|
label: '消息中心',
|
|
icon: <MessageOutlined />,
|
|
path: '/admin/messages',
|
|
permission: 'message:view'
|
|
},
|
|
{
|
|
key: 'charts',
|
|
label: '数据图表',
|
|
icon: <BarChartOutlined />,
|
|
path: '/admin/chart-dashboard',
|
|
permission: 'chart:view'
|
|
},
|
|
{
|
|
key: 'maps',
|
|
label: '地图',
|
|
icon: <EnvironmentOutlined />,
|
|
path: '/admin/map-dashboard',
|
|
permission: 'map:view'
|
|
}
|
|
];
|
|
|
|
// 用户菜单项
|
|
const userMenuItems: MenuProps['items'] = [
|
|
{
|
|
key: 'profile',
|
|
label: '个人资料',
|
|
icon: <UserOutlined />
|
|
},
|
|
{
|
|
key: 'theme',
|
|
label: isDark ? '切换到亮色模式' : '切换到暗色模式',
|
|
icon: isDark ? <SunOutlined /> : <MoonOutlined />,
|
|
onClick: () => toggleTheme()
|
|
},
|
|
{
|
|
key: 'logout',
|
|
label: '退出登录',
|
|
icon: <InfoCircleOutlined />,
|
|
danger: true
|
|
}
|
|
];
|
|
|
|
// 处理菜单点击
|
|
const handleMenuClick = (item: MenuItem) => {
|
|
if (item.path) {
|
|
navigate(item.path);
|
|
}
|
|
};
|
|
|
|
// 处理菜单展开变化
|
|
const onOpenChange = (keys: string[]) => {
|
|
const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);
|
|
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
|
|
};
|
|
|
|
return {
|
|
menuItems,
|
|
userMenuItems,
|
|
openKeys,
|
|
collapsed,
|
|
setCollapsed,
|
|
handleMenuClick,
|
|
onOpenChange
|
|
};
|
|
}; |