menu.tsx 3.3 KB

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