Files
d8d-admin-mobile-starter-pu…/client/admin/menu.tsx

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
};
};