src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue
@@ -1,17 +1,44 @@
<template>
  <a-spin :spinning="spinning">
    <a-transfer
      class="transfer-container"
      class="tree-transfer"
      :data-source="dataSource"
      show-search
      :list-style="{flex:1,height: '500px'}"
      :titles="['未分配部门', '已分配部门']"
      :operations="['分配部门', '移除部门']"
      :target-keys="targetKeys"
      :render="item => `${item.departName}`"
      :render="item => `${item.title}`"
      @change="handleChange"
      :rowKey="record => record.departId"
      @search="handleSearch"
    >
      <template slot="children" slot-scope="{ props: { direction, selectedKeys }, on: { itemSelect } }">
        <a-tree
          v-if="direction === 'left'"
          blockNode
          checkable
          checkStrictly
          :expandedKeys="expandedKeys"
          :autoExpandParent="autoExpandParent"
          @expand="handleTreeNodeExpand"
          :checkedKeys="[...selectedKeys, ...targetKeys]"
          :treeData="treeData"
          @check="(_, props) => {onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelect);}"
          @select="(_, props) => {onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelect); }">
          <template slot="title" slot-scope="{title}">
                     <span v-if="title.indexOf(searchValue) > -1">{{ title.substr(0, title.indexOf(searchValue)) }}<span
                       class="replaceSearch">{{ searchValue }}</span>{{ title.substr(title.indexOf(searchValue) + searchValue.length) }}</span>
            <span v-else>{{ title }}</span>
          </template>
        </a-tree>
      </template>
      <template slot="footer" slot-scope="{direction}" v-if="direction==='left'">
        <a-button type="primary" style="float:right;margin: 5px;margin-right: 10px"
                  @click="isExpandAllTreeNode=!isExpandAllTreeNode">
          展开/折叠
        </a-button>
      </template>
      <span slot="notFoundContent">暂无数据</span>
    </a-transfer>
@@ -21,6 +48,8 @@
<script>
  import dncApi from '@/api/dnc'
  const transferDataSource = []
  export default {
    name: 'DepartPermissionTransfer',
    components: {},
@@ -28,7 +57,10 @@
      currentTreeNodeInfo: {
        type: Object
      },
      dataSource: {
      allTreeKeys: {
        type: Array
      },
      treeDataProps: {
        type: Array
      },
      isAssignSonNode: {
@@ -38,15 +70,65 @@
    data() {
      return {
        targetKeys: [],
        spinning: false
        spinning: false,
        isExpandAllTreeNode: true,
        searchValue: '',
        expandedKeys: [],
        autoExpandParent: true,
        dataSource: transferDataSource
      }
    },
    watch: {
      isExpandAllTreeNode: {
        handler(value) {
          if (value) this.expandedKeys = this.allTreeKeys
          else this.expandedKeys = []
        }
      }
    },
    computed: {
      treeData() {
        return this.handleTreeData(this.treeDataProps, this.targetKeys)
      }
    },
    methods: {
      // 调用接口获取有权限的部门列表
      getHasPermissionDepartByApi() {
        const that = this
        that.spinning = true
        dncApi.getHasPermissionDepartApi(this.currentTreeNodeInfo)
          .then(res => {
            if (res.success) this.targetKeys = res.list.map(item => item.departId)
            if (res.success) this.targetKeys = res.list.map(item => item.id)
          })
          .finally(() => {
            that.spinning = false
          })
      },
      /**
       * 穿梭框搜索框输入时触发
       * @param direction 穿梭框的左右 "left"||"right"
       * @param value 输入值
       */
      handleSearch(direction, value) {
        if (direction === 'left') {
          let search = value
          let expandedKeys = transferDataSource
            .map(item => {
              if (item.title != null) {
                if (item.title.indexOf(search) > -1) {
                  return this.getParentKey(item.key, this.treeDataProps)
                }
                return null
              }
            })
            .filter((item, i, self) => item && self.indexOf(item) === i)
          Object.assign(this, {
            expandedKeys,
            searchValue: search,
            autoExpandParent: true
          })
        }
      },
      handleChange(targetKeys, direction, moveKeys) {
@@ -91,14 +173,92 @@
          .finally(() => {
            that.spinning = false
          })
      },
      onChecked(_, e, checkedKeys, itemSelect) {
        const { eventKey } = e.node
        itemSelect(eventKey, !this.isChecked(checkedKeys, eventKey))
      },
      handleTreeData(data, targetKeys = []) {
        data.forEach(item => {
          item['disabled'] = targetKeys.includes(item.key)
          if (item.children) {
            this.handleTreeData(item.children, targetKeys)
          }
        })
        return data
      },
      handleTreeNodeExpand(expandedKeys) {
        this.expandedKeys = expandedKeys
        this.autoExpandParent = false
      },
      /**
       * 递归获得输入项的父级key
       * @param key 子项key
       * @param tree 子项
       */
      getParentKey(key, tree) {
        let parentKey
        for (let i = 0; i < tree.length; i++) {
          const node = tree[i]
          if (node.children) {
            if (node.children.some(item => item.key === key)) {
              parentKey = node.key
            } else if (
              this.getParentKey(key, node.children)) {
              parentKey = this.getParentKey(key, node.children)
            }
          }
        }
        return parentKey
      },
      isChecked(selectedKeys, eventKey) {
        return selectedKeys.indexOf(eventKey) !== -1
      },
      flatten(list = []) {
        list.forEach(item => {
          transferDataSource.push(item)
          if (item.children) {
            this.flatten(item.children)
          }
        })
      }
    }
  }
</script>
<style scoped lang="less">
  .transfer-container {
  .tree-transfer {
    display: flex;
    align-items: center;
    ::-webkit-scrollbar {
      width: 8px;
    }
  }
  .tree-transfer .ant-transfer-list .ant-transfer-list-body {
    display: flex;
    flex-direction: column;
  }
  /deep/ .ant-transfer-list-body {
    display: flex;
    flex-direction: column;
    .ant-transfer-list-body-customize-wrapper {
      flex: 1;
      overflow: auto;
    }
  }
  .replaceSearch {
    color: #40a9ff;
    font-weight: bold;
    background-color: rgb(204, 204, 204);
  }
</style>