el-tree封装穿梭框组件

98 阅读3分钟

image.png 这个组件是选择人员,部门不能选择,选择的人员在右边展示,删除右边的人员时,左边的复选框也要同同时取消掉,点击确认的时候,把所有数据重新组装成一维数组传给后端,代码如下

<template>
  <el-dialog
    :visible.sync="selectDepartmentShow"
    :before-close="cancel"
    :title="title"
    width="600px"
  >
    <div class="center">
      <!-- 左边选择部门 -->
      <div class="department-left-content">
        <!-- <div class="tip-title">人员</div> -->
        <el-input placeholder="请输入" v-model="filterText">
          <i slot="prefix" class="el-input__icon el-icon-search"></i>
        </el-input>
        <el-tree
          :data="treeData"
          show-checkbox
          node-key="id"
          ref="tree"
          :props="defaultProps"
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          @check="handleTreeNodeClick"
          @node-click="onNodeClick"
        >
          <div class="custom-tree-node" slot-scope="{ node, data }">
            <div>{{ node.label }}</div>
            <div class="tree-right-icon">
              <!-- 4人 -->
              <svg
                t="1700029922321"
                class="icon"
                viewBox="0 0 1024 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="3297"
                width="9"
                height="12"
              >
                <path
                  d="M413.44 797.44l-58.88-58.816 226.56-226.56-226.56-226.56 58.88-58.88 285.376 285.44-285.44 285.44z"
                  fill="#999999"
                  p-id="3298"
                ></path>
              </svg>
            </div>
          </div>
        </el-tree>
      </div>
      <!-- 右边显示部门 -->
      <div class="department-right-content">
        <div class="choosed-info">
          <div class="choosed-num">
            <span>已选:</span>
           {{type === 'lecturerSetting'?'人员'+computedPersonnel+'个':''}}
          </div>
          <div class="delete-choosed-node">
            <el-button type="text" @click="deleteChoosedNode">清除</el-button>
          </div>
        </div>
        <div class="choosed-content">
          <div
            class="item-content"
            v-for="(item, index) in choosedTreeNode"
            :key="index"
          >
            <div class="item-name">{{ item.name }}</div>
            <div class="item-num">
              <!-- <span> 4人</span> -->
              <svg
              @click="deleteNode(item)"
                t="1700041639592"
                class="icon"
                viewBox="0 0 1024 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="3431"
                width="8"
                height="8"
              >
                <path
                  d="M512 432.512L865.92 78.464a56.192 56.192 0 1 1 79.616 79.616L591.36 512l353.92 353.92a56.064 56.064 0 0 1-61.312 91.776 56.192 56.192 0 0 1-18.176-12.16L512 591.36 158.08 945.536a56.192 56.192 0 1 1-79.488-79.616L432.512 512 78.464 158.08a56.192 56.192 0 1 1 79.616-79.488L512 432.512z"
                  fill="#bfbfbf"
                  p-id="3432"
                ></path>
              </svg>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div slot="footer">
      <el-button @click="cancel">取消</el-button>
      <el-button type="primary" @click="submitHandle()">确认</el-button>
    </div>
  </el-dialog>
