element-ui el-tree 权限列表 父子节点全选节点新增子级也被选中、非全选得不到父节点id的bug修复

问题描述:
在写后台管理是 遇到用el-tree展示权限列表的情况,给角色分配权限时,选择了某一项目前全有的权限,如图:


image.png

但是如果之后 我再新增一个子权限 这个子权限也会被默认选中,如图:
首先新增一个 但是我并没有去给任何角色分配此权限


image.png

但是:!!what the f**k??
image.png

产生原因:当我们在全部选中某一项权限时 权限的父级id也会被加入到我们已选择的权限中 当我们把含有父级id的权限数组传给后端,再请求权限列表时,el-tree检测到里面包含的父级权限的id,就会默认勾选上该父级权限及他下面的所有子权限。

解决办法:

办法1:取消父子级联动效果 使用 check-strictly 属性,

      <el-tree
        ref="tree"
        :data="listPermission"
        :props="props"
        node-key="permissionId"
        show-checkbox
        default-expand-all
        :default-checked-keys="hadPermissionIdList"
        getCheckedKeys
        check-strictly
      ></el-tree>

办法2,在添加权限和显示已有权限时 过滤掉父级id

第一步,在上传id的时候 过滤掉父级id 这样在之后请求权限列表时就不会有父级id存在,上述问题就不会存在了。但是,会有一个新的bug,如果有一个权限,情况一:他有子级,但是目前子级目前还没有添加上去,也就是他的haveChildFlag 为true,但是目前childList为[ ],或者,情况二:原本是子级,haveChildFlag 为false,后来子级变为父级,haveChildFlag 为true。那么这样的父级我们都应该先视为子级,等他变为父级之后,取消他的选中状态,等待管理员重新分配角色,否则,还是会出现有了父级id,子级(不论是否是新增)被全部选中的情况。
具体实现思路:在提交选中的权限的时候,过滤掉childList.length>0的父级。在请求到权限之后,过滤掉已有权限中childList.length>0的父级。

<template>
  <div>
    <el-button type="warning" @click="showDialog">分配权限</el-button>
    <el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
      <el-tree
        ref="tree"
        :data="listPermission"
        :props="props"
        node-key="permissionId"
        show-checkbox
        default-expand-all
        :default-checked-keys="hadPermissionIdList"
        getCheckedKeys
      ></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="handleSubmit">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { updateUser,getlistPermission, appointPermissionToRole,} from "@/network/systemManage";//这是我封装的网络请求 用的axios
export default {
  props: ["row"],
  data() {
    return {
      dialogVisible: false,
      data: [],
      selectedRole: [],
      props: {
        label: "permissionName",
        children: "childList",
      },
      count: 1,
      listPermission: [], //权限列表(所有)
      hadPermissionIdList: [], //已有的权限
      permissionIdList: [], //要选择的权限
      toDeletePermissionIdList: [], //被删掉的权限
      lock: false//防止重复点击的锁
    };
  },
  created() {},
  methods: {
    showDialog() {//打开弹窗
      this.dialogVisible = true;
      this.lock = false;
      const config = {
        pageIndex: 1,
        pageSize: 10,
        roleId: this.row.id,
      };
      getlistPermission(config).then((res) => { //获取某用户权限列表
        const data = res.data;
        if (data.code == 100) {
          //全部权限
          this.listPermission = data.content.allPermissionList;
          //该用户已有权限
          if (data.content.hadPermissionIdList) {
            this.hadPermissionIdList = data.content.hadPermissionIdList;
            //过滤父级id
            let newArr = [];
            let item = "";

            this.hadPermissionIdList.forEach((item) => {
              this.checked(item, this.listPermission, newArr);
            }); //item是已有的id,将已有的id与全部id进行匹配 找出父id然后删除
            this.hadPermissionIdList = newArr; //将删除了父级id的数据赋值过去,这样就不会选中父id下面的东西了。
          }
        }
      });
    },
    checked(id, data, newArr) {//这个函数是在检查id是否是父级id 将子级id过滤出来 运用到了递归
      data.forEach((item) => {
        if (item.permissionId == id) { //在数组的第一层中查找属于这个id的item
          if (!item.haveChildFlag || item.childList.length < 1) {//如果item没有子级或者子级为空就说明他不是父节点或者暂时不是父节点 因为也存在有子级但是子级还没有添加进去的情况 如果直接过滤掉haveChildFlag 为true的item 会导致判断不精准
            newArr.push(item.permissionId);
          }
        } else {
          if (item.haveChildFlag && item.childList.length != 0) {
            // 查找第二层 第三层 检查这个id是否是子节点的id
            this.checked(id, item.childList, newArr);
          }
        }
      });
    },
    handleSubmit() {
      //点击确定 发送配置权限时
      //获取选中的角色

      if (!this.lock) {//这个lock是为防止重复点击
        var selectedRoleAll = [];
        this.selectedRole = [];
        this.lock = true;
    //获取所有被选中的权限
         selectedRoleAll = this.$refs.tree.getCheckedNodes();
    //将是子级 或者是父级但是还没有添加子级(这种要暂时将他视为子级 等他真正添加了子级之后 再删除)的id过滤出来
        selectedRoleAll.forEach((item) => {
          if (item.childList.length === 0) {
            this.selectedRole.push(item);
          }
        });

        let arr = [];
      //拿到他们的id
        this.selectedRole.map((item) => {
          arr.push(item.permissionId);
        });
        // console.log("已选择" + arr);

        //  对比原本有的和现在选择的 筛选出原来有的现在没有的//这是个人需求 后端要求我在传送选择了哪些权限时将原本有现在没有了的权限一起返给他
        this.toDeletePermissionIdList = this.hadPermissionIdList.filter(
          (item) => {
            return arr.indexOf(item) == -1;
          }
        );
        // console.log("被删掉" + this.toDeletePermissionIdList);
        const config = {
          permissionIdList: arr,
          roleId: this.row.id,
          toDeletePermissionIdList: this.toDeletePermissionIdList,
        };
        // 发送请求
        appointPermissionToRole(config).then((res) => {
          const code = res.data.code;
          if (code == 100) {
            this.dialogVisible = false;
            this.$message({
              message: res.data.message,
              type: "success",
            });
          } else {
            this.$message.error(res.data.message);
          }
        });
      } else {
        return;
      }
    },
  },
};
</script>

