feat: 路由登录 动态路由重定向
This commit is contained in:
15
src/app.tsx
15
src/app.tsx
@@ -93,6 +93,7 @@ export const layout: RunTimeLayoutConfig = ({
|
|||||||
initialState,
|
initialState,
|
||||||
setInitialState,
|
setInitialState,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { wsCache } = useCache();
|
||||||
return {
|
return {
|
||||||
actionsRender: () => [
|
actionsRender: () => [
|
||||||
<Question key="doc" />,
|
<Question key="doc" />,
|
||||||
@@ -101,6 +102,18 @@ export const layout: RunTimeLayoutConfig = ({
|
|||||||
menu: {
|
menu: {
|
||||||
locale: false,
|
locale: false,
|
||||||
// 关闭国际化-
|
// 关闭国际化-
|
||||||
|
// request: async () => {
|
||||||
|
// const currentUser = wsCache.get(CACHE_KEY.USER);
|
||||||
|
|
||||||
|
// console.log("菜单请求被调用", initialState?.menus, currentUser);
|
||||||
|
// if (currentUser.menus) {
|
||||||
|
// const menuData = loopMenuItem(currentUser.menus);
|
||||||
|
// // console.log('转换后的菜单数据:', menuData);
|
||||||
|
// // const r = loopMenuItem(currentUser.menus);
|
||||||
|
// return menuData;
|
||||||
|
// }
|
||||||
|
// return [];
|
||||||
|
// },
|
||||||
},
|
},
|
||||||
avatarProps: {
|
avatarProps: {
|
||||||
src: initialState?.currentUser?.user.avatar,
|
src: initialState?.currentUser?.user.avatar,
|
||||||
@@ -238,7 +251,7 @@ export const request: RequestConfig = {
|
|||||||
// Umi 4 支持异步的 patchClientRoutes
|
// Umi 4 支持异步的 patchClientRoutes
|
||||||
export async function patchClientRoutes({ routes }: any) {
|
export async function patchClientRoutes({ routes }: any) {
|
||||||
const { wsCache } = useCache();
|
const { wsCache } = useCache();
|
||||||
|
console.log('patchClientRoutes', patchClientRoutes);
|
||||||
// 先尝试从缓存获取
|
// 先尝试从缓存获取
|
||||||
let menus = wsCache.get(CACHE_KEY.ROLE_ROUTERS);
|
let menus = wsCache.get(CACHE_KEY.ROLE_ROUTERS);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getTenantIdByName, login } from "@/services/login";
|
|
||||||
import {
|
import {
|
||||||
AlipayOutlined,
|
AlipayOutlined,
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
@@ -6,34 +5,36 @@ import {
|
|||||||
TaobaoOutlined,
|
TaobaoOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
WeiboOutlined,
|
WeiboOutlined,
|
||||||
} from "@ant-design/icons";
|
} from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
LoginFormPage,
|
LoginFormPage,
|
||||||
ProConfigProvider,
|
ProConfigProvider,
|
||||||
ProFormCaptcha,
|
ProFormCaptcha,
|
||||||
ProFormCheckbox,
|
ProFormCheckbox,
|
||||||
ProFormText,
|
ProFormText,
|
||||||
} from "@ant-design/pro-components";
|
} from '@ant-design/pro-components';
|
||||||
import { history, useModel, useNavigate } from "@umijs/max";
|
import { history, useModel, useNavigate } from '@umijs/max';
|
||||||
import { Button, Divider, Space, Tabs, theme, message } from "antd";
|
import { Button, Divider, message, Space, Tabs, theme } from 'antd';
|
||||||
import type { CSSProperties } from "react";
|
import type { CSSProperties } from 'react';
|
||||||
import { useState } from "react";
|
import { useState } from 'react';
|
||||||
import * as authUtil from "@/utils/auth";
|
import { flushSync } from 'react-dom';
|
||||||
import { flushSync } from "react-dom";
|
import { getTenantIdByName, login } from '@/services/login';
|
||||||
type LoginType = "phone" | "account";
|
import * as authUtil from '@/utils/auth';
|
||||||
|
|
||||||
|
type LoginType = 'phone' | 'account';
|
||||||
|
|
||||||
const iconStyles: CSSProperties = {
|
const iconStyles: CSSProperties = {
|
||||||
color: "rgba(0, 0, 0, 0.2)",
|
color: 'rgba(0, 0, 0, 0.2)',
|
||||||
fontSize: "18px",
|
fontSize: '18px',
|
||||||
verticalAlign: "middle",
|
verticalAlign: 'middle',
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
const [loginType, setLoginType] = useState<LoginType>("account");
|
const [loginType, setLoginType] = useState<LoginType>('account');
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
const [messageApi, contextHolder] = message.useMessage();
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
const { initialState, setInitialState } = useModel("@@initialState");
|
const { initialState, setInitialState } = useModel('@@initialState');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
// 获取租户 ID
|
// 获取租户 ID
|
||||||
const getTenantId = async (name: string) => {
|
const getTenantId = async (name: string) => {
|
||||||
@@ -57,7 +58,7 @@ const Page = () => {
|
|||||||
try {
|
try {
|
||||||
// 根据登录类型处理不同的参数
|
// 根据登录类型处理不同的参数
|
||||||
const params = {
|
const params = {
|
||||||
tenantName: "芋道源码",
|
tenantName: '芋道源码',
|
||||||
...values,
|
...values,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,21 +72,22 @@ const Page = () => {
|
|||||||
// 调用登录接口
|
// 调用登录接口
|
||||||
const data = await login(params);
|
const data = await login(params);
|
||||||
// 登录成功
|
// 登录成功
|
||||||
messageApi.success("登录成功!");
|
messageApi.success('登录成功!');
|
||||||
// 跳转到首页
|
// 跳转到首页
|
||||||
authUtil.setToken(data);
|
authUtil.setToken(data);
|
||||||
await fetchUserInfo();
|
await fetchUserInfo();
|
||||||
const urlParams = new URL(window.location.href).searchParams;
|
const urlParams = new URL(window.location.href).searchParams;
|
||||||
navigate(urlParams.get("redirect") || "/");
|
// navigate(urlParams.get("redirect") || "/");
|
||||||
|
window.location.href = urlParams.get('redirect') || '/';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messageApi.error("登录失败,请检查网络或稍后重试!");
|
messageApi.error('登录失败,请检查网络或稍后重试!');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "white",
|
backgroundColor: 'white',
|
||||||
height: "100vh",
|
height: '100vh',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@@ -95,8 +97,8 @@ const Page = () => {
|
|||||||
backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr"
|
backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr"
|
||||||
// title="BY"
|
// title="BY"
|
||||||
containerStyle={{
|
containerStyle={{
|
||||||
backgroundColor: "rgb(0 0 0 / 51%)",
|
backgroundColor: 'rgb(0 0 0 / 51%)',
|
||||||
backdropFilter: "blur(4px)",
|
backdropFilter: 'blur(4px)',
|
||||||
}}
|
}}
|
||||||
onFinish={handleSubmit}
|
onFinish={handleSubmit}
|
||||||
subTitle="百业到家云控台"
|
subTitle="百业到家云控台"
|
||||||
@@ -127,17 +129,17 @@ const Page = () => {
|
|||||||
actions={
|
actions={
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Divider plain>
|
<Divider plain>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: token.colorTextPlaceholder,
|
color: token.colorTextPlaceholder,
|
||||||
fontWeight: "normal",
|
fontWeight: 'normal',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -147,48 +149,48 @@ const Page = () => {
|
|||||||
<Space align="center" size={24}>
|
<Space align="center" size={24}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
border: "1px solid " + token.colorPrimaryBorder,
|
border: '1px solid ' + token.colorPrimaryBorder,
|
||||||
background: token.colorBgContainer,
|
background: token.colorBgContainer,
|
||||||
borderRadius: "50%",
|
borderRadius: '50%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AlipayOutlined style={{ ...iconStyles, color: "#1677FF" }} />
|
<AlipayOutlined style={{ ...iconStyles, color: '#1677FF' }} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
border: "1px solid " + token.colorPrimaryBorder,
|
border: '1px solid ' + token.colorPrimaryBorder,
|
||||||
background: token.colorBgContainer,
|
background: token.colorBgContainer,
|
||||||
borderRadius: "50%",
|
borderRadius: '50%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TaobaoOutlined style={{ ...iconStyles, color: "#FF6A10" }} />
|
<TaobaoOutlined style={{ ...iconStyles, color: '#FF6A10' }} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
height: 40,
|
height: 40,
|
||||||
width: 40,
|
width: 40,
|
||||||
background: token.colorBgContainer,
|
background: token.colorBgContainer,
|
||||||
border: "1px solid " + token.colorPrimaryBorder,
|
border: '1px solid ' + token.colorPrimaryBorder,
|
||||||
borderRadius: "50%",
|
borderRadius: '50%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<WeiboOutlined style={{ ...iconStyles, color: "#1890ff" }} />
|
<WeiboOutlined style={{ ...iconStyles, color: '#1890ff' }} />
|
||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,125 +201,125 @@ const Page = () => {
|
|||||||
activeKey={loginType}
|
activeKey={loginType}
|
||||||
onChange={(activeKey) => setLoginType(activeKey as LoginType)}
|
onChange={(activeKey) => setLoginType(activeKey as LoginType)}
|
||||||
>
|
>
|
||||||
<Tabs.TabPane key={"account"} tab={"账号密码登录"} />
|
<Tabs.TabPane key={'account'} tab={'账号密码登录'} />
|
||||||
<Tabs.TabPane key={"phone"} tab={"手机号登录"} />
|
<Tabs.TabPane key={'phone'} tab={'手机号登录'} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{loginType === "account" && (
|
{loginType === 'account' && (
|
||||||
<>
|
<>
|
||||||
<ProFormText
|
<ProFormText
|
||||||
name="username"
|
name="username"
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
size: "large",
|
size: 'large',
|
||||||
prefix: (
|
prefix: (
|
||||||
<UserOutlined
|
<UserOutlined
|
||||||
style={{
|
style={{
|
||||||
color: token.colorText,
|
color: token.colorText,
|
||||||
}}
|
}}
|
||||||
className={"prefixIcon"}
|
className={'prefixIcon'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgb(0 0 0 / 77%)",
|
backgroundColor: 'rgb(0 0 0 / 77%)',
|
||||||
color: "white",
|
color: 'white',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
placeholder={"用户名: admin or user"}
|
placeholder={'用户名: admin or user'}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入用户名!",
|
message: '请输入用户名!',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<ProFormText.Password
|
<ProFormText.Password
|
||||||
name="password"
|
name="password"
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
size: "large",
|
size: 'large',
|
||||||
prefix: (
|
prefix: (
|
||||||
<LockOutlined
|
<LockOutlined
|
||||||
style={{
|
style={{
|
||||||
color: token.colorText,
|
color: token.colorText,
|
||||||
}}
|
}}
|
||||||
className={"prefixIcon"}
|
className={'prefixIcon'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgb(0 0 0 / 77%)",
|
backgroundColor: 'rgb(0 0 0 / 77%)',
|
||||||
color: "white",
|
color: 'white',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
placeholder={"密码: ant.design"}
|
placeholder={'密码: ant.design'}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入密码!",
|
message: '请输入密码!',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{loginType === "phone" && (
|
{loginType === 'phone' && (
|
||||||
<>
|
<>
|
||||||
<ProFormText
|
<ProFormText
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
size: "large",
|
size: 'large',
|
||||||
prefix: (
|
prefix: (
|
||||||
<MobileOutlined
|
<MobileOutlined
|
||||||
style={{
|
style={{
|
||||||
color: token.colorText,
|
color: token.colorText,
|
||||||
}}
|
}}
|
||||||
className={"prefixIcon"}
|
className={'prefixIcon'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "rgb(0 0 0 / 77%)",
|
backgroundColor: 'rgb(0 0 0 / 77%)',
|
||||||
color: "white",
|
color: 'white',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
name="mobile"
|
name="mobile"
|
||||||
placeholder={"手机号"}
|
placeholder={'手机号'}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入手机号!",
|
message: '请输入手机号!',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pattern: /^1\d{10}$/,
|
pattern: /^1\d{10}$/,
|
||||||
message: "手机号格式错误!",
|
message: '手机号格式错误!',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<ProFormCaptcha
|
<ProFormCaptcha
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
size: "large",
|
size: 'large',
|
||||||
prefix: (
|
prefix: (
|
||||||
<LockOutlined
|
<LockOutlined
|
||||||
style={{
|
style={{
|
||||||
color: token.colorText,
|
color: token.colorText,
|
||||||
}}
|
}}
|
||||||
className={"prefixIcon"}
|
className={'prefixIcon'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
captchaProps={{
|
captchaProps={{
|
||||||
size: "large",
|
size: 'large',
|
||||||
}}
|
}}
|
||||||
placeholder={"请输入验证码"}
|
placeholder={'请输入验证码'}
|
||||||
captchaTextRender={(timing, count) => {
|
captchaTextRender={(timing, count) => {
|
||||||
if (timing) {
|
if (timing) {
|
||||||
return `${count} ${"获取验证码"}`;
|
return `${count} ${'获取验证码'}`;
|
||||||
}
|
}
|
||||||
return "获取验证码";
|
return '获取验证码';
|
||||||
}}
|
}}
|
||||||
name="captcha"
|
name="captcha"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入验证码!",
|
message: '请输入验证码!',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onGetCaptcha={async () => {
|
onGetCaptcha={async () => {
|
||||||
message.success("获取验证码成功!验证码为:1234");
|
message.success('获取验证码成功!验证码为:1234');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
@@ -332,7 +334,7 @@ const Page = () => {
|
|||||||
</ProFormCheckbox>
|
</ProFormCheckbox>
|
||||||
<a
|
<a
|
||||||
style={{
|
style={{
|
||||||
float: "right",
|
float: 'right',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
忘记密码
|
忘记密码
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { Spin } from 'antd';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type { MenuVO } from '@/services/system/menu';
|
import type { MenuVO } from '@/services/system/menu';
|
||||||
|
|
||||||
export const loopMenuItem = (menus: MenuVO[], pId: number | string): any[] => {
|
export const loopMenuItem = (
|
||||||
|
menus: MenuVO[],
|
||||||
|
pId: number | string = '/',
|
||||||
|
): any[] => {
|
||||||
return menus.map((item) => {
|
return menus.map((item) => {
|
||||||
let Component: React.ComponentType<any> | null = null;
|
let Component: React.ComponentType<any> | null = null;
|
||||||
if (item.component && item.component.trim().length > 0) {
|
if (item.component && item.component.trim().length > 0) {
|
||||||
@@ -59,113 +62,3 @@ export const loopMenuItem = (menus: MenuVO[], pId: number | string): any[] => {
|
|||||||
return routeItem;
|
return routeItem;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// return menus.flatMap((item) => {
|
|
||||||
// let Component: React.ComponentType<any> | null = null;
|
|
||||||
// if (item.component && item.component.length > 0) {
|
|
||||||
// // 防止配置了路由,但本地暂未添加对应的页面,产生的错误
|
|
||||||
// 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,
|
|
||||||
// hideInMenu: false,
|
|
||||||
// parentId: pId,
|
|
||||||
// id: item.id,
|
|
||||||
// children: [...loopMenuItem(item.children, item.id)], // 添加缺失的 children 属性
|
|
||||||
// },
|
|
||||||
// ];
|
|
||||||
// } else {
|
|
||||||
// return [
|
|
||||||
// {
|
|
||||||
// path: item.path,
|
|
||||||
// name: item.name,
|
|
||||||
// // icon: item.icon,
|
|
||||||
// id: item.id,
|
|
||||||
// parentId: pId,
|
|
||||||
// hideInMenu: !item.visible,
|
|
||||||
// element: (
|
|
||||||
// <React.Suspense
|
|
||||||
// fallback={<Spin style={{ width: "100%", height: "100%" }} />}
|
|
||||||
// >
|
|
||||||
// {Component && <Component />}
|
|
||||||
// </React.Suspense>
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// return [];
|
|
||||||
// };
|
|
||||||
|
|
||||||
// function getFirstLeafPath(menus: any[], parentPath: string): string {
|
|
||||||
// const firstMenu = menus[0];
|
|
||||||
// const currentPath = `${parentPath}/${firstMenu.path}`;
|
|
||||||
// if (firstMenu.children && firstMenu.children.length > 0) {
|
|
||||||
// if (!firstMenu.hideInMenu) {
|
|
||||||
// return getFirstLeafPath(firstMenu.children, currentPath);
|
|
||||||
// } else {
|
|
||||||
// return getFirstLeafPath(firstMenu.children, parentPath);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return currentPath;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// src/utils/route.ts
|
|
||||||
import { lazy } from 'react';
|
|
||||||
|
|
||||||
export interface RouteItem {
|
|
||||||
id: number;
|
|
||||||
parentId: number;
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
component: string | null;
|
|
||||||
componentName: string;
|
|
||||||
icon: string;
|
|
||||||
visible: boolean;
|
|
||||||
keepAlive: boolean;
|
|
||||||
alwaysShow: boolean;
|
|
||||||
children: RouteItem[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换后端路由数据为 Ant Design Pro 路由格式
|
|
||||||
*/
|
|
||||||
export function transformRoutes(routes: MenuVO[]): any[] {
|
|
||||||
return routes
|
|
||||||
.filter((route) => route.visible) // 只显示可见路由
|
|
||||||
.map((route) => {
|
|
||||||
const routeConfig: any = {
|
|
||||||
path: route.path,
|
|
||||||
name: route.name,
|
|
||||||
icon: route.icon || undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理组件
|
|
||||||
if (route.component) {
|
|
||||||
routeConfig.component = lazy(
|
|
||||||
() =>
|
|
||||||
import(`@/pages/${route.component}`).catch(
|
|
||||||
() => import('@/pages/404'),
|
|
||||||
), // 组件不存在时显示404
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理子路由
|
|
||||||
if (route.children && route.children.length > 0) {
|
|
||||||
routeConfig.routes = transformRoutes(route.children);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 隐藏菜单但保留路由
|
|
||||||
if (!route.visible) {
|
|
||||||
routeConfig.hideInMenu = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return routeConfig;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user