vue 权限分组

在权限设计时,分为部门、岗位、人员三部分, 人员下面挂部门,部门下面挂岗位,岗位下面挂菜单,用户在进行授权时,勾选了操作权限,默认数据权限也进行勾选。

权限组:查询、新增、修改、删除

用户交互如下:

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>
相关推荐
橙露15 分钟前
JavaScript 异步编程:Promise、async/await 从原理到实战
开发语言·javascript·ecmascript
2301_7806698625 分钟前
前端logo替换开发
前端·vue.js
我命由我123451 小时前
React Router 6 - 嵌套路由、路由传递参数
前端·javascript·react.js·前端框架·html·ecmascript·js
十六年开源服务商1 小时前
2026年WordPress网站地图完整指南
java·前端·javascript
英俊潇洒美少年2 小时前
MessageChannel 如何实现时间切片
javascript·react.js·ecmascript
技术钱3 小时前
react数据大屏四种适配方案
javascript·react.js·ecmascript
李明卫杭州3 小时前
JavaScript 严格模式下 arguments 的区别
前端·javascript
一次旅行4 小时前
今日心理学知识分享(三)
开发语言·javascript·程序人生·ecmascript
牛十二4 小时前
openclaw安装mcporter搜索小红书
开发语言·javascript·ecmascript
小金鱼Y4 小时前
🔥 前端人必看:浏览器安全核心知识点全解析(XSS/CSRF/DDoS)
前端·javascript·安全