app.tsx RunTimeLayoutConfig 运行时配置
关键代码1:值为后台获取的真实菜单及路由信息 initialState?.currentUser?.menus 为项目登录初始化后设置的菜单,此处可以在getInitialState 中进行设置,对后台的菜单进行处理,转换为antd 的格式
menuDataRender: () =>initialState?.currentUser?.menus,
关键代码2: routes.ts 一定要设置好路由和组件对应关系,不然就算获取到路由,访问的时候组件也是404页面, hideInMenu为true, 隐藏目录,通过后台获取菜单及路由
{
name: 'Home1',
icon: 'smile',
hidden: false,
hideInMenu: false,
path: '/Numbers',
// component: BasicLayout,
// layout: true,
// redirect: '/Numbers/NumbersModel',
routes: [
{
name: 'home',
icon: 'smile',
hidden: false,
hideInMenu: false,
path: '/Numbers/NumbersModel',
component: './Numbers/NumbersModel',
},
],
},
一级菜单icon实现代码
// 封装处理一级菜单方法
mport type { MenuDataItem } from '@ant-design/pro-layout';
import { createFromIconfontCN, SmileOutlined, HeartOutlined, BugOutlined } from '@ant-design/icons';
// 引入多个iconfot, 本地及远程
const IconFont = createFromIconfontCN({
scriptUrl: [
require('../../assets/iconfont/iconfont.js'),
'//at.alicdn.com/t/font_xxxx.js',
],
});
const IconMap = {
smile: <SmileOutlined />,
heart: <HeartOutlined />,
index: <IconFont type="icon-index" style={{ color: '#08c' }} />,
basic: <IconFont type="icon-basic" />,
bug: <BugOutlined />,
clockorder2: <IconFont type="icon-clockorder2" />,
report2: <IconFont type="icon-report2" />,
map: <IconFont type="icon-map" />,
data: <IconFont type="icon-data" />,
dict: <IconFont type="icon-dict" />,
}
export const loopMenuItem = (menus: MenuDataItem[]): MenuDataItem[] =>
menus.map(({ icon, routes, ...item }) => ({
...item,
icon: icon && IconMap[icon as string],
routes: routes && loopMenuItem(routes), //递归调用
}));
二级菜单icon 实现逻辑
menuItemRender: (menuItemProps, defaultDom) => {
if (menuItemProps.isUrl || !menuItemProps.path) {
return defaultDom;
}
return (
<Link to={menuItemProps.path} >
{menuItemProps.pro_layout_parentKeys && menuItemProps.pro_layout_parentKeys.length > 0 && menuItemProps.icon}
{defaultDom}
</Link>
)
},
附1:RunTimeLayoutConfig配置
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
console.log('initialState', initialState);
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
waterMarkProps: {
content: initialState?.currentUser?.name
},
footerRender: () => <Footer />,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
},
links: isDev
? [
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined />
<span>OpenAPI 文档</span>
</Link>,
<Link to="/~docs" key="docs">
<BookOutlined />
<span>业务组件文档</span>
</Link>,
]
: [],
menuHeaderRender: undefined,
menuDataRender: () => initialState?.currentUser?.menus,
// menu: () => loopMenuItem(initialState?.currentUser?.menus),
// 二级icon
menuItemRender: (menuItemProps, defaultDom) => {
if (menuItemProps.isUrl || !menuItemProps.path) {
return defaultDom;
}
return (
<Link to={menuItemProps.path} >
{menuItemProps.pro_layout_parentKeys && menuItemProps.pro_layout_parentKeys.length > 0 && menuItemProps.icon}
{defaultDom}
</Link>
)
},
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children, props) => {
// if (initialState?.loading) return <PageLoading />;
return (
<>
{children}
{!props.location?.pathname?.includes('/login') && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)}
</>
);
},
...initialState?.settings,
};
};
附二:获取菜单和用户信息
// 获取用户及菜单
const fetchUserInfo = async () => {
try {
// const msg = await queryCurrentUser();
let userInfo = {
name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: '00000001',
access: 'user',
};
const msg = await queryCurrentUserInfo();
// 先把菜单处理造出来
const menus = TreeDataTranslate(msg.obj.menus);
const newMenus = fetchRouter(menus, 1);
const fullMenus = routes.concat(newMenus);
const fullIcons = loopMenuItem(fullMenus);
console.log('menus', menus)
console.log('menus1', newMenus)
// console.log('fullMenus', fullMenus)
msg.data = { ...msg.obj, ...userInfo, menus: fullIcons }
// msg.data = { ...msg.obj, ...userInfo }
console.log('userInfo', msg);
return msg.data;
} catch (error) {
history.push(loginPath);
}
return undefined;
};
附三:转换服务端获取的菜单
/**
*
* @param {*} [
{
"id": 301,
"cat": "0",
"code": "userauth", // 路由name
"icon": "role", // 路由图标
"isLeaf": "T",
"isShow": "T", // 是否显示
"name": "用户权限",
"parentId": 0,
"sortOrder": 999
},
{
"id": 302,
"cat": "1",
"code": "user",
"icon": "data",
"isLeaf": "T",
"isShow": "T",
"name": "用户管理",
"parentId": 301, // 父级菜单id
"sortOrder": 999
},
{
"id": 303,
"cat": "1",
"code": "role",
"icon": "data",
"isLeaf": "T",
"isShow": "T",
"name": "角色",
"parentId": 301,
"sortOrder": 999
},
]
* @param {*} id
* @param {*} pid //
* @returns
*/
export function TreeDataTranslate(data, id = 'id', pid = 'parentId') {
let res = [];
let temp = {};
for (let i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i];
}
for (let k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]]['routes']) {
temp[data[k][pid]]['routes'] = [];
}
if (!temp[data[k][pid]]['_level']) {
temp[data[k][pid]]['_level'] = 1;
}
data[k]['_level'] = temp[data[k][pid]]._level + 1;
data[k]['pCode'] = temp[data[k][pid]].code;
temp[data[k][pid]]['routes'].push(data[k]);
} else {
res.push(data[k]);
}
}
return res;
}
export function TreeDataTranslate2(data, level) {
if (data) {
for (let k = 0; k < data.length; k++) {
data[k]['_level'] = level;
if (data[k]['routes'] && data[k]['routes'].length > 0) {
TreeDataTranslate2(data[k]['routes'], level + 1);
}
}
}
}
export function fetchRouter(arr, level) {
let ret = [];
arr.forEach((menu) => {
let item = {};
item.name = menu.code;
item.icon = menu.icon || 'smile';
item.hidden = menu.isShow != 'T';
item.hideInMenu = menu.isShow != 'T';
// item.exact = true;
if (menu.cat == 0) {
item.redirect = 'noredirect';
item.path = '/' + menu.code;
item.component = './' + menu.code
console.log('icon level :>> ', menu.icon, item.icon);
} else {
item.component = './' + menu.pCode + '/' + menu.code
item.path = '/' + menu.pCode + '/' + menu.code;
}
if (menu.routes) {
item.routes = fetchRouter(menu.routes, level + 1);
}
ret.push(item);
});
return ret;
}
参考:antd pro V5从服务端请求菜单
|