布局
import { ProLayoutProps } from "@ant-design/pro-components";
/**
* @name
*/
const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
navTheme: "light",
// 拂晓蓝
colorPrimary: "#1890ff",
layout: "mix",
contentWidth: "Fluid",
fixedHeader: false,
fixSiderbar: true,
colorWeak: false,
title: "Ant Design Pro",
pwa: true,
logo: "https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg",
iconfontUrl: "",
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
},
};
export default Settings;
文件目录
目录结构
数据来源参考 Ant Design Pro
├── config # umi 配置,包含路由,构建等配置
├── mock # 本地模拟数据
├── public
│ └── favicon.png # Favicon
├── src
│ ├── assets # 本地静态资源
│ ├── components # 业务通用组件
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # 全局 dva model
│ ├── pages # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── locales # 国际化资源
│ ├── global.less # 全局样式
│ └── global.ts # 全局 JS
├── tests # 测试工具
├── README.md
└── package.json
页面目录结构
src
├── components
└── pages
├── Welcome // 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
| ├── components // 对于复杂的页面可以再自己做更深层次的组织,但建议不要超过三层
| ├── Form.tsx
| ├── index.tsx // 页面组件的代码
| └── index.less // 页面样式
├── Order // 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
| ├── index.tsx
| └── index.less
├── user // 一系列页面推荐通过小写的单一字母做 group 目录
| ├── components // group 下公用的组件集合
| ├── Login // group 下的页面 Login
| ├── Register // group 下的页面 Register
| └── util.ts // 这里可以有一些共用方法之类,不做推荐和约束,看业务场景自行做组织
└── \* // 其它页面组件代码
APP.ts 配置
数据请求
动态路由
路由配置
关于什么是动态路由
与动态菜单
的区别
简单来说
动态路由就是控制页面访问的链接,当链接不存在时直接 404,可以很好的控制用户权限问题
动态菜单就是在已有的路由基础上控制哪个菜单渲染到页面上显示,没有显示的菜单依然可以访问,需要通过权限判断来控制页面要不要显示 403
当然了这两者使用其一就可以很好的控制菜单权限,当是也可以结合起来使用,效果也不错。
动态路由方案
app.ts
let extraRoutes: any; //存储服务器路由
/**需要在这里修改路由,直接操作routes就好不需要返回 */
export async function patchClientRoutes({ routes }: any) {
// element为路由对应组件,需要通过require()来加载或者import() 注意import是异步加载的
extraRoutes.children[1].element =
// 在require动态加载时不能直接将完整路径传进去需要使用拼接的方式也就是./pages必须拼接在外面,
// 因为如果写全部路径时打包工具会识别不了
require(`./pages/${extraRoutes.children[1].component}`).default();
// 为什么要加到path:'/'的路由下才起作用 不清楚可以打印看看
routes[2].children.push(extraRoutes);
console.log(extraRoutes.children[1].component);
}
export async function render(oldRender: any) {
// getRoutes 请求路由
await getRoutes({ userId: "001" })
.then((res) => {
extraRoutes = res;
oldRender();
})
.catch((rej) => {
console.log(rej, "rej");
});
}
请求 mock
export default {
"POST /api/myroutes": async (req: ReqRoutes, res: Response) => {
const { userId } = req;
res.send({
name: "系统管理",
path: "/system",
// 权限配置
access: "canUser",
children: [
{
path: "/system",
redirect: "/system/menu",
},
{
// 如果不返回name菜单不会渲染,但是还可以访问
name: "菜单配置",
path: "/system/menu",
component: "SystemManage/MenuConfigure",
},
],
});
},
};
请求 API
/** 获取路由 POST /api/myroutes */
export async function getRoutes(
body: API.Routes,
options?: { [key: string]: any }
) {
return request<Record<string, any>>("/api/myroutes", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
data: body,
...(options || {}),
});
}
动态菜单方案
1、动态菜单需要提前配置好路由,不管是本地配好,还是通过服务器请求
2、在 app.ts 中配置以下文件
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({
initialState,
setInitialState,
}) => {
return {
menu: {
// 请求参数 当参数改变时会重新执行请求
params: {
userId: initialState?.currentUser?.userid,
},
request: async (params, defaultMenuData) => {
const response = await fetch("/api/menu", {
method: "POST",
body: JSON.stringify(params),
headers: {
"Content-Type": "application/json",
},
});
const menuData = await response.json();
return menuData;
},
locale: true, // 将 locale 设置为 true
},
};
};