feat: 动态路由
This commit is contained in:
101
src/app.tsx
101
src/app.tsx
@@ -1,9 +1,9 @@
|
||||
import { LinkOutlined } from "@ant-design/icons";
|
||||
import React, { Children, Component, JSX, Suspense } from "react";
|
||||
import { Spin } from "antd";
|
||||
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
|
||||
import { SettingDrawer } from "@ant-design/pro-components";
|
||||
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
||||
import { history, Link } from "@umijs/max";
|
||||
import React from "react";
|
||||
import { history, Link, Navigate } from "@umijs/max";
|
||||
import {
|
||||
AvatarDropdown,
|
||||
AvatarName,
|
||||
@@ -16,13 +16,20 @@ import type { UserVO, TokenType, UserInfoVO } from "@/services/login/types";
|
||||
import defaultSettings from "../config/defaultSettings";
|
||||
import { errorConfig } from "./requestErrorConfig";
|
||||
import "@ant-design/v5-patch-for-react-19";
|
||||
import { getAccessToken, getRefreshToken, getTenantId } from "./utils/auth";
|
||||
import { getAccessToken, getRefreshToken, getTenantId } from "@/utils/auth";
|
||||
import { CACHE_KEY, useCache } from "./hooks/web/useCache";
|
||||
import { MenuVO } from "./services/system/menu";
|
||||
|
||||
import {
|
||||
transformBackendMenuToFlatRoutes,
|
||||
transformMenuToRoutes,
|
||||
} from "@/utils/menuUtils";
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const isDevOrTest = isDev || process.env.CI;
|
||||
const loginPath = "/user/login";
|
||||
|
||||
// 全局存储菜单数据和路由映射
|
||||
|
||||
/**
|
||||
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
|
||||
* */
|
||||
@@ -43,6 +50,9 @@ export async function getInitialState(): Promise<{
|
||||
const { data } = await getInfo();
|
||||
wsCache.set(CACHE_KEY.USER, data);
|
||||
wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus);
|
||||
|
||||
// 转换菜单格式
|
||||
|
||||
return data;
|
||||
} catch (_error) {
|
||||
history.push(loginPath);
|
||||
@@ -51,12 +61,17 @@ export async function getInitialState(): Promise<{
|
||||
};
|
||||
// 如果不是登录页面,执行
|
||||
const { location } = history;
|
||||
|
||||
if (
|
||||
![loginPath, "/user/register", "/user/register-result"].includes(
|
||||
location.pathname
|
||||
)
|
||||
) {
|
||||
const currentUser = await fetchUserInfo();
|
||||
const currentUser = wsCache.get(CACHE_KEY.USER);
|
||||
if (getAccessToken() && !currentUser) {
|
||||
fetchUserInfo();
|
||||
}
|
||||
|
||||
return {
|
||||
fetchUserInfo,
|
||||
currentUser,
|
||||
@@ -79,6 +94,10 @@ export const layout: RunTimeLayoutConfig = ({
|
||||
<Question key="doc" />,
|
||||
<SelectLang key="SelectLang" />,
|
||||
],
|
||||
menu: {
|
||||
locale: false,
|
||||
// 关闭国际化-
|
||||
},
|
||||
avatarProps: {
|
||||
src: initialState?.currentUser?.user.avatar,
|
||||
title: <AvatarName />,
|
||||
@@ -117,17 +136,9 @@ export const layout: RunTimeLayoutConfig = ({
|
||||
width: "331px",
|
||||
},
|
||||
],
|
||||
links: isDevOrTest
|
||||
? [
|
||||
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
|
||||
<LinkOutlined />
|
||||
<span>OpenAPI 文档</span>
|
||||
</Link>,
|
||||
]
|
||||
: [],
|
||||
menuHeaderRender: undefined,
|
||||
// 自定义 403 页面
|
||||
// unAccessible: <div>unAccessible</div>,
|
||||
unAccessible: <div>unAccessible</div>,
|
||||
// 增加一个 loading 的状态
|
||||
childrenRender: (children) => {
|
||||
// if (initialState?.loading) return <PageLoading />;
|
||||
@@ -187,3 +198,65 @@ export const request: RequestConfig = {
|
||||
},
|
||||
],
|
||||
};
|
||||
// umi 4 使用 modifyRoutes
|
||||
export function patchClientRoutes({ routes }: { routes: any }) {
|
||||
const { wsCache } = useCache();
|
||||
const globalMenus = wsCache.get(CACHE_KEY.ROLE_ROUTERS);
|
||||
const routerIndex = routes.findIndex((item: any) => item.path === "/");
|
||||
const parentId = routes[routerIndex].id;
|
||||
|
||||
if (globalMenus) {
|
||||
routes[routerIndex]["routes"].push(...loopMenuItem(globalMenus, parentId));
|
||||
}
|
||||
}
|
||||
|
||||
const loopMenuItem = (menus: any[], pId: number | string): any[] => {
|
||||
return menus.flatMap((item) => {
|
||||
let Component: React.ComponentType<any> | null = null;
|
||||
if (item.component && item.component.length > 0) {
|
||||
// 防止配置了路由,但本地暂未添加对应的页面,产生的错误
|
||||
console.log(item.component);
|
||||
Component = React.lazy(() => {
|
||||
const importComponent = () => import(`@/pages/${item.component}`);
|
||||
const import404 = () => import("@/pages/404");
|
||||
return importComponent().catch(import404);
|
||||
});
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
return [
|
||||
{
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
id: item.id,
|
||||
parentId: pId,
|
||||
children: [
|
||||
{
|
||||
path: item.url,
|
||||
element: <Navigate to={item.children[0].url} replace />,
|
||||
},
|
||||
...loopMenuItem(item.children, item.menuID),
|
||||
],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
id: item.menuID,
|
||||
parentId: pId,
|
||||
element: (
|
||||
<React.Suspense
|
||||
fallback={<Spin style={{ width: "100%", height: "100%" }} />}
|
||||
>
|
||||
{Component && <Component />}
|
||||
</React.Suspense>
|
||||
),
|
||||
children: [], // 添加缺失的 children 属性
|
||||
},
|
||||
];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user