VUE-ElementUI 对话框多层级树形控件,穿越框复杂业务实现

  1. 云栖社区>
  2. 前端那些事儿>
  3. 博客>
  4. 正文

VUE-ElementUI 对话框多层级树形控件,穿越框复杂业务实现

佀无极 2019-12-01 11:04:26 浏览2191
展开阅读全文

VUE-ElementUI 对话框多层级树形控件,穿越框复杂业务实现

请忽略css,主要是逻辑,看图,图片为子组件,左侧树形控件,中间选择框,右侧展示框

1575106275_1_
1575106412_1_

父组件

<template>
  <div class="box">
    <div class="ad-primary choose-btn" @click="chooseOne">请选择人员</div>
    <div class="ad-primary choose-btn" @click="chooseTwo">请选择管理员</div>
    <div>选择人员{{attendanceOfficerNameList}}</div>
    <div>选择管理员{{attendanceOfficerNameListF}}</div>

    <select-officer
      @dialogFun="dialogOne"
      :post-visible="dialogVisibleOne"
      :post-person="kqPerson"
      :post-frame="kqCount"
      :post-user="kqCountu"></select-officer>
    
    <select-officer
      @dialogFun="dialogTwo"
      :post-visible="dialogVisibleTwo"
      :post-person="labelPerson"
      :post-frame="labelCount"
      :post-user="labelCountu"></select-officer>
    
  </div>
</template>

<script>
  import attendanceOfficer from "@/pages/common/attendanceOfficer"

  export default {
    name: 'attendanceAdd',
    components: {
      'select-officer': attendanceOfficer
    },
    data() {
      return {
        dialogVisibleOne: false,
        dialogVisibleTwo: false,
        kqPerson: [],
        kqCount: 0,
        kqCountu: 0,
        labelPerson: [],
        labelCount: 0,
        labelCountu: 0,
        attendanceOfficerIds: [],
        attendanceOfficerNameList: "",
        attendanceOfficerIdsF: [],
        attendanceOfficerNameListF: "",
      }
    },
    created() {
      this.getDatas();
    },
    methods: {
      /** 考勤类型列表 */
      getDatas() {
        function getQuery (variable) {
          let code = window.location.search.substring(1)
          //let enUrl = 'user=dev-test&pwd=11111111'
          //let enUrls = encodeURIComponent(enUrl)
          //console.log(enUrls)
          let codes = decodeURIComponent(code)
          let vars = codes.split("&");
          for (let i = 0; i < vars.length; i++) {
            let pair = vars[i].split("=");
            if (pair[0] == variable) {
              return pair[1];
            }
          }
          return (false);
        }

        let that = this;
        let u = getQuery('kqId');
        //console.log('kq = '+u)
        if (u) {
          let params_show = {
            //"requestId":"4333532244114",
            "authToken": "12312",
            "userToken": "26cea5f746ae4c7fbf7c3a4018b23f28",
            "data": {
              "kqId": u
            }
          }
          this.http.post('www.centby.com/show', params_show).then(
            res => {
              if (res.data.kqPersons != null) {
                that.kqPerson = res.data.kqPersons;
                let j = 0;
                let k = 0;
                res.data.kqPersons.forEach(function (item) {
                  if (nodeType == 0) {
                    j++;
                  } else if (nodeType == 1) {
                    k++
                  }
                });
                that.kqCount = j;
                that.kqCountu = k;
              }
              if (res.data.kqLiablePersons != null) {
                that.labelPerson = res.data.kqLiablePersons;
                let m = 0;
                let n = 0;
                res.data.kqLiablePersons.forEach(function (item) {
                  if (nodeType == 0) {
                    m++;
                  } else if (nodeType == 1) {
                    n++
                  }
                });
                that.labelCount = m;
                that.labelCountu = n;
              }
              //console.log(JSON.stringify(res))
            },
            error => {
              console.log(error.message)
            }
          )
        }
      },
      chooseOne(){
        this.dialogVisibleOne = true;
      },
      chooseTwo(){
        this.dialogVisibleTwo = true;
      },
      dialogOne(data){
        //console.log(data)
        this.dialogVisibleOne = data.emita;
        this.attendanceOfficerIds = data.emitb;
        this.attendanceOfficerNameList = data.emitc;
      },
      dialogTwo(data){
        //console.log(data)
        this.dialogVisibleTwo = data.emita;
        this.attendanceOfficerIdsF = data.emitb;
        this.attendanceOfficerNameListF = data.emitc;
      }
    }
  }
