menu.tsx 4.6 KB

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