feat: 菜单管理 重构菜单配置 完成交互逻辑
This commit is contained in:
parent
e969b3911f
commit
0f6f2cccb6
|
@ -23,12 +23,16 @@
|
|||
style="margin-bottom: 12px"
|
||||
/>
|
||||
<j-tree
|
||||
v-if="treeData.length !== 0"
|
||||
show-line
|
||||
defaultExpandAll
|
||||
multiple
|
||||
draggable
|
||||
:tree-data="treeData"
|
||||
:height="500"
|
||||
@select="onSelect"
|
||||
:selectedKeys="selectedKeys"
|
||||
@drop="onDrop"
|
||||
>
|
||||
<template #title="row">
|
||||
<div class="tree-content">
|
||||
|
@ -38,24 +42,6 @@
|
|||
{{ row.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-content-action">
|
||||
<span @click="(e) => e.stopPropagation()">
|
||||
<PermissionButton
|
||||
type="text"
|
||||
:tooltip="{
|
||||
title: '删除',
|
||||
}"
|
||||
hasPermission="DataCollect/Collector:delete"
|
||||
:popConfirm="{
|
||||
title: `确定删除?`,
|
||||
onConfirm: () =>
|
||||
handlDelete(row.id),
|
||||
}"
|
||||
>
|
||||
<AIcon type="CloseOutlined" />
|
||||
</PermissionButton>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</j-tree>
|
||||
|
@ -69,28 +55,32 @@
|
|||
<script setup lang="ts" name="MenuSetting">
|
||||
import { getMenuTree_api } from '@/api/system/menu';
|
||||
import { getSystemPermission as getSystemPermission_api } from '@/api/initHome';
|
||||
import { filterMenu, getKeys, loop } from './utils';
|
||||
import {
|
||||
filterMenu,
|
||||
mergeMapToArr,
|
||||
developArrToMap,
|
||||
drop,
|
||||
select,
|
||||
} from './utils';
|
||||
import BaseMenu from './baseMenu';
|
||||
import type {
|
||||
AntTreeNodeDropEvent,
|
||||
TreeDataItem,
|
||||
TreeProps,
|
||||
} from 'ant-design-vue/es/tree';
|
||||
import type { AntTreeNodeDropEvent } from 'ant-design-vue/es/tree';
|
||||
import { treeFilter } from '@/utils/tree';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
const treeData = ref<any>();
|
||||
const selectedKeys: any = ref([]);
|
||||
const treeData = ref<any>([]);
|
||||
const filterText = ref('');
|
||||
treeData.value = [...BaseMenu];
|
||||
let systemMenu: any = reactive([]);
|
||||
const baseMenu = cloneDeep(BaseMenu);
|
||||
const systemMenu: any = ref([]);
|
||||
const baseMenu: any = ref([]);
|
||||
const AllMenu = ref([]);
|
||||
|
||||
const BaseMenuMap = new Map();
|
||||
BaseMenu.forEach((item) => {
|
||||
BaseMenuMap.set(item.code, item);
|
||||
});
|
||||
const onSelect = (selecteds: Array<string>, e: any) => {
|
||||
selectedKeys.value = select(selecteds, e);
|
||||
};
|
||||
|
||||
console.log(11, BaseMenuMap);
|
||||
const onDrop = (info: AntTreeNodeDropEvent) => {
|
||||
treeData.value = drop(info, treeData.value);
|
||||
};
|
||||
|
||||
const params = {
|
||||
paging: false,
|
||||
|
@ -114,20 +104,25 @@ const params = {
|
|||
};
|
||||
|
||||
const change = (val: any) => {
|
||||
treeData.value = treeFilter(baseMenu, val.target.value, 'name');
|
||||
};
|
||||
|
||||
const handlDelete = (value) => {
|
||||
console.log(22, value);
|
||||
treeData.value = treeFilter(AllMenu.value, val.target.value, 'name');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getMenuTree_api(params).then((resp: any) => {
|
||||
if (resp.status == 200) {
|
||||
systemMenu = resp.result;
|
||||
console.log(2, systemMenu);
|
||||
}
|
||||
// transfer.data.rightTreeData = resp.result;
|
||||
getSystemPermission_api().then((resp: any) => {
|
||||
baseMenu.value = filterMenu(
|
||||
resp.result.map((item: any) => JSON.parse(item).id),
|
||||
BaseMenu,
|
||||
);
|
||||
getMenuTree_api(params).then((resp: any) => {
|
||||
if (resp.status == 200) {
|
||||
systemMenu.value = resp.result;
|
||||
const baseMenuData = developArrToMap(baseMenu.value);
|
||||
const systemMenuData = developArrToMap(systemMenu.value, true);
|
||||
selectedKeys.value = systemMenuData.checkedKeys;
|
||||
AllMenu.value = mergeMapToArr(baseMenuData, systemMenuData);
|
||||
treeData.value = cloneDeep(AllMenu.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -183,15 +178,13 @@ onMounted(() => {
|
|||
&-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
&-title {
|
||||
flex: 1;
|
||||
font-weight: 800;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
color: #333333;
|
||||
}
|
||||
&-action {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { TreeProps } from "ant-design-vue";
|
||||
import type {
|
||||
AntTreeNodeDropEvent,
|
||||
TreeProps,
|
||||
TreeDataItem,
|
||||
} from 'ant-design-vue/es/tree';
|
||||
|
||||
/**
|
||||
* 根据权限过滤菜单
|
||||
|
@ -18,21 +22,167 @@ export const filterMenu = (permissions: string[], menus: any[]) => {
|
|||
});
|
||||
};
|
||||
|
||||
// 在树形结构中对id进行匹配,通过callback对匹配id的对象进行操作
|
||||
export const loop= (data: TreeProps['treeData'], id: string | number, callback: any) => {
|
||||
data?.forEach((item, index) => {
|
||||
if (item.id === id) {
|
||||
return callback(item, index, data);
|
||||
}
|
||||
if (item.children) {
|
||||
return loop(item.children, id, callback);
|
||||
/**
|
||||
* 合并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++) {
|
||||
const child = r[i].children;
|
||||
if (child) {
|
||||
updataArr(child);
|
||||
}
|
||||
r[i] = newMap.get(r[i].code);
|
||||
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) => {
|
||||
root.push(newMap.get(item));
|
||||
});
|
||||
}
|
||||
//
|
||||
export const getKeys = (data: any[]): (string | number)[] => {
|
||||
return data.reduce((pre: (string | number)[], next: any) => {
|
||||
const childrenKeys = next.children ? getKeys(next.children) : [];
|
||||
return [...pre, next.code, ...childrenKeys];
|
||||
}, []);
|
||||
}
|
||||
updataArr(root);
|
||||
return root;
|
||||
};
|
||||
|
||||
/**
|
||||
* 平铺菜单
|
||||
* @param value 默认菜单以及查询系统菜单 baseMenu systemMenu
|
||||
* @param checked 查询系统菜单传true
|
||||
* @returns 平铺菜单Map、根菜单名、系统选中的keys
|
||||
*/
|
||||
export const developArrToMap = (Menu: any, checked = false) => {
|
||||
const rootSet = new Set();
|
||||
const arrMap = new Map();
|
||||
const checkedKeys: any = [];
|
||||
const getMap = (arr: any, parentCode = 'root', preKey = '0') => {
|
||||
arr.forEach((item: any, index: number) => {
|
||||
const key = preKey + `-${index}`; //初始化key
|
||||
item.title = item.code;
|
||||
item.key = key;
|
||||
if (checked) {
|
||||
checkedKeys.push(key);
|
||||
}
|
||||
arrMap.set(item.code, item);
|
||||
if (parentCode === 'root') {
|
||||
rootSet.add(item.code); //处理根菜单
|
||||
}
|
||||
if (item?.children) {
|
||||
getMap(item?.children, item.code, key);
|
||||
}
|
||||
});
|
||||
};
|
||||
getMap(Menu);
|
||||
return { arrMap, rootSet, checkedKeys };
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择功能
|
||||
* @param selecteds onSelect事件默认参数
|
||||
* @param e onSelect事件默认参数
|
||||
* @returns 处理后的keys
|
||||
*/
|
||||
export const select = (selecteds: Array<string>, e: any) => {
|
||||
const { node } = e;
|
||||
const childKeys: Array<string> = [];
|
||||
const getChildKeys = (data: any, preKey = '0') => {
|
||||
data.forEach((item: any, index: number) => {
|
||||
const checkedKey = preKey + `-${index}`;
|
||||
childKeys.push(checkedKey);
|
||||
if (item?.children) {
|
||||
getChildKeys(item?.children, checkedKey);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (node?.children) {
|
||||
getChildKeys(node.children, node.key);
|
||||
}
|
||||
|
||||
const Keys = new Set(selecteds);
|
||||
const selectedAllKeys = [...[node.key, ...childKeys]];
|
||||
selectedAllKeys.forEach((item: string) => {
|
||||
Keys[e.selected ? 'add' : 'delete'](item);
|
||||
});
|
||||
return [...Keys];
|
||||
};
|
||||
|
||||
/**
|
||||
* 拖拽功能
|
||||
* @param info drop事件默认参数
|
||||
* @param treeData 当前treeData值
|
||||
* @returns 拖拽后treeData值
|
||||
*/
|
||||
export const drop = (info: AntTreeNodeDropEvent, treeData: any) => {
|
||||
const dropKey = info.node.key;
|
||||
const dragKey = info.dragNode.key;
|
||||
const dropPos = info.node.pos.split('-');
|
||||
const dropPosition =
|
||||
info.dropPosition - Number(dropPos[dropPos.length - 1]);
|
||||
const loop = (
|
||||
data: TreeProps['treeData'],
|
||||
key: string | number,
|
||||
callback: any,
|
||||
) => {
|
||||
data.forEach((item, index) => {
|
||||
if (item.key === key) {
|
||||
return callback(item, index, data);
|
||||
}
|
||||
if (item.children) {
|
||||
return loop(item.children, key, callback);
|
||||
}
|
||||
});
|
||||
};
|
||||
const data = [...treeData];
|
||||
|
||||
let dragObj: TreeDataItem;
|
||||
loop(
|
||||
data,
|
||||
dragKey,
|
||||
(item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
|
||||
arr.splice(index, 1);
|
||||
dragObj = item;
|
||||
},
|
||||
);
|
||||
if (!info.dropToGap) {
|
||||
loop(data, dropKey, (item: TreeDataItem) => {
|
||||
item.children = item.children || [];
|
||||
item.children.unshift(dragObj);
|
||||
});
|
||||
} else if (
|
||||
(info.node.children || []).length > 0 && // Has children
|
||||
info.node.expanded && // Is expanded
|
||||
dropPosition === 1 // On the bottom gap
|
||||
) {
|
||||
loop(data, dropKey, (item: TreeDataItem) => {
|
||||
item.children = item.children || [];
|
||||
item.children.unshift(dragObj);
|
||||
});
|
||||
} else {
|
||||
let ar: TreeProps['treeData'] = [];
|
||||
let i = 0;
|
||||
loop(
|
||||
data,
|
||||
dropKey,
|
||||
(
|
||||
_item: TreeDataItem,
|
||||
index: number,
|
||||
arr: TreeProps['treeData'],
|
||||
) => {
|
||||
ar = arr;
|
||||
i = index;
|
||||
},
|
||||
);
|
||||
if (dropPosition === -1) {
|
||||
ar.splice(i, 0, dragObj);
|
||||
} else {
|
||||
ar.splice(i + 1, 0, dragObj);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
};
|
Loading…
Reference in New Issue