menu.tsx 4.5 KB

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