在权限设计时,分为部门、岗位、人员三部分, 人员下面挂部门,部门下面挂岗位,岗位下面挂菜单,用户在进行授权时,勾选了操作权限,默认数据权限也进行勾选。
权限组:查询、新增、修改、删除
用户交互如下:
1、选中新增、修改、删除中的任何一个复选框时,查询框也选中。
2、选中查询框时,新增、修改、删除不变。
3、取消选中查询框时,新增、修改、删除都取消选中。
代码如下:
javascript
<template>
<div>
<el-tree
ref="treeRef"
class="permission-tree"
:data="menuTree"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:check-on-click-node="true"
@check="handleCheck"
:props="{
label: 'title'
}"
>
</el-tree>
</div>
</template>
<script>
export default {
data() {
return {
menuTree: [
{
id: '1717148200757',
code: 'departmentManagement',
title: '部门管理 ',
name: '部门管理 ',
parentIdId: null,
children: [
{
id: '1717148287418',
parentIdId: '1717148200757',
code: 'department',
title: '部门',
name: '部门 ',
children: [
{
id: 'department:query',
code: 'department:query',
name: '查询',
title: '查询',
parentIdId: '1717148287418',
dataPermission: true
},
{
id: 'department:add',
code: 'department:add',
name: '新增',
title: '新增',
parentIdId: '1717148287418',
dataPermission: false
},
{
id: 'department:update',
code: 'department:update',
name: '修改',
title: '修改',
parentIdId: '1717148287418',
dataPermission: false
},
{
id: 'department:delete',
code: 'department:delete',
name: '删除',
title: '删除',
parentIdId: '1717148287418',
dataPermission: false
}
]
}
]
},
{
id: '1717148223729',
code: 'jobManagement',
title: '岗位管理',
name: '岗位管理',
parentId: null,
children: [
{
id: '1717148366037',
parentId: '1717148223729',
code: 'jobInside',
title: '岗位',
name: '岗位',
children: [
{
id: 'permissionManagement:position:query',
code: 'permissionManagement:position:query',
name: '查询',
title: '查询',
parentIdId: '1717148366037',
dataPermission: true
},
{
id: 'permissionManagement:position:add',
code: 'permissionManagement:position:add',
name: '新增',
title: '新增',
parentIdId: '1717148366037',
dataPermission: false
},
{
id: 'permissionManagement:position:update',
code: 'permissionManagement:position:update',
name: '修改',
title: '修改',
parentIdId: '1717148366037',
dataPermission: false
},
{
id: 'permissionManagement:position:delete',
code: 'permissionManagement:position:delete',
name: '删除',
title: '删除',
parentIdId: '1717148366037',
dataPermission: false
}
]
}
]
},
{
id: '1717148248870',
code: 'userManagement',
title: '用户管理',
name: '用户管理',
parentId: null,
children: [
{
id: '1717148408202',
parentId: '1717148248870',
code: 'userAdmin',
title: '用户',
name: '用户',
children: [
{
id: 'userAdmin:query',
code: 'userAdmin:query',
name: '查询',
title: '查询',
parentIdId: '1717148408202',
dataPermission: true
},
{
id: 'userAdmin:add',
code: 'userAdmin:add',
name: '新增',
title: '新增',
parentIdId: '1717148408202',
dataPermission: false
},
{
id: 'userAdmin:update',
code: 'userAdmin:update',
name: '修改',
title: '修改',
parentIdId: '1717148408202',
dataPermission: false
},
{
id: 'userAdmin:delete',
code: 'userAdmin:delete',
name: '删除',
title: '删除',
parentIdId: '1717148408202',
dataPermission: false
}
]
}
]
}
]
};
},
methods: {
/**
* 复选框选中事件
* 实现的效果:
* 1、查询节点选中时,其相邻兄弟节点不变
* 2、查询节点取消选中时,其相邻兄弟节点取消选中
* 3、其相邻兄弟节点任何一个选中时,查询节点必选中
* 注:查询节点 dataPermission:true
* **/
handleCheck(data) {
if (!data.children) {
// 获取当前叶子节点的兄弟节点
const sublingsNode = this.getSiblingsById(this.menuTree, data.id);
// 获取当前叶子节点中为查询节点的项
const dataPermissionItem = [data, ...sublingsNode].find(
(item) => item.dataPermission
);
if (data.dataPermission) {
// 操作的是查询节点时,将其兄弟节点设置为取消选中状态
sublingsNode.forEach((item) => {
this.$refs.treeRef.setChecked(item, false);
});
} else {
// 操作的是兄弟节点时,将查询节点设置为选中状态
this.$refs.treeRef.setChecked(dataPermissionItem, true);
}
}
},
/**
* 通过当前节点的 id 查找兄弟节点
* treeData:树形结构的数据源
* nodeId:当前节点的 id
* **/
getSiblingsById(treeData, nodeId) {
function findSiblings(nodes) {
for (const node of nodes) {
if (node.id === nodeId) {
return nodes.filter((item) => item.id !== nodeId);
}
if (node.children) {
const siblings = findSiblings(node.children, node.id);
if (siblings) return siblings;
}
}
return null;
}
return findSiblings(treeData, null);
}
}
};
</script>
总结:
在写这部分逻辑时,难点在于取消数据权限时,怎么将操作权限也进行取消,这部分的交互相当于是查询是新增、修改、删除的取消全选操作。在进行这部分交互效果实现时,有考虑过使用 current-change 这个事件,因为这个事件可以获取到一个 Node 对象,在 Node 对象中可以获取到当前节点父节点,从而在父节点下找到当前节点及兄弟节点,从而避免了使用递归的方式查找兄弟节点,这个事件有个问题,无法触发 check 事件,导致在点击复选框选中时,事件未触发,所以退而求其次考虑使用 check 事件,配合递归方法实现最终的交互效果。
补充:
可以将递归函数去掉,使用 elementUI 中提供的 getNode 方法获取当前节点的兄弟节点,修改如下:
javascript
<template>
<div>
<el-tree
ref="treeRef"
class="permission-tree"
:data="menuTree"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:check-on-click-node="true"
@check="handleCheck"
:props="{
label: 'title'
}"
>
</el-tree>
</div>
</template>
<script>
export default {
data() {
return {
menuTree: [
{
id: '1717148200757',
code: 'departmentManagement',
title: '部门管理 ',
name: '部门管理 ',
parentIdId: null,
children: [
{
id: '1717148287418',
parentIdId: '1717148200757',
code: 'department',
title: '部门',
name: '部门 ',
children: [
{
id: 'department:query',
code: 'department:query',
name: '查询',
title: '查询',
parentIdId: '1717148287418',
dataPermission: true
},
{
id: 'department:add',
code: 'department:add',
name: '新增',
title: '新增',
parentIdId: '1717148287418',
dataPermission: false
},
{
id: 'department:update',
code: 'department:update',
name: '修改',
title: '修改',
parentIdId: '1717148287418',
dataPermission: false
},
{
id: 'department:delete',
code: 'department:delete',
name: '删除',
title: '删除',
parentIdId: '1717148287418',
dataPermission: false
}
]
}
]
},
{
id: '1717148223729',
code: 'jobManagement',
title: '岗位管理',
name: '岗位管理',
parentId: null,
children: [
{
id: '1717148366037',
parentId: '1717148223729',
code: 'jobInside',
title: '岗位',
name: '岗位',
children: [
{
id: 'permissionManagement:position:query',
code: 'permissionManagement:position:query',
name: '查询',
title: '查询',
parentIdId: '1717148366037',
dataPermission: true
},
{
id: 'permissionManagement:position:add',
code: 'permissionManagement:position:add',
name: '新增',
title: '新增',
parentIdId: '1717148366037',
dataPermission: false
},
{
id: 'permissionManagement:position:update',
code: 'permissionManagement:position:update',
name: '修改',
title: '修改',
parentIdId: '1717148366037',
dataPermission: false
},
{
id: 'permissionManagement:position:delete',
code: 'permissionManagement:position:delete',
name: '删除',
title: '删除',
parentIdId: '1717148366037',
dataPermission: false
}
]
}
]
},
{
id: '1717148248870',
code: 'userManagement',
title: '用户管理',
name: '用户管理',
parentId: null,
children: [
{
id: '1717148408202',
parentId: '1717148248870',
code: 'userAdmin',
title: '用户',
name: '用户',
children: [
{
id: 'userAdmin:query',
code: 'userAdmin:query',
name: '查询',
title: '查询',
parentIdId: '1717148408202',
dataPermission: true
},
{
id: 'userAdmin:add',
code: 'userAdmin:add',
name: '新增',
title: '新增',
parentIdId: '1717148408202',
dataPermission: false
},
{
id: 'userAdmin:update',
code: 'userAdmin:update',
name: '修改',
title: '修改',
parentIdId: '1717148408202',
dataPermission: false
},
{
id: 'userAdmin:delete',
code: 'userAdmin:delete',
name: '删除',
title: '删除',
parentIdId: '1717148408202',
dataPermission: false
}
]
}
]
}
]
};
},
methods: {
/**
* 复选框选中事件
* 实现的效果:
* 1、查询节点选中时,其相邻兄弟节点不变
* 2、查询节点取消选中时,其相邻兄弟节点取消选中
* 3、其相邻兄弟节点任何一个选中时,查询节点必选中
* 注:查询节点 dataPermission:true
* **/
handleCheck(data, checked, indeterminate) {
if (!data.children) {
// 只处理叶子节点
const parentNode = this.$refs.treeRef.getNode(data).parent;
if (parentNode) {
// 获取当前叶子节点的兄弟节点
// const sublingsNode = this.getSiblingsById(this.treeData, data.id);
// 获取当前叶子节点和兄弟节点
const siblings = parentNode.data.children;
const dataPermissionItem = siblings.find(
(item) => item.dataPermission
);
if (data.dataPermission) {
// 如果是查询节点,则取消选中所有非查询兄弟节点
siblings.forEach((sibling) => {
if (!sibling.dataPermission) {
this.$refs.treeRef.setChecked(sibling, false, false);
}
});
} else if (checked) {
// 如果是非查询节点被选中,则确保查询节点也被选中
this.$refs.treeRef.setChecked(dataPermissionItem, true, false);
}
}
}
}
// /**
// * 通过当前节点的 id 查找兄弟节点
// * treeData:树形结构的数据源
// * nodeId:当前节点的 id
// * **/
// getSiblingsById(treeData, nodeId) {
// function findSiblings(nodes) {
// for (const node of nodes) {
// if (node.id === nodeId) {
// return nodes.filter((item) => item.id !== nodeId);
// }
// if (node.children) {
// const siblings = findSiblings(node.children, node.id);
// if (siblings) return siblings;
// }
// }
// return null;
// }
// return findSiblings(treeData, null);
// }
}
};
</script>