menu.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import React from 'react';
  2. import { useNavigate } from 'react-router';
  3. import type { MenuProps } from 'antd';
  4. import {
  5. UserOutlined,
  6. DashboardOutlined,
  7. TeamOutlined,
  8. SettingOutlined,
  9. FileOutlined,
  10. MessageOutlined,
  11. InfoCircleOutlined,
  12. BarChartOutlined,
  13. EnvironmentOutlined,
  14. MoonOutlined,
  15. SunOutlined,
  16. CalendarOutlined,
  17. DatabaseOutlined,
  18. PieChartOutlined,
  19. MonitorOutlined
  20. } from '@ant-design/icons';
  21. import { useTheme } from './hooks_sys.tsx';
  22. export interface MenuItem {
  23. key: string;
  24. label: string;
  25. icon?: React.ReactNode;
  26. children?: MenuItem[];
  27. path?: string;
  28. permission?: string;
  29. }
  30. /**
  31. * 菜单搜索 Hook
  32. * 封装菜单搜索相关逻辑
  33. */
  34. export const useMenuSearch = (menuItems: MenuItem[]) => {
  35. const [searchText, setSearchText] = React.useState('');
  36. // 过滤菜单项
  37. const filteredMenuItems = React.useMemo(() => {
  38. if (!searchText) return menuItems;
  39. const filterItems = (items: MenuItem[]): MenuItem[] => {
  40. return items
  41. .map(item => {
  42. // 克隆对象避免修改原数据
  43. const newItem = { ...item };
  44. if (newItem.children) {
  45. newItem.children = filterItems(newItem.children);
  46. }
  47. return newItem;
  48. })
  49. .filter(item => {
  50. // 保留匹配项或其子项匹配的项
  51. const match = item.label.toLowerCase().includes(searchText.toLowerCase());
  52. if (match) return true;
  53. if (item.children?.length) return true;
  54. return false;
  55. });
  56. };
  57. return filterItems(menuItems);
  58. }, [menuItems, searchText]);
  59. // 清除搜索
  60. const clearSearch = () => {
  61. setSearchText('');
  62. };
  63. return {
  64. searchText,
  65. setSearchText,
  66. filteredMenuItems,
  67. clearSearch
  68. };
  69. };
  70. export const useMenu = () => {
  71. const { isDark, toggleTheme } = useTheme();
  72. const navigate = useNavigate();
  73. const [collapsed, setCollapsed] = React.useState(false);
  74. const [openKeys, setOpenKeys] = React.useState<string[]>([]);
  75. // 基础菜单项配置
  76. const menuItems: MenuItem[] = [
  77. {
  78. key: 'dashboard',
  79. label: '控制台',
  80. icon: <DashboardOutlined />,
  81. path: '/admin/dashboard'
  82. },
  83. {
  84. key: 'monitor',
  85. icon: <DatabaseOutlined />,
  86. label: '监控管理',
  87. children: [
  88. {
  89. key: 'device-monitor',
  90. label: '设备实时监控',
  91. path: '/admin/device-monitor',
  92. },
  93. {
  94. key: 'temperature-humidity',
  95. label: '温湿度监控',
  96. path: '/admin/temperature-humidity',
  97. },
  98. {
  99. key: 'smoke-water',
  100. label: '烟感及水浸监控',
  101. path: '/admin/smoke-water',
  102. },
  103. {
  104. key: 'device-map',
  105. label: '设备地图监控',
  106. path: '/admin/device-map',
  107. },
  108. {
  109. key: 'alert-records',
  110. label: '告警记录',
  111. path: '/admin/alert-records',
  112. },
  113. {
  114. key: 'alert-handle-logs',
  115. label: '告警处理记录',
  116. path: '/admin/alert-handle-logs',
  117. },
  118. {
  119. key: 'alert-notify-configs',
  120. label: '告警通知配置',
  121. path: '/admin/alert-notify-configs',
  122. },
  123. {
  124. key: 'device-alert-rules',
  125. label: '设备告警规则',
  126. path: '/admin/device-alert-rules',
  127. },
  128. ],
  129. },
  130. {
  131. key: 'zichan',
  132. icon: <CalendarOutlined />,
  133. label: '资产管理',
  134. children: [
  135. {
  136. key: 'zichan-categorys',
  137. label: '资产分类',
  138. path: '/admin/zichan-categorys'
  139. },
  140. {
  141. key: 'zichan-areas',
  142. label: '资产区域',
  143. path: '/admin/zichan-areas',
  144. },
  145. {
  146. key: 'zichan-info',
  147. label: '资产信息',
  148. path: '/admin/zichan',
  149. },
  150. {
  151. key: 'zichan-transfer',
  152. label: '资产流转',
  153. path: '/admin/zichan-transfer',
  154. },
  155. ],
  156. },
  157. {
  158. key: 'device',
  159. icon: <SettingOutlined />,
  160. label: '设备管理',
  161. children: [
  162. {
  163. key: 'device-types',
  164. label: '设备类型',
  165. path: '/admin/device-types',
  166. },
  167. {
  168. key: 'device-instances',
  169. label: '设备实例',
  170. path: '/admin/device-instances',
  171. },
  172. {
  173. key: 'modbus-rtu-devices',
  174. label: 'Modbus RTU设备',
  175. path: '/admin/modbus-rtu-devices',
  176. },
  177. {
  178. key: "greenhouse-protocol",
  179. label: "温室协议设置",
  180. path: "/admin/greenhouse-protocol"
  181. },
  182. {
  183. key: 'racks',
  184. label: '机柜管理',
  185. path: '/admin/racks',
  186. },
  187. {
  188. key: 'rack-server-types',
  189. label: '机柜服务器类型',
  190. path: '/admin/rack-server-types',
  191. },
  192. {
  193. key: 'rack-servers',
  194. label: '机柜服务器',
  195. path: '/admin/rack-servers',
  196. },
  197. ],
  198. },
  199. {
  200. key: "work-orders",
  201. label: "工单管理",
  202. icon: <MonitorOutlined />,
  203. path: "/admin/work-orders"
  204. },
  205. {
  206. key: 'inspection',
  207. label: '巡检管理',
  208. icon: <MonitorOutlined />,
  209. path: '/admin/inspections'
  210. },
  211. {
  212. key: 'analysis',
  213. icon: <PieChartOutlined />,
  214. label: '分析报表',
  215. children: [
  216. {
  217. key: 'analysis-alert-trend',
  218. label: '告警趋势图',
  219. path: '/admin/analysis/alert-trend',
  220. },
  221. {
  222. key: 'analysis-asset-category',
  223. label: '资产分类统计图',
  224. path: '/admin/analysis/asset-category',
  225. },
  226. {
  227. key: 'analysis-online-devices',
  228. label: '设备在线统计图',
  229. path: '/admin/analysis/online-devices',
  230. },
  231. {
  232. key: 'analysis-asset-transfer',
  233. label: '资产流转统计图',
  234. path: '/admin/analysis/asset-transfer',
  235. },
  236. ],
  237. },
  238. {
  239. key: 'users',
  240. label: '用户管理',
  241. icon: <TeamOutlined />,
  242. path: '/admin/users',
  243. permission: 'user:manage'
  244. },
  245. {
  246. key: 'settings',
  247. label: '系统设置',
  248. icon: <SettingOutlined />,
  249. children: [
  250. {
  251. key: 'theme-settings',
  252. label: '主题设置',
  253. path: '/admin/theme-settings',
  254. permission: 'system:settings'
  255. },
  256. {
  257. key: 'system-settings',
  258. label: '系统配置',
  259. path: '/admin/settings',
  260. permission: 'system:settings'
  261. }
  262. ]
  263. },
  264. {
  265. key: 'content',
  266. label: '内容管理',
  267. icon: <FileOutlined />,
  268. children: [
  269. {
  270. key: 'know-info',
  271. label: '知识库',
  272. path: '/admin/know-info',
  273. permission: 'content:manage'
  274. },
  275. {
  276. key: 'file-library',
  277. label: '文件库',
  278. path: '/admin/file-library',
  279. permission: 'content:manage'
  280. }
  281. ]
  282. },
  283. {
  284. key: 'messages',
  285. label: '消息中心',
  286. icon: <MessageOutlined />,
  287. path: '/admin/messages',
  288. permission: 'message:view'
  289. },
  290. {
  291. key: 'sms-module',
  292. label: '短信模块',
  293. icon: <MessageOutlined />,
  294. path: '/admin/sms-module',
  295. permission: 'message:view'
  296. },
  297. {
  298. key: 'charts',
  299. label: '数据图表',
  300. icon: <BarChartOutlined />,
  301. path: '/admin/chart-dashboard',
  302. permission: 'chart:view'
  303. },
  304. {
  305. key: 'maps',
  306. label: '地图',
  307. icon: <EnvironmentOutlined />,
  308. path: '/admin/map-dashboard',
  309. permission: 'map:view'
  310. }
  311. ];
  312. // 用户菜单项
  313. const userMenuItems: MenuProps['items'] = [
  314. {
  315. key: 'profile',
  316. label: '个人资料',
  317. icon: <UserOutlined />
  318. },
  319. {
  320. key: 'theme',
  321. label: isDark ? '切换到亮色模式' : '切换到暗色模式',
  322. icon: isDark ? <SunOutlined /> : <MoonOutlined />,
  323. onClick: () => toggleTheme()
  324. },
  325. {
  326. key: 'logout',
  327. label: '退出登录',
  328. icon: <InfoCircleOutlined />,
  329. danger: true
  330. }
  331. ];
  332. // 处理菜单点击
  333. const handleMenuClick = (item: MenuItem) => {
  334. if (item.path) {
  335. navigate(item.path);
  336. }
  337. };
  338. // 处理菜单展开变化
  339. const onOpenChange = (keys: string[]) => {
  340. const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);
  341. setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
  342. };
  343. return {
  344. menuItems,
  345. userMenuItems,
  346. openKeys,
  347. collapsed,
  348. setCollapsed,
  349. handleMenuClick,
  350. onOpenChange
  351. };
  352. };