feat: 菜单管理 菜单配置 修复菜单重复问题
This commit is contained in:
parent
bdc4f065ef
commit
25f4ecdbab
|
@ -21,6 +21,7 @@
|
||||||
@select="onSelect"
|
@select="onSelect"
|
||||||
:selectedKeys="selectedKeys"
|
:selectedKeys="selectedKeys"
|
||||||
@drop="onDrop"
|
@drop="onDrop"
|
||||||
|
@dragend="onDragend"
|
||||||
>
|
>
|
||||||
<template #title="row">
|
<template #title="row">
|
||||||
<div class="tree-content">
|
<div class="tree-content">
|
||||||
|
@ -63,12 +64,12 @@ import {
|
||||||
} from '@/api/initHome';
|
} from '@/api/initHome';
|
||||||
import {
|
import {
|
||||||
filterMenu,
|
filterMenu,
|
||||||
mergeMapToArr,
|
initData,
|
||||||
developArrToMap,
|
|
||||||
drop,
|
drop,
|
||||||
select,
|
select,
|
||||||
getMaxDepth,
|
getMaxDepth,
|
||||||
mergeArr,
|
mergeArr,
|
||||||
|
findAllParentsAndChildren,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import BaseMenu from '@/views/init-home/data/baseMenu';
|
import BaseMenu from '@/views/init-home/data/baseMenu';
|
||||||
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
|
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
|
||||||
|
@ -83,9 +84,9 @@ const selectedKeys: any = ref([]);
|
||||||
const treeData = ref<any>([]);
|
const treeData = ref<any>([]);
|
||||||
const systemMenu: any = ref([]);
|
const systemMenu: any = ref([]);
|
||||||
const baseMenu: any = ref([]);
|
const baseMenu: any = ref([]);
|
||||||
const AllMenu = ref([]);
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const treeDataDropChange = ref(false); // 标记treeData拖拽成功
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
paging: false,
|
paging: false,
|
||||||
|
@ -156,12 +157,31 @@ const onDrop = (info: AntTreeNodeDropEvent) => {
|
||||||
const maxDepth = getMaxDepth(newTreeData);
|
const maxDepth = getMaxDepth(newTreeData);
|
||||||
if (maxDepth > 3) {
|
if (maxDepth > 3) {
|
||||||
onlyMessage('仅支持3级菜单', 'error');
|
onlyMessage('仅支持3级菜单', 'error');
|
||||||
|
treeDataDropChange.value = false;
|
||||||
treeData.value = TreeData;
|
treeData.value = TreeData;
|
||||||
} else {
|
} else {
|
||||||
|
treeDataDropChange.value = true;
|
||||||
treeData.value = newTreeData;
|
treeData.value = newTreeData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDragend = (info: AntTreeNodeDropEvent) => {
|
||||||
|
const { node } = info;
|
||||||
|
const { children } = findAllParentsAndChildren(
|
||||||
|
cloneDeep(treeData.value),
|
||||||
|
node.code,
|
||||||
|
);
|
||||||
|
const cancelKeys = [node.code, ...children];
|
||||||
|
const Keys = new Set(cloneDeep(selectedKeys.value));
|
||||||
|
cancelKeys.forEach((i) => {
|
||||||
|
Keys.has(i) && Keys.delete(i);
|
||||||
|
});
|
||||||
|
//拖拽成功时更新selectedKeys
|
||||||
|
if (treeDataDropChange.value) {
|
||||||
|
selectedKeys.value = [...Keys];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSystemPermission_api().then((resp: any) => {
|
getSystemPermission_api().then((resp: any) => {
|
||||||
baseMenu.value = filterMenu(
|
baseMenu.value = filterMenu(
|
||||||
|
@ -178,13 +198,16 @@ onMounted(() => {
|
||||||
].includes(item.code),
|
].includes(item.code),
|
||||||
);
|
);
|
||||||
//初始化菜单
|
//初始化菜单
|
||||||
const baseMenuData = developArrToMap(baseMenu.value);
|
initData(baseMenu.value); // 不要克隆,通过引用 处理key和name
|
||||||
const systemMenuData = developArrToMap(systemMenu.value, true);
|
const systemMenuData = initData(systemMenu.value);
|
||||||
selectedKeys.value = systemMenuData.checkedKeys;
|
selectedKeys.value = systemMenuData.checkedKeys;
|
||||||
// AllMenu.value = mergeMapToArr(baseMenuData, systemMenuData);
|
|
||||||
AllMenu.value = mergeArr(cloneDeep(BaseMenu), systemMenu.value);
|
|
||||||
|
|
||||||
treeData.value = cloneDeep(AllMenu.value);
|
const AllMenu = mergeArr(
|
||||||
|
cloneDeep(BaseMenu),
|
||||||
|
cloneDeep(systemMenu.value),
|
||||||
|
);
|
||||||
|
|
||||||
|
treeData.value = AllMenu;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
import type {
|
import type {
|
||||||
AntTreeNodeDropEvent,
|
AntTreeNodeDropEvent,
|
||||||
TreeProps,
|
TreeProps,
|
||||||
|
@ -22,17 +23,17 @@ export const filterMenu = (permissions: string[], menus: any[]) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 拖拽跨级 存在顺序错乱,重复code todo
|
|
||||||
/**
|
/**
|
||||||
* 合并数组(合并菜单)
|
* 合并数组(合并菜单)
|
||||||
* @param oldData Array 默认菜单
|
* @param oldData Array 默认菜单
|
||||||
* @param newData Array 当前系统菜单
|
* @param newData Array 当前系统菜单
|
||||||
* @returns Array 合并后的菜单
|
* @returns Array 合并后的菜单
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
||||||
const mergedData = [];
|
const mergedData = [];
|
||||||
|
|
||||||
|
const { checkedKeys } = initData(cloneDeep(newData));
|
||||||
|
const filterCodeSet = new Set(checkedKeys); //记录系统选中
|
||||||
const mergeItem: any = (oldItem: any, newItem: any) => {
|
const mergeItem: any = (oldItem: any, newItem: any) => {
|
||||||
if (!oldItem) {
|
if (!oldItem) {
|
||||||
return newItem;
|
return newItem;
|
||||||
|
@ -43,9 +44,9 @@ export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
||||||
return oldItem;
|
return oldItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldItem.children && !newItem.children) {
|
// if (oldItem.children && !newItem.children) {
|
||||||
return oldItem;
|
// return oldItem;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (oldItem.children && newItem.children) {
|
if (oldItem.children && newItem.children) {
|
||||||
const mergedChildren = [];
|
const mergedChildren = [];
|
||||||
|
@ -60,7 +61,10 @@ export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
||||||
);
|
);
|
||||||
newChildren.splice(index, 1);
|
newChildren.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
mergedChildren.push(oldChild);
|
//防止重复code,系统已经选中的code不能再从old中添加
|
||||||
|
if (!filterCodeSet.has(oldChild.code)) {
|
||||||
|
mergedChildren.push(oldChild);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -76,11 +80,21 @@ export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
||||||
const oldItem = oldData.find((item) => item.code === newItem.code);
|
const oldItem = oldData.find((item) => item.code === newItem.code);
|
||||||
mergedData.push(mergeItem(oldItem, newItem));
|
mergedData.push(mergeItem(oldItem, newItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const oldItem of oldData) {
|
for (const oldItem of oldData) {
|
||||||
const newItem = newData.find((item) => item.code === oldItem.code);
|
if (!filterCodeSet.has(oldItem.code)) {
|
||||||
if (!newItem) {
|
const newItem = newData.find((item) => item.code === oldItem.code);
|
||||||
mergedData.push(oldItem);
|
if (!newItem) {
|
||||||
|
//防止重复code,系统已经选中的code不能再从old中添加
|
||||||
|
if (!filterCodeSet.has(oldItem.code)) {
|
||||||
|
if (oldItem.children) {
|
||||||
|
oldItem.children = oldItem.children.filter(
|
||||||
|
(i: any) => !filterCodeSet.has(i.code),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mergedData.push(oldItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,70 +102,26 @@ export const mergeArr = (oldData: Array<any>, newData: Array<any>) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并Map菜单转成Arr菜单
|
* 初始化菜单
|
||||||
* @param baseMenuData baseMenu developArrToMap平铺后的数据
|
|
||||||
* @param systemMenuData systemMenu developArrToMap平铺后的数据
|
|
||||||
* @returns 合并后的菜单
|
|
||||||
*/
|
|
||||||
export const mergeMapToArr = (baseMenuData: any, systemMenuData: any) => {
|
|
||||||
const updataArr = (r: any) => {
|
|
||||||
for (let i = 0; i < r.length; i++) {
|
|
||||||
let child = r[i].children;
|
|
||||||
if (child) {
|
|
||||||
updataArr(child);
|
|
||||||
}
|
|
||||||
r[i] = newMap.get(r[i].code);
|
|
||||||
r[i]?.parentCode && delete r[i].parentCode;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const root: any = [];
|
|
||||||
const newMap = new Map([...baseMenuData?.arrMap, ...systemMenuData.arrMap]);
|
|
||||||
const newRootArr = [
|
|
||||||
...new Set([...baseMenuData?.rootSet, ...systemMenuData.rootSet]),
|
|
||||||
];
|
|
||||||
newRootArr.forEach((item: any) => {
|
|
||||||
newMap.has(item) && root.push(newMap.get(item));
|
|
||||||
});
|
|
||||||
updataArr(root);
|
|
||||||
return root;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 平铺菜单
|
|
||||||
* @param value 默认菜单以及查询系统菜单 baseMenu systemMenu
|
* @param value 默认菜单以及查询系统菜单 baseMenu systemMenu
|
||||||
* @param checked 查询系统菜单传true
|
* @returns 系统选中的keys
|
||||||
* @param save 保存时传true
|
|
||||||
* @returns 平铺菜单Map、根菜单名、系统选中的keys
|
|
||||||
*/
|
*/
|
||||||
export const developArrToMap = (Menu: any, checked = false, save = false) => {
|
export const initData = (Menu: any) => {
|
||||||
const rootSet = new Set();
|
|
||||||
const arrMap = new Map();
|
|
||||||
const checkedKeys: any = [];
|
const checkedKeys: any = [];
|
||||||
const getMap = (arr: any, parentCode = 'root') => {
|
const getMap = (arr: any) => {
|
||||||
arr.forEach((item: any) => {
|
arr.forEach((item: any) => {
|
||||||
item.title = item.code;
|
item.title = item.code;
|
||||||
item.key = item.code;
|
item.key = item.code; // treeData需要唯一key
|
||||||
if (save) {
|
|
||||||
delete item.checked; //保存时删除 checked 字段
|
checkedKeys.push(item.code);
|
||||||
checkedKeys.push(item.code);
|
|
||||||
} else {
|
|
||||||
if (checked || item?.checked) {
|
|
||||||
item.checked = item?.checked || checked;
|
|
||||||
checkedKeys.push(item.code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arrMap.set(item.code, item);
|
|
||||||
if (parentCode === 'root') {
|
|
||||||
rootSet.add(item.code); //处理根菜单
|
|
||||||
}
|
|
||||||
if (item?.children) {
|
if (item?.children) {
|
||||||
getMap(item?.children, item.code);
|
getMap(item?.children);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
getMap(Menu);
|
getMap(Menu);
|
||||||
return { arrMap, rootSet, checkedKeys };
|
return { checkedKeys };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,7 +134,7 @@ export const developArrToMap = (Menu: any, checked = false, save = false) => {
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function findAllParentsAndChildren(data: any, code: any) {
|
export const findAllParentsAndChildren = (data: any, code: any) => {
|
||||||
const result = {
|
const result = {
|
||||||
parents: [],
|
parents: [],
|
||||||
children: [],
|
children: [],
|
||||||
|
@ -213,7 +183,7 @@ function findAllParentsAndChildren(data: any, code: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
};
|
||||||
/**
|
/**
|
||||||
* 选择功能
|
* 选择功能
|
||||||
* @param selecteds onSelect事件默认参数
|
* @param selecteds onSelect事件默认参数
|
||||||
|
|
Loading…
Reference in New Issue