menu.tsx 4.3 KB

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