奇葩小需求:选择任意用户时,要同步选中其他租户下的用户(vue-Treeselect)

664 阅读1分钟

先说一下需求吧。因为所作系统存在多租户的情况,一个用户可能属于不同租户,所有选择任意一个用户时,要求选中所有不同租户下的全部相同用户,并且在选择框内只展示一个用户。如下图效果:

image.png

使用组件是 treeSelect,实现思路是:当选择时遍历数据,选中所有相同 userId 的数据,取消选中亦是。 难点在于如何在输入框只展示一条。找了半天文档没找到,最终通过操作节点,隐藏节点实现。具体代码如下:

<template>
  <div id="app">
    <treeselect :value="value" :multiple="true" style="width: 300px" :default-expand-level="3" :options="options"
                :normalizer="normalizer" @select="select" @deselect="deselect">
      <div slot="value-label" slot-scope="{ node }">{{ node.raw.userName }}<span class="user-div">{{node.raw.userId}}</span></div>
    </treeselect>
  </div>
</template>

<script>
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'

const OPTIONS = [
  {
    userId: 'all',
    userName: '全选',
    children: [
      {
        id: 'tenant1',
        tenantName: '钻石集团',
        children: [{
          userId: 'admin001',
          tenantId: 'tenant1',
          userName: '租户1'
        }, {
          userId: 'admin002',
          tenantId: 'tenant1',
          userName: '租户2'
        }]
      }, {
        id: 'tenant2',
        tenantName: '铂金集团',
        children: [{
          userId: 'admin001',
          tenantId: 'tenant2',
          userName: '租户1'
        }, {
          userId: 'admin003',
          tenantId: 'tenant2',
          userName: '租户3'
        }, {
          userId: 'admin004',
          tenantId: 'tenant2',
          userName: '租户4'
        }]
      }, {
        id: 'tenant3',
        tenantName: '黄金集团',
        children: [{
          userId: 'admin001',
          tenantId: 'tenant3',
          userName: '租户1'
        }, {
          userId: 'admin005',
          tenantId: 'tenant3',
          userName: '租户5'
        }]
      }
    ]
  }
]
export default {
  components: {Treeselect},
  data () {
    return {
      value: [],
      options: [],
      allList: [],
      normalizer (node) {
        if (node.id) {
          node.userId = node.id
          node.userName = node.tenantName
        }
        return {
          id: `${node.userId}${node.tenantId ? (';' + node.tenantId) : ''}`,
          label: node.userName,
          children: node.children
        }
      }
    }
  },
  methods: {
    /**
     * 选中节点
     * @param node
     */
    select (node) {
      if (node.userId === 'all') {
        this.value = this.allList.map(el => `${el.userId};${el.tenantId}`)
      } else if (node.id && node.children) {
        let users = []
        node.children.forEach(item => {
          let info = this.allList.filter(el => el.userId === item.userId).map(el => `${el.userId};${el.tenantId}`)
          users = [...users, ...info]
        })
        this.value = Array.from(new Set([...this.value, ...users]))
      } else {
        let users = this.allList.filter(el => el.userId === node.userId).map(el => `${el.userId};${el.tenantId}`)
        this.value = [...this.value, ...users]
      }
      this.$nextTick(() => {
        let userIds = []
        let nodes = document.getElementsByClassName('vue-treeselect__multi-value-item-container')
        for (let item of nodes) {
          let info = item.getElementsByClassName('user-div')
          let userId = info[0].innerHTML
          if (userIds.includes(userId)) {
            item.style.display = 'none'
          } else {
            userIds.push(userId)
          }
        }
      })
    },
    /**
     * 取消选中
     * @param node
     */
    deselect (node) {
      if (node.userId === 'all') {
        this.value = []
      } else if (node.id && node.children) {
        node.children.forEach(item => {
          this.value = this.value.filter(el => !el.includes(item.userId))
        })
      } else {
        this.value = this.value.filter(el => !el.includes(node.userId))
      }
    }
  },
  created () {
    this.options = OPTIONS
    this.allList = []
    OPTIONS[0].children.forEach(item => {
      this.allList = [...this.allList, ...item.children]
    })
  }
}
</script>

<style scoped>
.user-div{
  display: none;
}
</style>