2021-09-15

基于elementui实现部门树结构 ,一个用户可能在多个部门(即树结构下存在多个id相同的用户)

在这里插入图片描述

要求

1、点击左边部门节点选中添加或删除该节点下的所有用户,点击用户,若用户在其他部门也存在,同样也要勾选上。并将选中的用户在右边展示。
2、点击右边的删除,左边的tree树形控件对应取消选中该用户。
3、当有默认选中的用户,左边对应选中该用户

难点

elementui-tree中如果出现id相同时会被覆盖,导致所有方法都只能操作到相同用户的最后一个

解决方案

通过elementui自定义节点内容实现

代码

<div class="selectPersonnel">
  <div class="tree">
    <div class="content">
      <el-tree :data="treeData" :props="defaultProps" :expand-on-click-node="false" class="eltree">
        <span class="custom-tree-node" slot-scope="{ node, data }">
          <el-checkbox :value="checked(data)" @change="chengeChecked(data)" :class="{'ishals':data.children&&ishals(data),'checkbox':true}">{{node.label}}</el-checkbox>
        </span>
      </el-tree>
    </div>
  </div>
  <div class="personnel">
    <div class="title">已选</div>
    <div class="content">
      <div v-for="(item,index) in selectData" :key="item.id">
        <div>{{item.label}}</div>
          <i class="el-icon-close" @click="remove(index)"></i>
        </div>
      </div>
    </div>
  </div>
