menu.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import React from 'react';
  2. import { useNavigate } from 'react-router';
  3. import { useAuth } from './hooks/AuthProvider';
  4. import {
  5. Users,
  6. Settings,
  7. User,
  8. LogOut,
  9. BarChart3,
  10. LayoutDashboard,
  11. File
  12. } from 'lucide-react';
  13. export interface MenuItem {
  14. key: string;
  15. label: string;
  16. icon?: React.ReactNode;
  17. children?: MenuItem[];
  18. path?: string;
  19. permission?: string;
  20. onClick?: () => void;
  21. }
  22. /**
  23. * 菜单搜索 Hook
  24. * 封装菜单搜索相关逻辑
  25. */
  26. export const useMenuSearch = (menuItems: MenuItem[]) => {
  27. const [searchText, setSearchText] = React.useState('');
  28. // 过滤菜单项
  29. const filteredMenuItems = React.useMemo(() => {
  30. if (!searchText) return menuItems;
  31. const filterItems = (items: MenuItem[]): MenuItem[] => {
  32. return items
  33. .map(item => {
  34. // 克隆对象避免修改原数据
  35. const newItem = { ...item };
  36. if (newItem.children) {
  37. newItem.children = filterItems(newItem.children);
  38. }
  39. return newItem;
  40. })
  41. .filter(item => {
  42. // 保留匹配项或其子项匹配的项
  43. const match = item.label.toLowerCase().includes(searchText.toLowerCase());
  44. if (match) return true;
  45. if (item.children?.length) return true;
  46. return false;
  47. });
  48. };
  49. return filterItems(menuItems);
  50. }, [menuItems, searchText]);
  51. // 清除搜索
  52. const clearSearch = () => {
  53. setSearchText('');
  54. };
  55. return {
  56. searchText,
  57. setSearchText,
  58. filteredMenuItems,
  59. clearSearch
  60. };
  61. };
  62. export const useMenu = () => {
  63. const navigate = useNavigate();
  64. const { logout: handleLogout } = useAuth();
  65. const [collapsed, setCollapsed] = React.useState(false);
  66. // 基础菜单项配置
  67. const menuItems: MenuItem[] = [
  68. {
  69. key: 'dashboard',
  70. label: '控制台',
  71. icon: <LayoutDashboard className="h-4 w-4" />,
  72. path: '/admin/dashboard'
  73. },
  74. {
  75. key: 'users',
  76. label: '用户管理',
  77. icon: <Users className="h-4 w-4" />,
  78. path: '/admin/users',
  79. permission: 'user:manage'
  80. },
  81. {
  82. key: 'files',
  83. label: '文件管理',
  84. icon: <File className="h-4 w-4" />,
  85. path: '/admin/files',
  86. permission: 'file:manage'
  87. },
  88. {
  89. key: 'analytics',
  90. label: '数据分析',
  91. icon: <BarChart3 className="h-4 w-4" />,
  92. path: '/admin/analytics',
  93. permission: 'analytics:view'
  94. },
  95. {
  96. key: 'settings',
  97. label: '系统设置',
  98. icon: <Settings className="h-4 w-4" />,
  99. path: '/admin/settings',
  100. permission: 'settings:manage'
  101. },
  102. ];
  103. // 用户菜单项
  104. const userMenuItems = [
  105. {
  106. key: 'profile',
  107. label: '个人资料',
  108. icon: <User className="mr-2 h-4 w-4" />,
  109. onClick: () => navigate('/admin/profile')
  110. },
  111. {
  112. key: 'settings',
  113. label: '账户设置',
  114. icon: <Settings className="mr-2 h-4 w-4" />,
  115. onClick: () => navigate('/admin/account-settings')
  116. },
  117. {
  118. type: 'separator',
  119. key: 'divider',
  120. },
  121. {
  122. key: 'logout',
  123. label: '退出登录',
  124. icon: <LogOut className="mr-2 h-4 w-4" />,
  125. onClick: () => handleLogout()
  126. }
  127. ];
  128. // 处理菜单点击
  129. const handleMenuClick = (item: MenuItem) => {
  130. if (item.path) {
  131. navigate(item.path);
  132. }
  133. if (item.onClick) {
  134. item.onClick();
  135. }
  136. };
  137. return {
  138. menuItems,
  139. userMenuItems,
  140. collapsed,
  141. setCollapsed,
  142. handleMenuClick,
  143. };
  144. };