</template>
<script>
import { getDartmentApi } from '@/api/api'
export default {
  props: {
    selectDepartmentShow: {
      type: Boolean,
      default: true
    },
    type: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: ''
    },
    readio: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      treeData: [],
      choosedTreeNode: [], // 给后端的数据
      dataForm: {
        name: 123
      },
      filterText: '',
      currentNodeId: '',
      defaultProps: {
        children: 'childList',
        label: 'name',
        disabled: 'isDepartment'
      },
      newTreeData: []
    }
  },
  created () {
    this.getDepartmentData()
  },
  watch: {
    filterText (val) {
      console.log(val)
      this.$refs.tree.filter(val)
    }
  },
  computed: {
    computedPersonnel () {
      // 选择的人员
      let arr = []
      arr = JSON.parse(JSON.stringify(this.getCheckTag(this.choosedTreeNode))).filter(item => !item.isDepartment)

      return arr.length
    }
  },
  methods: {

    cancel () {
      this.$parent.selectDepartmentShow = false
    },
    getDepartmentData () {
      getDartmentApi({
        isEnable: 1
      }).then((res) => {
        this.treeData = res.data
      })
    },
    submitHandle () {
      // 找所有人员
      if (this.type === 'lecturerSetting') {
          //所有选择的数据
        this.newTreeData = JSON.parse(JSON.stringify(this.getCheckTag(this.choosedTreeNode)))
      }
      this.$emit('submitHandle', this.newTreeData)
    },
    getCheckTag (list, newNodeId = []) {
    //查找所有子级
      for (const i in list) {
        newNodeId.push(list[i])
        if (list[i].childList) {
          this.getCheckTag(list[i].childList, newNodeId)
        }
      }
      return newNodeId
    },
    deleteChoosedNode () {
      // 清除已选内容
      this.$refs.tree.setCheckedKeys([])
      this.choosedTreeNode = []
    },
    deleteNode (item) {
      // 删除节点
      this.choosedTreeNode.forEach((V, index) => {
        if (V.id === item.id) {
        //这个是删除右边选中的数据
          this.choosedTreeNode.splice(index, 1)
          //这个是el-tree取消复选框的方法
          this.$refs.tree.setChecked(item, false, false)
        }
      })
    },
    filterNode (value, data) {
      // 过滤,搜索
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    onNodeClick (edata, node, obj) {},
    handleTreeNodeClick (edata, node, obj) {
      // 选择树形复选框
      console.log(node, obj, '=======')
      if (this.readio === 'readio') {
        // 单选
        this.$refs.tree.setCheckedKeys([])
        this.$refs.tree.setCheckedNodes([edata])
        this.choosedTreeNode = [JSON.parse(JSON.stringify(edata))]
      } else {
        if (node.checkedKeys.includes(edata.id)) {
          this.choosedTreeNode.push(JSON.parse(JSON.stringify(edata)))
        } else {
          for (let i = 0; i < this.choosedTreeNode.length; i++) {
            if (!node.checkedKeys.includes(this.choosedTreeNode[i].id)) {
              this.choosedTreeNode.splice(i, 1)
            }
          }
        }
      }
    }
  }
}
</script>
<style lang="scss" scoped>
/deep/.el-dialog__body {
  padding: 0px !important;
  max-height: 500px;
  overflow: auto;
}
.header-title {
  display: flex;
  align-items: center;
  svg {
    margin-right: 8px;
  }
}
.center {
  display: flex;
  align-items: baseline;
  .department-left-content {
    flex: 1;
    border-right: 1px solid #f3f3f3;
    padding: 16px 20px;
    .tip-title {
      font-size: 14px;
      color: rgba(0, 0, 0, 0.9);
      margin-bottom: 8px;
    }
    .breadcrumb {
      margin-top: 16px;
      background: rgba(51, 51, 51, 0.04);
      border-radius: 0px 0px 0px 0px;
      padding: 3px 8px 0 8px;
      margin-bottom: 10px;
      /deep/ .el-breadcrumb__item {
        margin-bottom: 8px;
      }
    }
    .breadcrumb-ul {
      display: flex; /* 将子元素横向排列 */
      flex-wrap: wrap;
      align-items: center;
      .breadcrumb-item {
        margin-right: 5px;
        margin-bottom: 5px;
        font-size: 14px;
      }
    }
    .custom-tree-node {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
    }
  }
  .department-right-content {
    flex: 1;
    padding: 16px 20px;
    .choosed-info {
      display: flex;
      align-items: center;
      justify-content: space-between;
      .choosed-num {
        color: #000000;
        font-size: 14px;
        span {
          color: #666666;
        }
      }
    }
    .choosed-content {
      .item-content {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-top: 10px;
        .item-num {
          display: flex;
          align-items: center;
          span {
            margin-right: 8px;
          }
        }
      }
    }
  }
}

.active {
  color: #0089ff;
}
.default {
  color: #666666;
}
/deep/.myCell .el-checkbox__input {
  display: none !important;
}
</style>

父组件的接收

//组件
 <SelectPersonnel
      v-if="selectDepartmentShow"
      :selectDepartmentShow="selectDepartmentShow"
      @submitHandle="_submitHandle"
      type="lecturerSetting"
      title="选择人员"
    />
//data数据
 selectDepartmentShow: false
 //方法
     _submitHandle (arr) {
     //子组件选择的数据,都是一维数据,重新组装传给后端
      const submitArr = []
      arr.forEach(item => {
        if (!item.isDepartment) {
          submitArr.push({
            employeeId: item.id,
            employeeName: item.name
          })
        }
      })
      }