index.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import React, {
  2. useMemo,
  3. useEffect,
  4. useState,
  5. useCallback,
  6. Suspense,
  7. } from "react";
  8. import { App, Layout, message } from "antd";
  9. import { useSelector } from "react-redux";
  10. import {
  11. Route,
  12. Routes,
  13. useNavigate,
  14. useLocation,
  15. Navigate,
  16. } from "react-router-dom";
  17. import { Content } from "antd/es/layout/layout";
  18. import { hasToken, getTokenInfo } from "@/utils";
  19. import store from "@/store";
  20. import { LayoutSider, LayoutHeader } from "./components";
  21. import { RootState } from "@/store";
  22. import { RouteType } from "./types";
  23. import { DEFAULT_ADMIN_MENU, DEFAULT_MENU } from "./constants";
  24. import "./index.scss";
  25. import { MemoSpinLoding } from "@/components";
  26. import { isNaN } from "lodash";
  27. const NotFound = React.lazy(() => import("@/components/NotFound"));
  28. export default function CustomLayout() {
  29. const navigate = useNavigate();
  30. const location = useLocation();
  31. const [activeMenuKey, setActiveMenuKey] = useState("/");
  32. const baseStore = useSelector<RootState, RootState["base"]>(
  33. (state) => state.base
  34. );
  35. const menuList = useMemo<RouteType[]>(() => {
  36. const list = baseStore.userInfo?.user.isAdmin
  37. ? [...DEFAULT_MENU, ...DEFAULT_ADMIN_MENU]
  38. : [...DEFAULT_MENU];
  39. function deep(v: RouteType[], parent?: RouteType) {
  40. const stack: RouteType[] = [];
  41. v.forEach((item) => {
  42. const { child = [], ...rest } = item;
  43. if (!!parent) {
  44. rest.key = parent.key + rest.key;
  45. rest.parent = {
  46. key: parent.key,
  47. label: parent.label,
  48. };
  49. }
  50. stack.push(rest);
  51. if (!!child.length) {
  52. stack.push(...deep(child, item));
  53. }
  54. });
  55. return stack;
  56. }
  57. return deep(list);
  58. }, [baseStore.userInfo]);
  59. const [curMenu, setCurMenu] = useState<null | RouteType>(null);
  60. useEffect(() => {
  61. if (!hasToken()) {
  62. message.open({
  63. type: "warning",
  64. content: "登录失效!",
  65. duration: 4,
  66. });
  67. navigate("/login", {
  68. replace: true,
  69. });
  70. } else {
  71. store.dispatch({ type: "setUserInfo", payload: getTokenInfo() });
  72. }
  73. }, [navigate]);
  74. /**
  75. * 初始化菜单选中状态
  76. */
  77. const getActiveMenu = useCallback(() => {
  78. const split = location.pathname.split("/").slice(1);
  79. const pMenu = "/" + split[0];
  80. if (split.length > 1) {
  81. const pathname = split
  82. .map((i) => (!isNaN(Number(i)) ? ":id" : i))
  83. .join("/");
  84. setCurMenu(menuList.find((i) => i.key === `/${pathname}`) as RouteType);
  85. } else {
  86. setCurMenu(menuList.find((i) => i.key === pMenu) as RouteType);
  87. }
  88. setActiveMenuKey(pMenu);
  89. }, [location, menuList]);
  90. useEffect(() => {
  91. getActiveMenu();
  92. }, [getActiveMenu]);
  93. const handleMenu = useCallback(
  94. (item: Partial<RouteType>) => {
  95. const path = item?.key as string;
  96. setActiveMenuKey(path);
  97. navigate(path);
  98. },
  99. [setActiveMenuKey, navigate]
  100. );
  101. return (
  102. <App>
  103. <Layout hasSider className="layout">
  104. {/* 菜单 */}
  105. <LayoutSider
  106. selectedKeys={[activeMenuKey]}
  107. items={menuList.filter((i) => !i.hide)}
  108. onClick={handleMenu}
  109. />
  110. <Layout style={{ marginLeft: 220 }}>
  111. {/* 头部 */}
  112. <LayoutHeader menu={curMenu} />
  113. {/* 主体 */}
  114. <Content
  115. style={{
  116. margin: "15px",
  117. overflow: "initial",
  118. position: "relative",
  119. background: "#ffffff",
  120. padding: 20,
  121. borderRadius: 4,
  122. }}
  123. >
  124. <Suspense fallback={<MemoSpinLoding />}>
  125. <Routes>
  126. <Route path="/" element={<Navigate to="/weapon" />} />
  127. {menuList.map((menu) => (
  128. <Route
  129. key={menu.key}
  130. path={menu.key}
  131. Component={menu.component}
  132. />
  133. ))}
  134. <Route path="*" Component={NotFound} />
  135. </Routes>
  136. </Suspense>
  137. </Content>
  138. </Layout>
  139. </Layout>
  140. </App>
  141. );
  142. }