feat: 动态路由
This commit is contained in:
@@ -12,13 +12,14 @@ const Settings: ProLayoutProps & {
|
|||||||
colorPrimary: "#1890ff",
|
colorPrimary: "#1890ff",
|
||||||
layout: "mix",
|
layout: "mix",
|
||||||
contentWidth: "Fluid",
|
contentWidth: "Fluid",
|
||||||
fixedHeader: false,
|
fixedHeader: true,
|
||||||
fixSiderbar: true,
|
fixSiderbar: true,
|
||||||
colorWeak: false,
|
colorWeak: false,
|
||||||
title: "tashow - 管理后台",
|
title: "百业到家云控台",
|
||||||
pwa: true,
|
pwa: true,
|
||||||
logo: "https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg",
|
logo: "/logo.svg",
|
||||||
iconfontUrl: "",
|
iconfontUrl: "",
|
||||||
|
splitMenus: true,
|
||||||
token: {
|
token: {
|
||||||
// 参见ts声明,demo 见文档,通过token 修改样式
|
// 参见ts声明,demo 见文档,通过token 修改样式
|
||||||
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
|
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
* @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 <StepBackwardOutlined /> 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 <UserOutlined /> 则取值应为 user 或者 User
|
* @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 <StepBackwardOutlined /> 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 <UserOutlined /> 则取值应为 user 或者 User
|
||||||
* @doc https://umijs.org/docs/guides/routes
|
* @doc https://umijs.org/docs/guides/routes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: "/user",
|
path: "/user",
|
||||||
@@ -28,6 +29,24 @@ export default [
|
|||||||
icon: "smile",
|
icon: "smile",
|
||||||
component: "./Welcome",
|
component: "./Welcome",
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// path: "/system1",
|
||||||
|
// name: "system1",
|
||||||
|
// icon: "smile",
|
||||||
|
// routes: [
|
||||||
|
// {
|
||||||
|
// name: "tenant",
|
||||||
|
// path: "/system1/tenant",
|
||||||
|
// routes: [
|
||||||
|
// {
|
||||||
|
// name: "package",
|
||||||
|
// path: "/system1/tenant/package",
|
||||||
|
// component: "system/tenant/package",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
path: "/admin",
|
path: "/admin",
|
||||||
name: "admin",
|
name: "admin",
|
||||||
@@ -58,6 +77,6 @@ export default [
|
|||||||
{
|
{
|
||||||
component: "404",
|
component: "404",
|
||||||
layout: false,
|
layout: false,
|
||||||
path: "./*",
|
path: "*",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
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 type { Settings as LayoutSettings } from "@ant-design/pro-components";
|
||||||
import { SettingDrawer } from "@ant-design/pro-components";
|
import { SettingDrawer } from "@ant-design/pro-components";
|
||||||
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
||||||
import { history, Link } from "@umijs/max";
|
import { history, Link, Navigate } from "@umijs/max";
|
||||||
import React from "react";
|
|
||||||
import {
|
import {
|
||||||
AvatarDropdown,
|
AvatarDropdown,
|
||||||
AvatarName,
|
AvatarName,
|
||||||
@@ -16,13 +16,20 @@ import type { UserVO, TokenType, UserInfoVO } from "@/services/login/types";
|
|||||||
import defaultSettings from "../config/defaultSettings";
|
import defaultSettings from "../config/defaultSettings";
|
||||||
import { errorConfig } from "./requestErrorConfig";
|
import { errorConfig } from "./requestErrorConfig";
|
||||||
import "@ant-design/v5-patch-for-react-19";
|
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 { 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 isDev = process.env.NODE_ENV === "development";
|
||||||
const isDevOrTest = isDev || process.env.CI;
|
const isDevOrTest = isDev || process.env.CI;
|
||||||
const loginPath = "/user/login";
|
const loginPath = "/user/login";
|
||||||
|
|
||||||
|
// 全局存储菜单数据和路由映射
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
|
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
|
||||||
* */
|
* */
|
||||||
@@ -43,6 +50,9 @@ export async function getInitialState(): Promise<{
|
|||||||
const { data } = await getInfo();
|
const { data } = await getInfo();
|
||||||
wsCache.set(CACHE_KEY.USER, data);
|
wsCache.set(CACHE_KEY.USER, data);
|
||||||
wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus);
|
wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus);
|
||||||
|
|
||||||
|
// 转换菜单格式
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
history.push(loginPath);
|
history.push(loginPath);
|
||||||
@@ -51,12 +61,17 @@ export async function getInitialState(): Promise<{
|
|||||||
};
|
};
|
||||||
// 如果不是登录页面,执行
|
// 如果不是登录页面,执行
|
||||||
const { location } = history;
|
const { location } = history;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
![loginPath, "/user/register", "/user/register-result"].includes(
|
![loginPath, "/user/register", "/user/register-result"].includes(
|
||||||
location.pathname
|
location.pathname
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const currentUser = await fetchUserInfo();
|
const currentUser = wsCache.get(CACHE_KEY.USER);
|
||||||
|
if (getAccessToken() && !currentUser) {
|
||||||
|
fetchUserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fetchUserInfo,
|
fetchUserInfo,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -79,6 +94,10 @@ export const layout: RunTimeLayoutConfig = ({
|
|||||||
<Question key="doc" />,
|
<Question key="doc" />,
|
||||||
<SelectLang key="SelectLang" />,
|
<SelectLang key="SelectLang" />,
|
||||||
],
|
],
|
||||||
|
menu: {
|
||||||
|
locale: false,
|
||||||
|
// 关闭国际化-
|
||||||
|
},
|
||||||
avatarProps: {
|
avatarProps: {
|
||||||
src: initialState?.currentUser?.user.avatar,
|
src: initialState?.currentUser?.user.avatar,
|
||||||
title: <AvatarName />,
|
title: <AvatarName />,
|
||||||
@@ -117,17 +136,9 @@ export const layout: RunTimeLayoutConfig = ({
|
|||||||
width: "331px",
|
width: "331px",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
links: isDevOrTest
|
|
||||||
? [
|
|
||||||
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
|
|
||||||
<LinkOutlined />
|
|
||||||
<span>OpenAPI 文档</span>
|
|
||||||
</Link>,
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
menuHeaderRender: undefined,
|
menuHeaderRender: undefined,
|
||||||
// 自定义 403 页面
|
// 自定义 403 页面
|
||||||
// unAccessible: <div>unAccessible</div>,
|
unAccessible: <div>unAccessible</div>,
|
||||||
// 增加一个 loading 的状态
|
// 增加一个 loading 的状态
|
||||||
childrenRender: (children) => {
|
childrenRender: (children) => {
|
||||||
// if (initialState?.loading) return <PageLoading />;
|
// 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 属性
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ body,
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family:
|
font-family: AlibabaSans, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
AlibabaSans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
|
Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||||
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
}
|
}
|
||||||
|
|
||||||
.colorWeak {
|
.colorWeak {
|
||||||
@@ -55,7 +55,7 @@ body,
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-layout {
|
.ant-layout {
|
||||||
min-height: 100vh;
|
min-height: 100vh !important;
|
||||||
}
|
}
|
||||||
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
|
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
|
||||||
left: unset;
|
left: unset;
|
||||||
|
|||||||
@@ -1,52 +1,53 @@
|
|||||||
export default {
|
export default {
|
||||||
'menu.welcome': '欢迎',
|
"menu.welcome": "欢迎",
|
||||||
'menu.more-blocks': '更多区块',
|
"menu.more-blocks": "更多区块",
|
||||||
'menu.home': '首页',
|
"menu.home": "首页",
|
||||||
'menu.admin': '管理页',
|
"menu.admin": "管理页",
|
||||||
'menu.admin.sub-page': '二级管理页',
|
"menu.admin.sub-page": "二级管理页",
|
||||||
'menu.login': '登录',
|
"menu.login": "登录",
|
||||||
'menu.register': '注册',
|
"menu.register": "注册",
|
||||||
'menu.register-result': '注册结果',
|
"menu.register-result": "注册结果",
|
||||||
'menu.dashboard': 'Dashboard',
|
"menu.dashboard": "Dashboard",
|
||||||
'menu.dashboard.analysis': '分析页',
|
"menu.dashboard.analysis": "分析页",
|
||||||
'menu.dashboard.monitor': '监控页',
|
"menu.dashboard.monitor": "监控页",
|
||||||
'menu.dashboard.workplace': '工作台',
|
"menu.dashboard.workplace": "工作台",
|
||||||
'menu.exception.403': '403',
|
"menu.exception.403": "403",
|
||||||
'menu.exception.404': '404',
|
"menu.exception.404": "404",
|
||||||
'menu.exception.500': '500',
|
"menu.exception.500": "500",
|
||||||
'menu.form': '表单页',
|
"menu.form": "表单页",
|
||||||
'menu.form.basic-form': '基础表单',
|
"menu.form.basic-form": "基础表单",
|
||||||
'menu.form.step-form': '分步表单',
|
"menu.form.step-form": "分步表单",
|
||||||
'menu.form.step-form.info': '分步表单(填写转账信息)',
|
"menu.form.step-form.info": "分步表单(填写转账信息)",
|
||||||
'menu.form.step-form.confirm': '分步表单(确认转账信息)',
|
"menu.form.step-form.confirm": "分步表单(确认转账信息)",
|
||||||
'menu.form.step-form.result': '分步表单(完成)',
|
"menu.form.step-form.result": "分步表单(完成)",
|
||||||
'menu.form.advanced-form': '高级表单',
|
"menu.form.advanced-form": "高级表单",
|
||||||
'menu.list': '列表页',
|
"menu.list": "列表页",
|
||||||
'menu.list.table-list': '查询表格',
|
"menu.list.table-list": "查询表格",
|
||||||
'menu.list.basic-list': '标准列表',
|
"menu.list.basic-list": "标准列表",
|
||||||
'menu.list.card-list': '卡片列表',
|
"menu.list.card-list": "卡片列表",
|
||||||
'menu.list.search-list': '搜索列表',
|
"menu.list.search-list": "搜索列表",
|
||||||
'menu.list.search-list.articles': '搜索列表(文章)',
|
"menu.list.search-list.articles": "搜索列表(文章)",
|
||||||
'menu.list.search-list.projects': '搜索列表(项目)',
|
"menu.list.search-list.projects": "搜索列表(项目)",
|
||||||
'menu.list.search-list.applications': '搜索列表(应用)',
|
"menu.list.search-list.applications": "搜索列表(应用)",
|
||||||
'menu.profile': '详情页',
|
"menu.profile": "详情页",
|
||||||
'menu.profile.basic': '基础详情页',
|
"menu.profile.basic": "基础详情页",
|
||||||
'menu.profile.advanced': '高级详情页',
|
"menu.profile.advanced": "高级详情页",
|
||||||
'menu.result': '结果页',
|
"menu.result": "结果页",
|
||||||
'menu.result.success': '成功页',
|
"menu.result.success": "成功页",
|
||||||
'menu.result.fail': '失败页',
|
"menu.result.fail": "失败页",
|
||||||
'menu.exception': '异常页',
|
"menu.exception": "异常页",
|
||||||
'menu.exception.not-permission': '403',
|
"menu.exception.not-permission": "403",
|
||||||
'menu.exception.not-find': '404',
|
"menu.exception.not-find": "404",
|
||||||
'menu.exception.server-error': '500',
|
"menu.exception.server-error": "500",
|
||||||
'menu.exception.trigger': '触发错误',
|
"menu.exception.trigger": "触发错误",
|
||||||
'menu.account': '个人页',
|
"menu.account": "个人页",
|
||||||
'menu.account.center': '个人中心',
|
"menu.account.center": "个人中心",
|
||||||
'menu.account.settings': '个人设置',
|
"menu.account.settings": "个人设置",
|
||||||
'menu.account.trigger': '触发报错',
|
"menu.account.trigger": "触发报错",
|
||||||
'menu.account.logout': '退出登录',
|
"menu.account.logout": "退出登录",
|
||||||
'menu.editor': '图形编辑器',
|
"menu.editor": "图形编辑器",
|
||||||
'menu.editor.flow': '流程编辑器',
|
"menu.editor.flow": "流程编辑器",
|
||||||
'menu.editor.mind': '脑图编辑器',
|
"menu.editor.mind": "脑图编辑器",
|
||||||
'menu.editor.koni': '拓扑编辑器',
|
"menu.editor.koni": "拓扑编辑器",
|
||||||
|
// 基础设施相关菜单
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { history, useIntl } from '@umijs/max';
|
import { PageContainer } from "@ant-design/pro-components";
|
||||||
import { Button, Card, Result } from 'antd';
|
import { history, useIntl } from "@umijs/max";
|
||||||
import React from 'react';
|
import { Button, Card, Result } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
const NoFoundPage: React.FC = () => (
|
const NoFoundPage: React.FC = () => (
|
||||||
<Card variant="borderless">
|
<Card variant="borderless">
|
||||||
<Result
|
<Result
|
||||||
status="404"
|
status="404"
|
||||||
title="404"
|
title="404"
|
||||||
subTitle={useIntl().formatMessage({ id: 'pages.404.subTitle' })}
|
subTitle={useIntl().formatMessage({ id: "pages.404.subTitle" })}
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" onClick={() => history.push('/')}>
|
<Button type="primary" onClick={() => history.push("/")}>
|
||||||
{useIntl().formatMessage({ id: 'pages.404.buttonText' })}
|
{useIntl().formatMessage({ id: "pages.404.buttonText" })}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
5
src/pages/system/tenant/list/index.tsx
Normal file
5
src/pages/system/tenant/list/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const TenantList = () => {
|
||||||
|
return <div>TenantList</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TenantList;
|
||||||
5
src/pages/system/tenant/package/index.tsx
Normal file
5
src/pages/system/tenant/package/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const TenantPackage = () => {
|
||||||
|
return <div>TenantPackage</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TenantPackage;
|
||||||
@@ -104,7 +104,7 @@ const Page = () => {
|
|||||||
backdropFilter: "blur(4px)",
|
backdropFilter: "blur(4px)",
|
||||||
}}
|
}}
|
||||||
onFinish={handleSubmit}
|
onFinish={handleSubmit}
|
||||||
subTitle="百业到家-管理平台"
|
subTitle="百业到家云控台"
|
||||||
// activityConfig={{
|
// activityConfig={{
|
||||||
// style: {
|
// style: {
|
||||||
// boxShadow: "0px 0px 8px rgba(0, 0, 0, 0.2)",
|
// boxShadow: "0px 0px 8px rgba(0, 0, 0, 0.2)",
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export async function login(
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
export async function getTenantIdByName(
|
export async function getTenantIdByName(
|
||||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|
||||||
params: { name: string },
|
params: { name: string },
|
||||||
options?: { [key: string]: any }
|
options?: { [key: string]: any }
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
import request from '@/config/axios'
|
import { request } from "@umijs/max";
|
||||||
|
|
||||||
// 获得授权信息
|
// 获得授权信息
|
||||||
export const getAuthorize = (clientId: string) => {
|
// export const getAuthorize = (clientId: string) => {
|
||||||
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
|
// return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 发起授权
|
// // 发起授权
|
||||||
export const authorize = (
|
// export const authorize = (
|
||||||
responseType: string,
|
// responseType: string,
|
||||||
clientId: string,
|
// clientId: string,
|
||||||
redirectUri: string,
|
// redirectUri: string,
|
||||||
state: string,
|
// state: string,
|
||||||
autoApprove: boolean,
|
// autoApprove: boolean,
|
||||||
checkedScopes: string[],
|
// checkedScopes: string[],
|
||||||
uncheckedScopes: string[]
|
// uncheckedScopes: string[]
|
||||||
) => {
|
// ) => {
|
||||||
// 构建 scopes
|
// // 构建 scopes
|
||||||
const scopes = {}
|
// const scopes = {}
|
||||||
for (const scope of checkedScopes) {
|
// for (const scope of checkedScopes) {
|
||||||
scopes[scope] = true
|
// scopes[scope] = true
|
||||||
}
|
// }
|
||||||
for (const scope of uncheckedScopes) {
|
// for (const scope of uncheckedScopes) {
|
||||||
scopes[scope] = false
|
// scopes[scope] = false
|
||||||
}
|
// }
|
||||||
// 发起请求
|
// // 发起请求
|
||||||
return request.post({
|
// return request.post({
|
||||||
url: '/system/oauth2/authorize',
|
// url: '/system/oauth2/authorize',
|
||||||
headers: {
|
// headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
// 'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
},
|
// },
|
||||||
params: {
|
// params: {
|
||||||
response_type: responseType,
|
// response_type: responseType,
|
||||||
client_id: clientId,
|
// client_id: clientId,
|
||||||
redirect_uri: redirectUri,
|
// redirect_uri: redirectUri,
|
||||||
state: state,
|
// state: state,
|
||||||
auto_approve: autoApprove,
|
// auto_approve: autoApprove,
|
||||||
scope: JSON.stringify(scopes)
|
// scope: JSON.stringify(scopes)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface MenuVO {
|
|||||||
keepAlive: boolean;
|
keepAlive: boolean;
|
||||||
alwaysShow?: boolean;
|
alwaysShow?: boolean;
|
||||||
createTime: Date;
|
createTime: Date;
|
||||||
|
children?: MenuVO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询菜单(精简)列表
|
// 查询菜单(精简)列表
|
||||||
|
|||||||
97
src/utils/menuUtils.ts
Normal file
97
src/utils/menuUtils.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// src/utils/menuUtils.ts
|
||||||
|
import { MenuVO } from "@/services/system/menu";
|
||||||
|
import type { MenuDataItem } from "@ant-design/pro-components";
|
||||||
|
// src/utils/menuUtils.ts
|
||||||
|
|
||||||
|
// src/utils/menuUtils.ts
|
||||||
|
// src/utils/route.ts
|
||||||
|
export function transformMenuToRoutes(menuData: MenuVO[]): any[] {
|
||||||
|
return menuData.map((item) => ({
|
||||||
|
path: item.path,
|
||||||
|
name: item.name,
|
||||||
|
icon: item.icon,
|
||||||
|
component: item.component,
|
||||||
|
routes: item.children ? transformMenuToRoutes(item.children) : undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/route.ts
|
||||||
|
export function transformBackendMenuToFlatRoutes(menuData: any[]) {
|
||||||
|
const flatRoutes: any[] = [];
|
||||||
|
|
||||||
|
function processMenu(items: any[], parentRouteId = "ant-design-pro-layout") {
|
||||||
|
items.forEach((item) => {
|
||||||
|
const currentRouteId = `route-${item.id}`;
|
||||||
|
|
||||||
|
// 处理路径 - 如果是子路由,需要组合完整路径
|
||||||
|
let fullPath = item.path;
|
||||||
|
if (item.parentId !== 0 && !item.path.startsWith("/")) {
|
||||||
|
// 子路由需要相对路径
|
||||||
|
fullPath = item.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const route: any = {
|
||||||
|
id: currentRouteId,
|
||||||
|
path: fullPath,
|
||||||
|
name: item.name,
|
||||||
|
parentId: parentRouteId,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加图标(如果不是 # 的话)
|
||||||
|
if (item.icon && item.icon !== "#") {
|
||||||
|
route.icon = item.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加组件路径
|
||||||
|
if (item.component) {
|
||||||
|
// 转换组件路径为动态导入格式
|
||||||
|
route.component = item.component;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他属性
|
||||||
|
if (!item.visible) {
|
||||||
|
route.hideInMenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
flatRoutes.push(route);
|
||||||
|
|
||||||
|
// 递归处理子菜单
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
processMenu(item.children, currentRouteId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
processMenu(menuData);
|
||||||
|
return flatRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformMenuData(menuData: any[]) {
|
||||||
|
const transformItem = (item: any, parentPath = "") => {
|
||||||
|
const fullPath = item.path.startsWith("/")
|
||||||
|
? item.path
|
||||||
|
: `${parentPath}/${item.path}`;
|
||||||
|
const result: any = {
|
||||||
|
path: fullPath,
|
||||||
|
name: item.name,
|
||||||
|
key: `${item.id}`,
|
||||||
|
};
|
||||||
|
if (item.icon && item.icon !== "#") {
|
||||||
|
result.icon = item.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.visible) {
|
||||||
|
result.hideInMenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
result.children = item.children.map((child: any) =>
|
||||||
|
transformItem(child, fullPath)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
result;
|
||||||
|
};
|
||||||
|
return menuData.map((item) => transformItem(item));
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user