<style>
</style>

另一种需求

如果后端要求在上传权限id时,不能过滤掉父级id,那么应该对代码做出修改。

经过调试发现,使用

var  selectedRoleAll = this.$refs.tree.getCheckedNodes();

el-tree只有在子节点全选中时,父节点才是选中状态,selectedRoleAll 中才会有父节点id,当取消一个子节点,父节点就变成了半选状态,此时,应当使用:

var parentArr = this.$refs.tree.getHalfCheckedNodes()

来获取子父节点,然后将两者的id提出来,进行拼接,再将拼接后的数据上传

 [半选节点(父级)id].concat([子节点id]),

注意再看一遍我的属性配置

 <el-tree
        ref="tree"
        :data="listPermission"
        :props="props"
        node-key="permissionId"
        show-checkbox
        default-expand-all
        :default-checked-keys="hadPermissionIdList"
        getCheckedKeys
        @check-change="checkChange"
      ></el-tree>

这样就能在子元素非全选的情况下将父节点id上传,但是这样在请求到以后权限的时候,为了避免出现之前的bug,需要将父节点id过滤出来再绑定到
default-checked-keys上,方法与第一种情况中给的一样,不再赘述。
数据:

"content":{
        "allPermissionList":[
            {
                "childList":[
                    {
                        "childList":[],//子级列表
                        "haveChildFlag":false,///根据这个字段判断是不是有没有子级
                        "menuFlag":true,
                        "modelAction":"admin/listRole",
                        "parentLevelId":1,
                        "permissionId":2,
                        "permissionName":"角色管理"
                    },
                    {
                        "childList":[],
                        "haveChildFlag":true,
                        "menuFlag":true,
                        "modelAction":"admin/listPermission",
                        "parentLevelId":1,
                        "permissionId":8,
                        "permissionName":"菜单管理"
                    },
                ],
                "haveChildFlag":true,
                "menuFlag":true,
                "modelAction":"admin",
                "parentLevelId":0,
                "permissionId":1,
                "permissionName":"系统管理"
            },
            {
                "childList":[
                    {
                        "childList":[],
                        "haveChildFlag":false,
                        "menuFlag":false,
                        "modelAction":"terminal/listTerminal",
                        "parentLevelId":6,
                        "permissionId":7,
                        "permissionName":"设备列表"
                    },
                ],
                "haveChildFlag":true,
                "menuFlag":true,
                "modelAction":"terminal",
                "parentLevelId":0,
                "permissionId":6,
                "permissionName":"设备管理"
            },
            {
                "childList":[
                    
                    {
                        "childList":[
                            {
                                "childList":[],
                                "haveChildFlag":false,
                                "menuFlag":true,
                                "modelAction":"dispathTask/yinliu/follow",
                                "parentLevelId":61,
                                "permissionId":63,
                                "permissionName":"关注功能"
                            }
                        ],
                        "haveChildFlag":true,
                        "menuFlag":true,
                        "modelAction":"executeTask/yinliu",
                        "parentLevelId":59,
                        "permissionId":61,
                        "permissionName":"引流功能"
                    },
                    {
                        "childList":[],
                        "haveChildFlag":false,
                        "menuFlag":true,
                        "modelAction":"dispathTask/danxiang",
                        "parentLevelId":59,
                        "permissionId":66,
                        "permissionName":"单项功能"
                    },
                ],
                "haveChildFlag":true,
                "menuFlag":true,
                "modelAction":"dispathTask",
                "parentLevelId":0,
                "permissionId":59,
                "permissionName":"任务下发"
            },
            {
                "childList":[],
                "haveChildFlag":false,
                "menuFlag":false,
                "modelAction":"admin/getCurrentUserInfo",
                "parentLevelId":0,
                "permissionId":78,
                "permissionName":"获取当前用户信息"
            },
        ]
    },
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345