menu路由构建优化
This commit is contained in:
@@ -23,6 +23,9 @@ export interface SysMenu extends BaseDTO {
|
||||
url?: string;
|
||||
/** 菜单组件 */
|
||||
component?: string;
|
||||
/** 菜单布局 */
|
||||
layout?: string;
|
||||
/** 菜单布局 */
|
||||
/** 菜单图标 */
|
||||
icon?: string;
|
||||
/** 菜单顺序 */
|
||||
|
||||
@@ -83,16 +83,21 @@ function generateRouteFromMenu(menu: SysMenu, isTopLevel = true): RouteRecordRaw
|
||||
|
||||
// 如果有子菜单,使用布局组件
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
// 如果是顶层的NAVIGATION类型菜单,使用NavigationLayout
|
||||
if (isTopLevel && menu.type === MenuType.NAVIGATION) {
|
||||
route.component = getComponent(menu.component || 'NavigationLayout');
|
||||
} else if (menu.type === MenuType.SIDEBAR) {
|
||||
// SIDEBAR类型的菜单使用BlankLayout,避免嵌套布局
|
||||
// BlankLayout 只是一个纯容器,不会添加额外的导航栏或面包屑
|
||||
route.component = getComponent(menu.component || 'BlankLayout');
|
||||
// 根据layout字段选择布局
|
||||
const layout = (menu as any).layout || menu.component;
|
||||
|
||||
if (layout) {
|
||||
// 如果指定了layout,使用指定的布局
|
||||
route.component = getComponent(layout);
|
||||
} else {
|
||||
// 其他情况使用BasicLayout
|
||||
route.component = getComponent(menu.component || 'BasicLayout');
|
||||
// 根据菜单类型选择默认布局
|
||||
if (isTopLevel && menu.type === MenuType.NAVIGATION) {
|
||||
route.component = getComponent('NavigationLayout');
|
||||
} else if (menu.type === MenuType.SIDEBAR) {
|
||||
route.component = getComponent('BlankLayout');
|
||||
} else {
|
||||
route.component = getComponent('BasicLayout');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有子菜单,使用具体的页面组件
|
||||
@@ -277,6 +282,7 @@ export function buildMenuTree(menus: SysMenu[]): SysMenu[] {
|
||||
|
||||
const menuMap = new Map<string, SysMenu>();
|
||||
const rootMenus: SysMenu[] = [];
|
||||
const maxDepth = allMenus.length; // 最多遍历len层
|
||||
|
||||
// 创建菜单映射
|
||||
allMenus.forEach(menu => {
|
||||
@@ -285,23 +291,47 @@ export function buildMenuTree(menus: SysMenu[]): SysMenu[] {
|
||||
}
|
||||
});
|
||||
|
||||
// 构建树结构
|
||||
allMenus.forEach(menu => {
|
||||
const menuNode = menuMap.get(menu.menuID!);
|
||||
if (!menuNode) return;
|
||||
// 循环构建树结构,最多遍历maxDepth次
|
||||
for (let depth = 0; depth < maxDepth; depth++) {
|
||||
let hasChanges = false;
|
||||
|
||||
if (!menu.parentID || menu.parentID === '0') {
|
||||
// 根菜单
|
||||
rootMenus.push(menuNode);
|
||||
} else {
|
||||
// 子菜单
|
||||
const parent = menuMap.get(menu.parentID);
|
||||
if (parent) {
|
||||
parent.children = parent.children || [];
|
||||
parent.children.push(menuNode);
|
||||
allMenus.forEach(menu => {
|
||||
if (!menu.menuID) return;
|
||||
|
||||
const menuNode = menuMap.get(menu.menuID);
|
||||
if (!menuNode) return;
|
||||
|
||||
// 如果节点已经在树中,跳过
|
||||
if (isNodeInTree(menuNode, rootMenus)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!menu.parentID || menu.parentID === '0' || menu.parentID === '') {
|
||||
// 根菜单
|
||||
if (!isNodeInTree(menuNode, rootMenus)) {
|
||||
rootMenus.push(menuNode);
|
||||
hasChanges = true;
|
||||
}
|
||||
} else {
|
||||
// 子菜单
|
||||
const parent = menuMap.get(menu.parentID);
|
||||
if (parent && isNodeInTree(parent, rootMenus)) {
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
if (!parent.children.includes(menuNode)) {
|
||||
parent.children.push(menuNode);
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有变化,说明树构建完成
|
||||
if (!hasChanges) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 按orderNum排序
|
||||
const sortMenus = (menus: SysMenu[]): SysMenu[] => {
|
||||
@@ -316,6 +346,19 @@ export function buildMenuTree(menus: SysMenu[]): SysMenu[] {
|
||||
return sortMenus(rootMenus);
|
||||
}
|
||||
|
||||
// 检查节点是否已经在树中
|
||||
function isNodeInTree(node: SysMenu, tree: SysMenu[]): boolean {
|
||||
for (const treeNode of tree) {
|
||||
if (treeNode.menuID === node.menuID) {
|
||||
return true;
|
||||
}
|
||||
if (treeNode.children && isNodeInTree(node, treeNode.children)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据权限过滤菜单
|
||||
* @param menus 菜单列表
|
||||
|
||||
@@ -271,32 +271,62 @@ async function loadDeptList() {
|
||||
|
||||
// 将扁平数据转换为树形结构
|
||||
function buildTree(flatData: SysDept[]): SysDept[] {
|
||||
if (!flatData || flatData.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const tree: SysDept[] = [];
|
||||
const map: Record<string, SysDept> = {};
|
||||
const map = new Map<string, SysDept>();
|
||||
const maxDepth = flatData.length; // 最多遍历len层
|
||||
|
||||
// 创建映射表
|
||||
// 初始化所有节点
|
||||
flatData.forEach(item => {
|
||||
if (item.deptID) {
|
||||
map[item.deptID] = { ...item, children: [] };
|
||||
map.set(item.deptID, { ...item, children: [] });
|
||||
}
|
||||
});
|
||||
|
||||
// 构建树形结构
|
||||
flatData.forEach(item => {
|
||||
if (item.deptID) {
|
||||
const node = map[item.deptID];
|
||||
if (item.parentID && map[item.parentID]) {
|
||||
// 有父节点,添加到父节点的children中
|
||||
if (!map[item.parentID].children) {
|
||||
map[item.parentID].children = [];
|
||||
}
|
||||
map[item.parentID].children!.push(node);
|
||||
} else {
|
||||
// 没有父节点或父节点不存在,作为根节点
|
||||
tree.push(node);
|
||||
// 循环构建树结构,最多遍历maxDepth次
|
||||
for (let depth = 0; depth < maxDepth; depth++) {
|
||||
let hasChanges = false;
|
||||
|
||||
flatData.forEach(item => {
|
||||
if (!item.deptID) return;
|
||||
|
||||
const node = map.get(item.deptID);
|
||||
if (!node) return;
|
||||
|
||||
// 如果节点已经在树中,跳过
|
||||
if (isNodeInTree(node, tree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.parentID || item.parentID === '0' || item.parentID === '') {
|
||||
// 根节点
|
||||
if (!isNodeInTree(node, tree)) {
|
||||
tree.push(node);
|
||||
hasChanges = true;
|
||||
}
|
||||
} else {
|
||||
// 查找父节点
|
||||
const parent = map.get(item.parentID);
|
||||
if (parent && isNodeInTree(parent, tree)) {
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
if (!parent.children.includes(node)) {
|
||||
parent.children.push(node);
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有变化,说明树构建完成
|
||||
if (!hasChanges) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清理空的children数组
|
||||
function cleanEmptyChildren(nodes: SysDept[]) {
|
||||
@@ -313,6 +343,19 @@ function buildTree(flatData: SysDept[]): SysDept[] {
|
||||
return tree;
|
||||
}
|
||||
|
||||
// 检查节点是否已经在树中
|
||||
function isNodeInTree(node: SysDept, tree: SysDept[]): boolean {
|
||||
for (const treeNode of tree) {
|
||||
if (treeNode.deptID === node.deptID) {
|
||||
return true;
|
||||
}
|
||||
if (treeNode.children && isNodeInTree(node, treeNode.children)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增部门
|
||||
function handleAdd() {
|
||||
isEdit.value = false;
|
||||
|
||||
@@ -347,32 +347,62 @@ async function loadMenuList() {
|
||||
|
||||
// 将扁平数据转换为树形结构
|
||||
function buildTree(flatData: SysMenu[]): SysMenu[] {
|
||||
if (!flatData || flatData.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const tree: SysMenu[] = [];
|
||||
const map: Record<string, SysMenu> = {};
|
||||
const map = new Map<string, SysMenu>();
|
||||
const maxDepth = flatData.length; // 最多遍历len层
|
||||
|
||||
// 创建映射表
|
||||
// 初始化所有节点
|
||||
flatData.forEach(item => {
|
||||
if (item.menuID) {
|
||||
map[item.menuID] = { ...item, children: [] };
|
||||
map.set(item.menuID, { ...item, children: [] });
|
||||
}
|
||||
});
|
||||
|
||||
// 构建树形结构
|
||||
flatData.forEach(item => {
|
||||
if (item.menuID) {
|
||||
const node = map[item.menuID];
|
||||
if (item.parentID && map[item.parentID]) {
|
||||
// 有父节点,添加到父节点的children中
|
||||
if (!map[item.parentID].children) {
|
||||
map[item.parentID].children = [];
|
||||
}
|
||||
map[item.parentID].children!.push(node);
|
||||
} else {
|
||||
// 没有父节点或父节点不存在,作为根节点
|
||||
tree.push(node);
|
||||
// 循环构建树结构,最多遍历maxDepth次
|
||||
for (let depth = 0; depth < maxDepth; depth++) {
|
||||
let hasChanges = false;
|
||||
|
||||
flatData.forEach(item => {
|
||||
if (!item.menuID) return;
|
||||
|
||||
const node = map.get(item.menuID);
|
||||
if (!node) return;
|
||||
|
||||
// 如果节点已经在树中,跳过
|
||||
if (isNodeInTree(node, tree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.parentID || item.parentID === '0' || item.parentID === '') {
|
||||
// 根节点
|
||||
if (!isNodeInTree(node, tree)) {
|
||||
tree.push(node);
|
||||
hasChanges = true;
|
||||
}
|
||||
} else {
|
||||
// 查找父节点
|
||||
const parent = map.get(item.parentID);
|
||||
if (parent && isNodeInTree(parent, tree)) {
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
if (!parent.children.includes(node)) {
|
||||
parent.children.push(node);
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有变化,说明树构建完成
|
||||
if (!hasChanges) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清理空的children数组
|
||||
function cleanEmptyChildren(nodes: SysMenu[]) {
|
||||
@@ -389,6 +419,19 @@ function buildTree(flatData: SysMenu[]): SysMenu[] {
|
||||
return tree;
|
||||
}
|
||||
|
||||
// 检查节点是否已经在树中
|
||||
function isNodeInTree(node: SysMenu, tree: SysMenu[]): boolean {
|
||||
for (const treeNode of tree) {
|
||||
if (treeNode.menuID === node.menuID) {
|
||||
return true;
|
||||
}
|
||||
if (treeNode.children && isNodeInTree(node, treeNode.children)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增菜单
|
||||
function handleAdd() {
|
||||
isEdit.value = false;
|
||||
|
||||
Reference in New Issue
Block a user