151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
|
|
import { metaInfo } from '@/meta';
|
||
|
|
import React from 'react';
|
||
|
|
import { FormattedMessage } from 'react-intl';
|
||
|
|
|
||
|
|
export type MenuItem = {
|
||
|
|
key: string;
|
||
|
|
label: string | React.ReactElement;
|
||
|
|
disabled?: boolean;
|
||
|
|
icon?: React.ReactNode;
|
||
|
|
children?: MenuItem[];
|
||
|
|
_order?: number;
|
||
|
|
};
|
||
|
|
|
||
|
|
const formatDisplayName = (displayName: string) => {
|
||
|
|
// 用 {{xxx}} 包起来的字符串需要处理国际化
|
||
|
|
if (/^{{(.*)}}$/.test(displayName)) {
|
||
|
|
const key = displayName.match(/^{{(.*)}}$/)![1].trim();
|
||
|
|
return <FormattedMessage id={key} />;
|
||
|
|
}
|
||
|
|
|
||
|
|
return displayName;
|
||
|
|
};
|
||
|
|
|
||
|
|
const flatten = (info: Meta[]) => {
|
||
|
|
const result: Meta[] = [];
|
||
|
|
info.forEach((item) => {
|
||
|
|
if (item._children?.length) {
|
||
|
|
result.push(...flatten(item._children));
|
||
|
|
} else {
|
||
|
|
result.push(item);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return result;
|
||
|
|
};
|
||
|
|
|
||
|
|
const deeplySortMenu = (menus: MenuItem[]) => {
|
||
|
|
const newMenus = [...menus];
|
||
|
|
newMenus.sort((a, b) => a._order! - b._order!);
|
||
|
|
newMenus.forEach((menu) => {
|
||
|
|
if (menu.children) {
|
||
|
|
menu.children = deeplySortMenu(menu.children);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return newMenus;
|
||
|
|
};
|
||
|
|
|
||
|
|
const getMenuItems = (): MenuItem[] => {
|
||
|
|
const menus: MenuItem[] = [];
|
||
|
|
const flatMetaInfo = flatten(metaInfo);
|
||
|
|
|
||
|
|
// head
|
||
|
|
flatMetaInfo.forEach((item) => {
|
||
|
|
if (!item.headMenu) return;
|
||
|
|
// 非路由页面头部菜单
|
||
|
|
if (typeof item.headMenu !== 'boolean') {
|
||
|
|
const find = menus.find(
|
||
|
|
(menu) => menu.key === (item.headMenu as any)?.key,
|
||
|
|
);
|
||
|
|
if (!find) {
|
||
|
|
menus.push({
|
||
|
|
key: (item.headMenu as any)?.key,
|
||
|
|
label: formatDisplayName((item.headMenu as any)?.label),
|
||
|
|
_order: (item.headMenu as any)?.order ?? 0,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 路由页面头部菜单
|
||
|
|
if (item.headMenu === true) {
|
||
|
|
menus.push({
|
||
|
|
key: item._fullpath ?? '',
|
||
|
|
label: formatDisplayName(item.displayName ?? ''),
|
||
|
|
_order: item.order ?? 0,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// side
|
||
|
|
flatMetaInfo.forEach((item) => {
|
||
|
|
if (!item.sideMenu) return;
|
||
|
|
|
||
|
|
const head = menus.find((menu) => menu.key === (item.headMenu as any)?.key);
|
||
|
|
if (!head) return;
|
||
|
|
if (!head.children) head.children = [];
|
||
|
|
|
||
|
|
// 非路由页面侧边菜单(分组)
|
||
|
|
if (typeof item.sideMenu !== 'boolean') {
|
||
|
|
const find = head.children.find(
|
||
|
|
(menu) => menu.key === (item.sideMenu as any)?.key,
|
||
|
|
);
|
||
|
|
if (!find) {
|
||
|
|
head.children.push({
|
||
|
|
key: (item.sideMenu as any)?.key,
|
||
|
|
label: formatDisplayName((item.sideMenu as any)?.label),
|
||
|
|
_order: (item.sideMenu as any)?.order,
|
||
|
|
children: [
|
||
|
|
{
|
||
|
|
key: item._fullpath ?? '',
|
||
|
|
label: formatDisplayName(item.displayName ?? ''),
|
||
|
|
_order: item.order ?? 0,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
find.children!.push({
|
||
|
|
key: item._fullpath ?? '',
|
||
|
|
label: formatDisplayName(item.displayName ?? ''),
|
||
|
|
_order: item.order ?? 0,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// 路由页面侧边菜单
|
||
|
|
if (item.sideMenu === true) {
|
||
|
|
head.children.push({
|
||
|
|
key: item._fullpath ?? '',
|
||
|
|
label: formatDisplayName(item.displayName ?? ''),
|
||
|
|
_order: item.order ?? 0,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// sort
|
||
|
|
return deeplySortMenu(menus);
|
||
|
|
};
|
||
|
|
|
||
|
|
export const menuItems = getMenuItems();
|
||
|
|
|
||
|
|
export const findHeadMenuByHeadKey = (headKey) => {
|
||
|
|
return menuItems.find((menu) => menu.key === headKey);
|
||
|
|
};
|
||
|
|
|
||
|
|
export const findHeadMenuBySideKey = (
|
||
|
|
sideKey: string,
|
||
|
|
menus: MenuItem[] = menuItems,
|
||
|
|
): MenuItem | null => {
|
||
|
|
const find = menus.find((menu) =>
|
||
|
|
menu.children?.some(
|
||
|
|
(child) =>
|
||
|
|
child.key === sideKey ||
|
||
|
|
!!findHeadMenuBySideKey(sideKey, menu.children ?? []),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
if (find) return find;
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
export const findFirstSubMenu = (menu: MenuItem): MenuItem | undefined => {
|
||
|
|
if (!menu?.children?.[0]?.children?.length) return menu?.children?.[0];
|
||
|
|
return findFirstSubMenu(menu.children[0]);
|
||
|
|
};
|