</script>

<style scoped>
  .choose-btn {
    width: 80px;
    height: 30px;
    line-height: 30px;
    padding: 0 20px;
    margin-bottom: 10px;
    font-size: 14px;
    font-weight: 600;
    border-radius: 4px;
    cursor: pointer;
  }
</style>

子组件

<template>
  <el-dialog
    title="选择人员"
    align="left"
    :visible.sync="dialogVisible"
    width="50%"
    :before-close="handleClose">
    <div class="chosen-modal">
      <div class="chosen-modal-left">
        <div class="chosen-modal-hd">
          <div class="chosen-modal-hd-search">
            <i class="el-icon-search" @click="searchSelect"></i>
            <input type="text" class="aui-input" placeholder="搜索" v-model="searchWord" id="chosenSearch">
          </div>
        </div>
        <div class="chosen-modal-bd" style="position: relative;">
          <div class="chosen-left" style="width: 200px;">
            <el-tree :data="treeData" :props="defaultProps" node-key="id" @node-click="handleNodeClick">
                <span class="custom-tree-node" slot-scope="{ node, data }">
                  <i class="el-icon-folder-opened" v-show="data.nodeType == 0 ? true : false"></i>
                  <i class="el-icon-s-custom" v-show="data.nodeType == 0 ? false : true"></i>
                  <span>{{ node.label }}</span>
                </span>
            </el-tree>
          </div>
          <div class="chosen-right">
            <el-checkbox v-model="checkAll" @change="handleCheckAllChange" :disabled="forbid">全选</el-checkbox>
            <div style="margin: 15px 0;"></div>
            <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
              <el-checkbox v-for="item in category" :label="item.id" :key="item.id" :disabled="forbid">
                <i class="el-icon-folder-opened" v-show="item.nodeType == 0 ? true : false"></i>
                <i class="el-icon-s-custom" v-show="item.nodeType == 0 ? false : true"></i>
                {{item.name}}
              </el-checkbox>
            </el-checkbox-group>
          </div>
        </div>
      </div>
      <div class="chosen-modal-right">
        <div class="chosen-modal-right-hd">
          <p id="tipText">已选{{frameCount}}个架构,{{userCount}}名用户</p>
        </div>
        <div class="chosen-modal-right-bd">
          <div class="chosen-person-org" v-for="items in selectList" :key="items.id" @click="delList(items.id)">
            <i class="el-icon-folder-opened" v-show="items.nodeType == 0 ? true : false"></i>
            <i class="el-icon-s-custom" v-show="items.nodeType == 0 ? false : true"></i>
            <span class="js-chosen-rs-text">{{items.name}}</span>
            <i class="el-icon-close"></i>
          </div>
        </div>
      </div>
    </div>
    <span slot="footer" class="dialog-footer">
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" class="ad-primary" @click="next">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script>
  //centby.com

  export default {
    name: 'attendanceOfficer',
    props: {
      postFrame: {
        type: Number
      },
      postUser: {
        type: Number
      },
      postVisible: {
        type: Boolean
      },
      postPerson: {
        type: Array,
        default: () => []
      }
    },
    data () {
      return {
        searchWord: "",
        defaultProps: {
          children: 'children',
          label: 'label'
        },
        treeData: [],//树形渲染
        category: [],//选中框渲染
        selectList: [],//展示框渲染
        checkAll: false,//全选按钮状态
        checkedCities: [],//选中框选中的 id 列表
        listId:[],//选中框所有 id 列表
        parentList: [],//当前树形节点所有父级 id 列表包含自己
        forbid: false,//选中框所有禁选状态,默认可选
        frameCount: 0,
        userCount: 0,
        attendanceOfficerIds: [],//选中的 id 传给父组件
        attendanceOfficerNameList: "",//选中字符串传给父组件,做展示
        reviewData: '',//展示框请求回显数据
        dialogVisible: false//对话框打开或关闭状态
      }
    },
    watch: {
      postFrame: {
        handler(newName, oldName) {
          this.frameCount = newName;
        },
        immediate: true,
        deep: true
      },
      postUser: {
        handler(newName, oldName) {
          this.userCount = newName;
        },
        immediate: true,
        deep: true
      },
      postPerson: {
        handler(newName, oldName) {
          this.selectList = newName;
        },
        immediate: true,
        deep: true
      },
      postVisible: {
        handler(newName, oldName) {
          this.dialogVisible = newName;
        },
        type: Boolean
      }
    },
    created(){
      this.treePool();
    },
    methods: {
      handleClose(){
        this.dialogVisible = false;
        this.$emit('dialogFun', this.dialogVisible);
      },
      next() {
        let list = this.selectList;
        let arr = [];
        list.forEach(item => {
          this.attendanceOfficerIds.push(item.id);
          arr.push(item.name);
        })
        this.attendanceOfficerNameList = arr.join(",");
        console.log(this.attendanceOfficerIds)
        console.log(this.attendanceOfficerNameList)
        this.dialogVisible = false;
        //对话框打开关闭状态,选中 id 列表,选中 name 列表返回给父组件
        this.$emit('dialogFun', {emita:this.dialogVisible,emitb:this.attendanceOfficerIds,emitc:this.attendanceOfficerNameList});
      },
      treePool () {
        //展示框数据
        // this.selectList = [{
        //   id: '7387601',
        //   name: '科技部',
        //   nodeType: '0'
        // }]
        //树形数据
        /*
        [{
            "id": "0",
            "label": "学生",
            "nodeType": 0,
            "orgType": 1,
            "children": [
                {
                    "id": "3736461431145987660",
                    "label": "初中部",
                    "nodeType": 0,
                    "orgType": 1,
                    "children": [
                        {
                            "id": "3736461431145987661",
                            "label": "2011级",
                            "nodeType": 0,
                            "orgType": 1,
                            "children": [
                                {
                                    "id": "3736461431145987662",
                                    "label": "3班",
                                    "nodeType": 0,
                                    "orgType": 1,
                                    "children": [
                                        {
                                            "id": "3736461431145987663",
                                            "label": "小牛奶",
                                            "nodeType": 1,
                                            "orgType": 1,
                                            "children": null
                                        },
                                        {
                                            "id": "3736461431145987663",
                                            "label": "小牛奶",
                                            "nodeType": 1,
                                            "orgType": 1,
                                            "children": null
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }]
        */
        let that = this;
        let params = {
          //"requestId":"4333532244114",
          "authToken":"12312",
          "userToken":"26cea5f746ae4c7fbf7c3a4018b23f28",
          "data":{

          }
        }
        this.http.post('www.centby.com/whole', params).then(
          res => {
            that.treeData = res.data;
            //console.log(JSON.stringify(treeData))
          },
          error => {
            console.log(error.message)
          }
        )
      },
      searchSelect() {
        console.log(this.searchWord);
        let that = this;
        let keyWord = this.searchWord;
        let params = {
          //"requestId":"userToken1574677356105xRx1",
          "authToken":"666",
          "userToken":"666",
          "data":{
            "keyWord": keyWord
          }
        }
        this.http.post('www.centby.com/word', params).then(
          res => {
            console.log(JSON.stringify(res))
            that.treeData = res.data
          },
          error => {
            console.log(error.message)
          }
        )
      },
      handleCheckAllChange(val) {
        let all = JSON.parse(JSON.stringify(this.listId));
        //console.log("all  ===   "+all)
        this.checkedCities = val ? all : [];
        //this.isIndeterminate = false;
        //console.log("list  ===   "+this.checkedCities);
        let that = this;
        let categorys = JSON.parse(JSON.stringify(this.category));
        if(val === true){
          //全部展示
          categorys.forEach(function(item){
            categorys.find(function(s){
              if(s.id === item.id){
                //console.log(s)
                that.selectList = that.selectList.concat([s])
                //放入展示框,并去重
                let k = {};
                that.selectList = that.selectList.reduce(function (subitem, next) {
                  k[next.id] ? '' : k[next.id] = true && subitem.push(next);
                  return subitem;
                }, []);
              }
            })
          })
        }else{
          //取消展示
          categorys.forEach(function(item){
            for(let j = 0;j < that.selectList.length;j++){
              if(that.selectList[j].id === item.id){
                that.selectList.splice(j,1);
              }
            }
          })
        }
        //计算展示框数量
        let j = 0;
        let k = 0;
        that.selectList.forEach(function(item){
          if(item.nodeType == 0){
            j++;
          }else if(item.nodeType == 1){
            k++
          }
        });
        that.frameCount = j;
        that.userCount = k;
      },
      handleCheckedCitiesChange(value) {
        //console.log("sub  ===   "+JSON.stringify(value))
        /*
        //选中 id 列表数据示例
        //checkedCities = [3736461431145987743]
        //选择框数据示例
        category = [
            {
                "id": "3736461431145987660",
                "name": "初中部",
                "nodeType": 0
            },
            {
                "id": "3736461431145987743",
                "name": "小学部",
                "nodeType": 0
            }
        ]
        * * */
        let categorys = this.category;
        console.log("value  === " + this.checkedCities )
        let checkedCount = value.length;
        this.checkAll = checkedCount === this.category.length;
        //this.isIndeterminate = checkedCount > 0 && checkedCount < this.category.length;
        let that = this;
        //console.log('list  = '+this.listId)
        let deepCopy = JSON.stringify(this.listId);
        let unChecked = JSON.parse(deepCopy);
        //选中ID展示
        value.forEach(function (item) {
          //console.log(item)
          //添加到展示框
          categorys.find(function(s){
            if(s.id === item){
              //console.log(s)
              that.selectList = that.selectList.concat([s])
              //放入展示框,并去重
              let k = {};
              that.selectList = that.selectList.reduce(function (subitem, next) {
                k[next.id] ? '' : k[next.id] = true && subitem.push(next);
                return subitem;
              }, []);
            }
          })
          //console.log('uncheck = '+JSON.stringify(unChecked))
          //获取不选中的id
          for(let i = 0;i < unChecked.length;i++){
            // /console.log(item)
            if(unChecked[i] == item){
              unChecked.splice(i,1);
            }
          }
        })
        //console.log('res = '+JSON.stringify(unChecked))
        //把未选中的从展示框删除
        unChecked.forEach(function(item){
          for(let j = 0;j < that.selectList.length;j++){
            if(that.selectList[j].id == item){
              that.selectList.splice(j,1);
            }
          }
        })
        //计算展示框数量
        let j = 0;
        let k = 0;
        that.selectList.forEach(function(item){
          if(item.nodeType == 0){
            j++;
          }else if(item.nodeType == 1){
            k++
          }
        });
        that.frameCount = j;
        that.userCount = k;
      },
      delList(val){
        console.log('del     '+JSON.stringify(val))
        //console.log('forbid  = '+ this.forbid)
        let that = this;
        //let checkedMenu = JSON.parse(JSON.stringify(this.checkedCities));
        let categorys = JSON.parse(JSON.stringify(that.category));
        //第一步先从展示框删除
        for(let j = 0;j < that.selectList.length;j++){
          if(that.selectList[j].id == val){
            that.selectList.splice(j,1);
          }
        }
        let permission = this.forbid;
        if(permission === true){
          //禁止选择状态
          //第二步拿删除当前id后的展示框列表 和 所有树形父级 id 列表对比
          let hasOne = false;
          let parent = JSON.parse(JSON.stringify(that.parentList));
          let showList = JSON.parse(JSON.stringify(that.selectList));
          console.log('after   ==  '+ JSON.stringify(showList))
          console.log('parent   ==  '+ JSON.stringify(parent))
          parent.forEach(function(item){
            showList.forEach(function(show){
              if(show.id == item){
                hasOne = true;
              }
            })
          })
          //没有父级,改变禁选状态为可选,并重新渲染选择框列表
          if(hasOne === false){
            //改变禁选状态为可选
            that.forbid = false;
            //从展示框删除
            for(let j = 0;j < that.selectList.length;j++){
              if(that.selectList[j].id == val){
                that.selectList.splice(j,1);
              }
            }
            //重新渲染选中框
            that.checkAll = false;
            that.checkedCities = [];
            that.selectList.forEach(function (item) {
              //console.log(item)
              categorys.find(function(s){
                if(s.id === item.id){
                  //console.log(s)
                  that.checkedCities.push(item.id)
                  //选中等于当前所有选中框列表全选操作
                  if(that.checkedCities.length == categorys.length){
                    that.checkAll = true;
                  }
                }
              })
            })
          }
        }else{
          //非禁选状态
          //重新渲染选中框
          for(let j = 0;j < that.checkedCities.length;j++){
            if(that.checkedCities[j] == val){
              that.checkedCities.splice(j,1);
              that.checkAll = false;
            }
          }
        }
        //计算展示框数量
        let j = 0;
        let k = 0;
        that.selectList.forEach(function(item){
          if(item.nodeType == 0){
            j++;
          }else if(item.nodeType == 1){
            k++
          }
        });
        that.frameCount = j;
        that.userCount = k;
      },
      handleNodeClick(data) {
        //点击树状列表
        //console.log(data);
        /*
        //选择框数据示例
        {
          "code": 0,
          "message": "调用成功",
          "data": {
              "parentIds": [],
              "nodes": [
                  {
                      "id": "3736461431145987660",
                      "name": "初中部",
                      "nodeType": 0
                  },
                  {
                      "id": "3736461431145987743",
                      "name": "小学部",
                      "nodeType": 0
                  }
              ]
          }
        }

        //选中 id 数据示例
        checkedCities = [3736461431145987743]
        //选择框展示数据示例,展示框数据结构和选择框数据结构相同,选择框选中的列表为数组结构 id 列表
        category = [
            {
                "id": "3736461431145987660",
                "name": "初中部",
                "nodeType": 0
            },
            {
                "id": "3736461431145987743",
                "name": "小学部",
                "nodeType": 0
            }
        ]
        * * */
        let that = this;
        let idx = data.id;
        let types = data.orgType;
        let params = {
          //"requestId":"userToken1574677356105xRx1",
          "authToken":"666",
          "userToken":"666",
          "data":{
            "orgId": idx,
            "orgType": types
          }
        }
        this.http.post('www.centby.com/info', params).then(
          res => {
            //console.log(res)
            that.category = res.data.nodes;
            //提取所有ID并保存
            let arr = [];
            that.category.forEach(function(item){
              //console.log(item.id)
              arr.push(item.id)
            });
            that.listId = arr;
            //所有id保存,that.listId = ['3736461431145987600','3736461431145987601','3736461431145987602'];
            //初始化并保存当前所有树形父级 id 列表包含自己,展示框删除操作会调用此数据
            that.parentList = JSON.parse(JSON.stringify(res.data.parentIds));
            console.log('parent   =  '+ JSON.stringify(that.parentList));
            //初始化禁选判断,禁选,全选按钮,已选中
            let permission = false;
            that.forbid = false;
            that.checkAll = false;
            that.checkedCities = [];
            //使用JSON转换解决深拷贝问题
            let parent = JSON.parse(JSON.stringify(that.parentList));
            let showList = JSON.parse(JSON.stringify(that.selectList));
            //每次点击树状列表,拿当前所有树形父级 id 列表(parentIds)包含自己,和展示框列表 id 对比,如果有,选择框展示全部全选并且禁止状态
            //展示框删除动作,会取此禁选状态做展示框删除动作
            parent.forEach(function(item){
              showList.forEach(function(show){
                if(show.id == item){
                  permission = true;
                }
              })
            })
            if(permission == true){
              //禁止选择操作
              that.checkedCities = that.listId;
              that.checkAll = true;
              that.forbid = true;
              // that.selectList.forEach(function (item) {
              //   if(item.id == idx){
              //     that.checkedCities = that.listId;
              //     that.checkAll = true;
              //     that.forbid = true;
              //   }
              // })
            }else{
              //不禁止状态回显渲染
              that.selectList.forEach(function (item) {
                //console.log(item)
                that.category.find(function(s){
                  if(s.id === item.id){
                    //console.log(s)
                    that.checkedCities.push(item.id)
                    //选中等于当前所有选中框列表全选操作
                    if(that.checkedCities.length == that.listId.length){
                      that.checkAll = true;
                    }
                  }
                })
              })
            }

          },
          error => {
            console.log(error.message)
          }
        )
      },
    }
  }
