239 lines
5.9 KiB
Java
239 lines
5.9 KiB
Java
import memoizeOne from 'memoize-one';
|
||
import isEqual from 'lodash/isEqual';
|
||
import { formatMessage } from 'umi/locale';
|
||
import Authorized from '@/utils/Authorized';
|
||
import { menu } from '../defaultSettings';
|
||
import { getAdminMenus, getAdminUrls } from '../services/admin';
|
||
|
||
const { check } = Authorized;
|
||
|
||
// Conversion router to menu.
|
||
function formatter(data, parentAuthority, parentName) {
|
||
return data
|
||
.map(item => {
|
||
if (!item.name || !item.path) {
|
||
return null;
|
||
}
|
||
|
||
let locale = 'menu';
|
||
if (parentName) {
|
||
locale = `${parentName}.${item.name}`;
|
||
} else {
|
||
locale = `menu.${item.name}`;
|
||
}
|
||
// if enableMenuLocale use item.name,
|
||
// close menu international
|
||
const name = menu.disableLocal
|
||
? item.name
|
||
: formatMessage({ id: locale, defaultMessage: item.name });
|
||
const result = {
|
||
...item,
|
||
name,
|
||
locale,
|
||
authority: item.authority || parentAuthority,
|
||
};
|
||
if (item.routes) {
|
||
const children = formatter(item.routes, item.authority, locale);
|
||
// Reduce memory usage
|
||
result.children = children;
|
||
}
|
||
delete result.routes;
|
||
return result;
|
||
})
|
||
.filter(item => item);
|
||
}
|
||
|
||
const memoizeOneFormatter = memoizeOne(formatter, isEqual);
|
||
|
||
/**
|
||
* get SubMenu or Item
|
||
*/
|
||
const getSubMenu = item => {
|
||
// doc: add hideChildrenInMenu
|
||
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
|
||
return {
|
||
...item,
|
||
children: filterMenuData(item.children), // eslint-disable-line
|
||
};
|
||
}
|
||
return item;
|
||
};
|
||
|
||
/**
|
||
* filter menuData
|
||
*/
|
||
const filterMenuData = menuData => {
|
||
if (!menuData) {
|
||
return [];
|
||
}
|
||
return menuData
|
||
.filter(item => item.name && !item.hideInMenu)
|
||
.map(item => check(item.authority, getSubMenu(item)))
|
||
.filter(item => item);
|
||
};
|
||
|
||
// 用于生成uuid
|
||
function S4() {
|
||
return ((1 + Math.random()) * 0x10000 || 0).toString(16).substring(1);
|
||
}
|
||
function guid() {
|
||
return S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4();
|
||
}
|
||
|
||
const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => {
|
||
let res;
|
||
for (let i = 0; i < antDataMenus.length; i += 1) {
|
||
const antDataMenu = antDataMenus[i];
|
||
if (antDataMenu.path === requestDataMenu.handler) {
|
||
res = rootAntDataMenu;
|
||
break;
|
||
}
|
||
if (antDataMenu.children) {
|
||
res = findRootMenu(antDataMenu.children, antDataMenu, requestDataMenu);
|
||
break;
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
|
||
const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => {
|
||
return requestDataMenus.map(item => {
|
||
if (!item.handler) {
|
||
// root 节点
|
||
const uuid = `sms${guid()}`;
|
||
const res = {
|
||
icon: 'user',
|
||
name: item.displayName,
|
||
path: uuid,
|
||
};
|
||
|
||
// 子节点
|
||
if (item.children) {
|
||
// 通过子节点找到对于的父节点,设置 path,没有则是 uuid
|
||
const rootMenu = findRootMenu(antMenuData, {}, item.children[0]);
|
||
if (rootMenu) {
|
||
res.path = rootMenu.path;
|
||
}
|
||
|
||
// 开始递归构建数据结构
|
||
const childrenMenus = buildTreeMenu(antMenuData, moveChildrenMenusData, item.children);
|
||
res.children = childrenMenus;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
// moveChildrenMenusData 是一个 map,对比 url 地址是否存在,不存在就给一个 404 的页面
|
||
const handleMapperData = moveChildrenMenusData[item.handler];
|
||
if (handleMapperData) {
|
||
return {
|
||
...handleMapperData,
|
||
icon: 'user',
|
||
name: item.displayName,
|
||
path: item.handler,
|
||
};
|
||
}
|
||
|
||
// 没有就返回404页面
|
||
return moveChildrenMenusData['/exception/404'];
|
||
});
|
||
};
|
||
|
||
const moveChildrenMenus = antDataMenus => {
|
||
let res = {};
|
||
for (let i = 0; i < antDataMenus.length; i += 1) {
|
||
const antDataMenu = antDataMenus[i];
|
||
res[antDataMenu.path] = {
|
||
...res,
|
||
...antDataMenu,
|
||
};
|
||
|
||
if (antDataMenu.children) {
|
||
const childrenMenus = moveChildrenMenus(antDataMenu.children);
|
||
res = {
|
||
...res,
|
||
...childrenMenus,
|
||
};
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
|
||
/**
|
||
* 获取面包屑映射
|
||
* @param {Object} menuData 菜单配置
|
||
*/
|
||
const getBreadcrumbNameMap = menuData => {
|
||
const routerMap = {};
|
||
|
||
const flattenMenuData = data => {
|
||
data.forEach(menuItem => {
|
||
if (menuItem.children) {
|
||
flattenMenuData(menuItem.children);
|
||
}
|
||
// Reduce memory usage
|
||
routerMap[menuItem.path] = menuItem;
|
||
});
|
||
};
|
||
flattenMenuData(menuData);
|
||
return routerMap;
|
||
};
|
||
|
||
const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
|
||
|
||
export default {
|
||
namespace: 'menu',
|
||
|
||
state: {
|
||
menuData: [],
|
||
urlsData: {},
|
||
breadcrumbNameMap: {},
|
||
},
|
||
|
||
effects: {
|
||
*getMenuData({ payload }, { put, call }) {
|
||
const { data } = yield call(getAdminMenus);
|
||
const { routes, authority } = payload;
|
||
|
||
// authority 已经不适用
|
||
const antMenuData = filterMenuData(memoizeOneFormatter(routes, authority));
|
||
let menuData = antMenuData;
|
||
// const resultMenuData = data;
|
||
if (data !== 'all') {
|
||
const moveChildrenMenusData = moveChildrenMenus(antMenuData);
|
||
const buildTreeMenuData = buildTreeMenu(antMenuData, moveChildrenMenusData, data);
|
||
menuData = buildTreeMenuData;
|
||
}
|
||
|
||
// 生成 menu 和 router mapping
|
||
const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(menuData);
|
||
yield put({
|
||
type: 'save',
|
||
payload: { menuData, breadcrumbNameMap },
|
||
});
|
||
},
|
||
*getUrlsData(state, { put, call }) {
|
||
const { data } = yield call(getAdminUrls);
|
||
|
||
// 构建 {'/user': true} 这种 map 结构方便取数据、
|
||
const urlsData = {};
|
||
data.forEach(item => {
|
||
urlsData[item] = true;
|
||
});
|
||
|
||
yield put({
|
||
type: 'save',
|
||
payload: { urlsData },
|
||
});
|
||
},
|
||
},
|
||
|
||
reducers: {
|
||
save(state, { payload }) {
|
||
return {
|
||
...state,
|
||
...payload,
|
||
};
|
||
},
|
||
},
|
||
};
|