</div>
data() {
      return {
        treeData: [{
          label: '总公司',
          id: 0,
          children: [{
            label: '子公司A',
            id: 1,
            children: [{
              label: '部门A',
              id: 4,
              children: [{
                label: '用户A',
                id: 9,
              }]
            }]
          }, {
            label: '子公司B',
            id: 2,
            children: [{
              label: '部门B',
              id: 5,
              children: [{
                label: '用户B',
                id: 10,
              }, {
                label: '用户C',
                id: 20,
              }, {
                label: '用户D',
                id: 21,
              }]
            }, {
              label: '部门C',
              id: 6,
              children: [{
                label: '用户E',
                id: 11,
              }]
            }]
          }, {
            label: '子公司C',
            id: 3,
            children: [{
              label: '部门D',
              id: 7,
              children: [{
                label: '用户F',
                id: 13,
              }, {
                label: '用户G',
                id: 12,
              }]
            }, {
              label: '部门E',
              id: 8,
              children: [{
                label: '用户F',
                id: 13,
              }]
            }]
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'orgName'
        },
        selectData: []
      };
    },
 methods: {
      //每个节点的选择状态,false为未选择,true为选中
      checked(data) {
        let flag = false //默认为选择
        if (data.children) { //当不为用户层节点时
          flag = this.mapChildren(data, true) //遍历子集,默认为true,当节点下的某一个用户没有被选中时返回false
        } else { //当为用户层节点时
          flag = this.isInArr(this.selectData, 'id', data.id) > -1 //判断用户是否已选择
        }
        return flag
      },
      //判断非用户层的节点下的用户是否全部为选择状态,是则返回true,不是则返回false
      mapChildren(data, flag) {
        if (data.children) { //若当前层下还有层级
          data.children.forEach(item => { //遍历回调
            let isCheck = this.mapChildren(item, true)
            if (!isCheck) { //某个用户没有被选中赋值flag为false
              flag = false
            }
          })
        } else { //若当前层是用户层
          let ischeckout = this.isInArr(this.selectData, 'id', data.id) == -1 
          if (ischeckout) { //若这个用户没有被选中赋值flag为false
            flag = false
          }
        }
        return flag
      },
      //点击多选框触发
      chengeChecked(data) {
        if (!data.children) { //点击用户层的多选框
          let index = this.isInArr(this.selectData, 'id', data.id) //判断之前有没有选择当前用户
          if (index == -1) { //之前没有选择当前用户,则推入
            this.selectData.push(data)
          } else { //之前有选择当前用户,则删除
            this.selectData.splice(index, 1)
          }
        } else { //点击不是用户层的多选框
          let allUser = this.getAllUser(data) //获取到这个节点下的所有用户
          if (this.isAllSelect(data)) { //之前已全部选中所有用户
            allUser.forEach(item => {
              let index = this.isInArr(this.selectData, 'id', item.id)
              this.selectData.splice(index, 1) //取消这个节点所有选中的用户
            })
          } else { //之前有的用户没有选中
            allUser.forEach(item => {
              let index = this.isInArr(this.selectData, 'id', item.id)
              if (index == -1) {
                this.selectData.push(item) //添加这个节点所有未选中的用户
              }
            })
          }
        }
      },
      //判断当前arr数组的某一项的key键的值对应keyValue,存在则返回下标,否则放回-1
      isInArr(arr, key, keyValue) {
        let flag = -1
        arr.forEach((item, index) => {
          if (item[key] == keyValue) {
            flag = index
          }
        })
        return flag
      },
      //判断是否为全选
      isAllSelect(data) {
        let copyData = this.$Tools.deepCopy(data)
        let allUser = this.getAllUser(copyData)
        let statue = []
        allUser.forEach(item => {
          let ischeckout = this.isInArr(this.selectData, 'id', item.id) == -1
          if (ischeckout) {
            statue.push(-1)
          } else {
            statue.push(0)
          }
        })
        // console.log(statue.indexOf(0) > -1,)
        if (statue.indexOf(0) > -1 && statue.indexOf(-1) == -1) {
          return true
        } else {
          return false
        }
      },
      //判断是否为半选
      ishals(data) {
        let copyData = this.$Tools.deepCopy(data)
        let allUser = this.getAllUser(copyData)
        let statue = []
        allUser.forEach(item => {
          let ischeckout = this.isInArr(this.selectData, 'id', item.id) == -1
          if (ischeckout) {
            statue.push(-1)
          } else {
            statue.push(0)
          }
        })
        return statue.indexOf(-1) > -1 && statue.indexOf(0) > -1
      },
      //获取所有的用户
      getAllUser(data) {
        let allData = []
        if (data.children) {
          data.children.forEach(item => {
            let itemData = this.$Tools.deepCopy(this.getAllUser(item))
            let preData = this.$Tools.deepCopy(allData)
            allData = [...preData, ...itemData]
          })
        } else {
          allData.push(data)
        }
        return allData
      },
      //点击X删除对应的
      remove(index) {
        this.selectData.splice(index, 1)
      },
    },
<style scoped lang="less">
  @deep: ~">>>";
.selectPersonnel {
    display: flex;
    justify-content: space-between;
    padding-bottom: 20px;
    .tree {
      width: 40%;
      background: #2B2B2B;
      height: 400px;
      margin-right: 5px;
      box-shadow: 0px 3px 17px rgba(0, 0, 0, 0.48);
      border-radius: 5px;
      .content {
        height: calc(100% - 20px);
        padding: 10px;
        overflow-x: hidden;
        overflow-y: auto;
        .customTree {
          .treeList {
            height: 25px;
            line-height: 25px;
            color: #fff;
          }
          .treeList1 {
            margin-left: 10px;
          }
          .treeList2 {
            margin-left: 20px;
          }
          .treeList3 {
            margin-left: 30px;
          }
        }
      }
      .content::-webkit-scrollbar {
        width: 6px; //  设置为0则不显示 不会影响页面宽度
      }
      .content::-webkit-scrollbar-track {
        border-radius: 5px;
        background-color: #2B2B2B;
      }
      .content::-webkit-scrollbar-thumb {
        background-color: #999;
        border-radius: 10px;
      }
      .content::-webkit-scrollbar-thumb:hover {
        background-color: #666;
      }
      .content::-webkit-scrollbar-corner {
        background-color: #2B2B2B;
      }
      .eltree {
        // width: 100%;
        background: transparent;
        color: #FFFFFF;
        @{deep} .el-tree-node__content {
          background: transparent;
          &:hover {
            background: transparent;
          }
        }
        @{deep} .el-tree-node__label {
          color: rgba(255, 255, 255, 0.6);
        }
      }
    }
    .personnel {
      flex: 1;
      height: 400px;
      background: #2B2B2B;
      box-shadow: 0px 3px 17px rgba(0, 0, 0, 0.48);
      font-size: 14px;
      font-family: PingFang SC;
      font-weight: 400;
      line-height: 30px;
      color: rgba(255, 255, 255, 0.6);
      .title {
        padding-left: 20px;
        color: rgba(255, 255, 255, 1);
      }
      .content {
        height: calc(100% - 50px);
        padding: 10px;
        overflow-x: hidden;
        overflow-y: auto;
      }
      .content::-webkit-scrollbar {
        width: 6px; //  设置为0则不显示 不会影响页面宽度
      }
      .content::-webkit-scrollbar-track {
        border-radius: 5px;
        background-color: #2B2B2B;
      }
      .content::-webkit-scrollbar-thumb {
        background-color: #999;
        border-radius: 10px;
      }
      .content::-webkit-scrollbar-thumb:hover {
        background-color: #666;
      }
      .content::-webkit-scrollbar-corner {
        background-color: #2B2B2B;
      }
      .labelContent {
        display: flex;
        >div {
          padding-left: 20px;
          width: calc(100% - 60px);
        }
        .el-icon-close {
          transition: none;
          font-size: 20px;
          width: 30px;
          line-height: 30px;
          text-align: center;
        }
        &:hover {
          background: #434343;
          color: rgba(255, 255, 255, 1);
        }
      }
    }
  }
  .ishals {
    // #04a3ff
    @{deep} .el-checkbox__inner {
      background: #409EFF;
      // #04a3ff;
    }
    @{deep} .el-checkbox__inner::before {
      content: '';
      position: absolute;
      display: block;
      background-color: #FFF;
      height: 2px;
      -webkit-transform: scale(.5);
      transform: scale(.5);
      left: 0;
      right: 0;
      top: 0.35714rem;
    }
  }
  .checkbox {
    @{deep} .el-checkbox__label {
      color: #fff
    }
  }
  </style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值