</script>

<style scoped lang="scss">
  .box >>> .el-checkbox {
    display: block;
  }
  .chosen-modal {
    display: flex;
    height: 598px;
    padding: 15px;
    border-top: 1px solid #eee;
    border-bottom: 1px solid #eee;
  }
  .chosen-modal-left {
    width: 430px;
  }
  .chosen-modal-hd {
    padding: 20px;
    display: flex;
    border-top: 1px solid #dddee1;
    border-right: 1px solid #dddee1;
    border-left: 1px solid #dddee1;
  }
  .chosen-modal-hd .chosen-modal-hd-search {
    position: relative;
    flex: 1;
  }
  .chosen-modal-hd .chosen-modal-hd-search i {
    width: 32px;
    height: 32px;
    line-height: 32px;
    font-size: 16px;
    text-align: center;
    color: #80848f;
    position: absolute;
    right: 0;
    z-index: 1;
    cursor: pointer;
  }
  .aui-input {
    display: inline-block;
    width: 100%;
    height: 32px;
    line-height: 1.5;
    padding: 4px 32px 4px 7px;
    box-sizing: border-box;
    font-size: 12px;
    border: 1px solid #dddee1;
    border-radius: 4px;
    color: #6e7d8f;
    background-color: #fff;
    background-image: none;
    position: relative;
    cursor: text;
    transition: border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out;
  }
  .chosen-modal-bd {
    display: flex;
    height: 526px;
    border: 1px solid #dddee1;
  }
  .chosen-left {
    margin-top: -1px;
    width: 200px;
    min-width: 200px;
    height: 525px;
    overflow-y: auto;
    position: absolute;
    background: #fff;
    z-index: 2;
    overflow-x: hidden;
    border-top: 1px solid #dddee1;
    border-right: 1px solid #dddee1;
  }
  .chosen-left-device {
    margin-top: -1px;
    width: 200px;
    min-width: 200px;
    height: 525px;
    overflow-y: auto;
    position: absolute;
    background: #fff;
    z-index: 2;
    overflow-x: hidden;
    border-top: 1px solid #dddee1;
  }
  .chosen-right {
    flex: 1;
    padding-left: 200px;
    z-index: 1;
    overflow-y: scroll;
  }
  .chosen-right .el-checkbox {
    padding: 10px 15px;
    color: #0cb181;
  }
  .aui-checkbox-label {
    align-items: center;
    width: 100%;
    white-space: normal;
    word-wrap: break-word;
    word-break: break-all;
    margin-bottom: 0;
    line-height: 1.3;
  }
  .chosen-modal-right {
    flex: 1;
    border: 1px solid #dddee1;
    margin-left: 20px;
  }
  .chosen-modal-right-hd {
    padding: 20px;
  }
  .chosen-modal-right-bd {
    height: 538px;
    overflow: auto;
  }
  .chosen-person-org {
    display: flex;
    padding: 6px 20px;
    height: 20px;
    align-items: center;
  }
  .chosen-modal-right-bd>div>i {
    font-size: 12px;
    color: #0cb181;
    margin-right: 5px;
    align-self: baseline;
    position: relative;
    top: 6px;
  }
  .chosen-modal-right-bd>div>span {
    flex: 1;
    word-wrap: break-word;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    word-break: break-all;
    overflow: hidden;
  }

</style>

网友评论

登录后评论
0/500
评论
佀无极
+ 关注
所属团队号: 前端那些事儿