index.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import { Navbar } from "@contentful/f36-navbar";
  2. import {
  3. MagnifyingGlassIcon,
  4. QuestionIcon,
  5. GearSixIcon,
  6. } from "@contentful/f36-icons";
  7. import { useAuth } from "../../contexts/AuthContext";
  8. import { useMenu } from "../../contexts/MenuContext";
  9. import { useNavigate, useLocation } from "react-router-dom";
  10. import { useEffect, useState } from "react";
  11. import type { JeecgMenu } from "../../types/menu";
  12. import SearchModal from "../../components/SearchModal";
  13. export default function Header() {
  14. const { menus, loading } = useAuth();
  15. const { activeFirstMenu, setActiveFirstMenu, setActiveSecondMenu } =
  16. useMenu();
  17. const navigate = useNavigate();
  18. const location = useLocation();
  19. const [isSearchOpen, setIsSearchOpen] = useState(false);
  20. // 获取顶级菜单(一级菜单)
  21. const topMenus = menus.filter((menu) => !menu.hidden && !menu.meta?.hideMenu);
  22. // 根据当前路由自动设置活动菜单
  23. useEffect(() => {
  24. const path = location.pathname;
  25. const segments = path.split("/").filter(Boolean);
  26. const firstPath = segments[0];
  27. const matchedMenu = topMenus.find((menu) => {
  28. const menuPath = menu.path || "";
  29. const menuSegments = menuPath.split("/").filter(Boolean);
  30. return menuSegments[0] === firstPath;
  31. });
  32. if (matchedMenu && matchedMenu.id !== activeFirstMenu?.id) {
  33. setActiveFirstMenu(matchedMenu);
  34. setActiveSecondMenu(null);
  35. }
  36. }, [
  37. location.pathname,
  38. topMenus,
  39. activeFirstMenu,
  40. setActiveFirstMenu,
  41. setActiveSecondMenu,
  42. ]);
  43. // 处理菜单点击
  44. const handleMenuClick = (menu: JeecgMenu, child?: JeecgMenu) => {
  45. if (child) {
  46. // 点击子菜单
  47. setActiveFirstMenu(menu);
  48. setActiveSecondMenu(child);
  49. navigate(child.path || "");
  50. } else {
  51. // 点击一级菜单(无子菜单)
  52. setActiveFirstMenu(menu);
  53. setActiveSecondMenu(null);
  54. navigate(menu.path || "");
  55. }
  56. };
  57. // 跳转到权限管理
  58. const toPermissionPage = () => {
  59. debugger;
  60. };
  61. // 退出登录
  62. const loginOut = () => {
  63. navigate('/login')
  64. }
  65. if (loading) {
  66. return <div style={{ padding: "16px" }}>加载中...</div>;
  67. }
  68. // 渲染主导航(桌面端)
  69. const mainNavigation = (
  70. <>
  71. {topMenus.map((menu) => {
  72. const hasChildren = menu.children && menu.children.length > 0;
  73. const isActive = activeFirstMenu?.id === menu.id;
  74. if (hasChildren) {
  75. // 有子菜单的项目
  76. return (
  77. <Navbar.Item
  78. key={menu.id}
  79. title={menu.meta?.title || menu.name}
  80. isActive={isActive}
  81. >
  82. {menu.children
  83. ?.filter((child) => !child.hidden && !child.meta?.hideMenu)
  84. .map((child) => (
  85. <Navbar.MenuItem
  86. key={child.id}
  87. title={child.meta?.title || child.name}
  88. onClick={() => handleMenuClick(menu, child)}
  89. />
  90. ))}
  91. </Navbar.Item>
  92. );
  93. } else {
  94. // 无子菜单的项目
  95. return (
  96. <Navbar.Item
  97. key={menu.id}
  98. title={menu.meta?.title || menu.name}
  99. isActive={isActive}
  100. onClick={() => handleMenuClick(menu)}
  101. />
  102. );
  103. }
  104. })}
  105. </>
  106. );
  107. // 渲染移动端导航
  108. const mobileNavigation = (
  109. <>
  110. {topMenus.map((menu) => {
  111. const hasChildren = menu.children && menu.children.length > 0;
  112. if (hasChildren) {
  113. // 有子菜单的项目
  114. return (
  115. <Navbar.Submenu key={menu.id} title={menu.meta?.title || menu.name}>
  116. {menu.children
  117. ?.filter((child) => !child.hidden && !child.meta?.hideMenu)
  118. .map((child) => (
  119. <Navbar.MenuItem
  120. key={child.id}
  121. title={child.meta?.title || child.name}
  122. onClick={() => handleMenuClick(menu, child)}
  123. />
  124. ))}
  125. </Navbar.Submenu>
  126. );
  127. } else {
  128. // 无子菜单的项目
  129. return (
  130. <Navbar.MenuItem
  131. key={menu.id}
  132. title={menu.meta?.title || menu.name}
  133. onClick={() => handleMenuClick(menu)}
  134. />
  135. );
  136. }
  137. })}
  138. </>
  139. );
  140. // 右侧辅助导航
  141. const secondaryNavigation = (
  142. <>
  143. <Navbar.Item
  144. label="快速搜索"
  145. icon={<MagnifyingGlassIcon />}
  146. onClick={() => setIsSearchOpen(true)}
  147. />
  148. <Navbar.Item label="帮助菜单" icon={<QuestionIcon />}>
  149. <Navbar.MenuItem
  150. as="a"
  151. target="_blank"
  152. rel="noopener noreferrer"
  153. title="帮助中心"
  154. href="https://www.contentful.com/help/"
  155. />
  156. <Navbar.MenuItem
  157. as="a"
  158. target="_blank"
  159. rel="noopener noreferrer"
  160. title="开发者文档"
  161. href="https://www.contentful.com/developers/docs/"
  162. />
  163. <Navbar.MenuDivider />
  164. <Navbar.MenuItem
  165. as="a"
  166. target="_blank"
  167. rel="noopener noreferrer"
  168. title="获取支持"
  169. href="https://support.contentful.com"
  170. />
  171. </Navbar.Item>
  172. <Navbar.Item label="设置菜单" icon={<GearSixIcon />}>
  173. <Navbar.MenuSectionTitle>通用</Navbar.MenuSectionTitle>
  174. <Navbar.MenuItem title="首页" />
  175. <Navbar.MenuItem title="API 密钥" />
  176. <Navbar.MenuSectionTitle>空间</Navbar.MenuSectionTitle>
  177. <Navbar.MenuItem title="应用" />
  178. <Navbar.MenuItem title="权限" onClick={toPermissionPage} />
  179. </Navbar.Item>
  180. </>
  181. );
  182. return (
  183. <>
  184. <Navbar
  185. mainNavigation={mainNavigation}
  186. mobileNavigation={mobileNavigation}
  187. // switcher={
  188. // <Navbar.Switcher
  189. // isAlias={false}
  190. // envVariant="master"
  191. // space="Content Space"
  192. // environment="master"
  193. // />
  194. // }
  195. secondaryNavigation={secondaryNavigation}
  196. account={
  197. <Navbar.Account username="管理员" initials="A" label="账户设置">
  198. <Navbar.MenuItem title="账户设置" />
  199. <Navbar.MenuItem title="控制台" />
  200. <Navbar.MenuDivider />
  201. <Navbar.MenuItem
  202. title="外部链接"
  203. as="a"
  204. href="https://www.contentful.com"
  205. target="_blank"
  206. rel="noopener noreferrer"
  207. />
  208. <Navbar.MenuDivider />
  209. <Navbar.MenuItem title="退出登录" onClick={loginOut} />
  210. </Navbar.Account>
  211. }
  212. aria={{
  213. labelMainNavigation: "主导航",
  214. labelSecondaryNavigation: "辅助导航",
  215. labelAccount: "我的账户",
  216. }}
  217. />
  218. {/* 搜索对话框 */}
  219. <SearchModal
  220. isOpen={isSearchOpen}
  221. onClose={() => setIsSearchOpen(false)}
  222. />
  223. </>
  224. );
  225. }