使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

伍华聪   2021-04-20 我要评论

最近在改造原有Bootstrap开发框架,增加一个Vue&Element前端的时候,发现需要处理一个级联更新的过程,就是选择公司,然后更新部门,选择部门,或者人员列表,选择作为主管的一个实现,不同于Bootstrap使用Select2的插件,这里前端是Vue&Element,那么我们可以选择下拉列表的方式展现,在Element中可以考虑使用Cascader 级联选择器,也可以考虑使用封装Tree 树形控件,或者使用第三方组件Vue-TreeSelect组件。本篇随笔介绍使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理过程。

1、Vue-TreeSelect组件的使用

在我早期随笔《循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用》中也大概介绍了一下Vue-TreeSelect组件,这里我们再来回顾一下它的用法。

GitHub地址:https://github.com/riophae/vue-treeselect

官网地址:https://vue-treeselect.js.org/

NPM安装:

npm install --save @riophae/vue-treeselect

界面代码如下所示。

<template>
  <div id="app">
    <treeselect v-model="value" :multiple="true" :options="options" />
  </div>
</template>

这里的value就是选中的集合,options则是树列表的节点数据,和Element中的Tree组件一样,options的格式也包含id, lable, children这几个属性。

如果常规的数据提供,我们只要准备这些数据格式给options即可。

如下面的数据格式。

      treedata: [// 初始化树列表
        { // 默认数据
          label: '一级 1',
          children: [{
            label: '二级 1-1'
          }]
        }
      ]

不过我们一般数据是动态从后端接口中提取的,不是静态的,所以需要使用相应的方法来获取,并设置。

如果是后端接口无法满足特定的属性名称,那么Vue-TreeSelect组件也提供了一个 normalizer 属性方法用来重定义节点属性名称

 类似下面的javascript代码

export default {
  data: () => ({
    value: null,
    options: [ {
      key: 'a',
      name: 'a',
      subOptions: [ {
        key: 'aa',
        name: 'aa',
      } ],
    } ],
    normalizer(node) {
      return {
        id: node.key,
        label: node.name,
        children: node.subOptions,
      }
    },
  }),
}

通过normalizer 属性方法可以把数据源的属性映射到树列表中去。有时候我们对于空列表,可能还需要判断为空,并移除这个属性,代码如下所示。

  normalizer (node) {
    if (node.children && !node.children.length) {
      delete node.children
    }
    return {
      id: node.key,
      label: node.name,
      children: node.children,
    }
  },

另外,有时候需要在列表值变化的时候,触发级联更新,那么就需要处理@input事件了。

  <treeselect
    :options="options"
    :value="value"
    :searchable="false"
    @input="updateValue"
    />

 

2、公司-部门-人员级联下拉列表的处理

综合上面的几个特点,我们公司-部门-人员级联下拉列表的处理就需要上面的知识点来处理。

 在上面的弹出对话框中,选择所属公司,默认部门,所属经理的操作,级联处理过程效果如下所示。

 界面代码如下所示

  <el-col :span="12">
    <el-form-item label="所属公司" prop="company_ID">
      <treeselect :options="myGroupCompany" v-model="addForm.company_ID" :searchable="false"
        :default-expand-level="Infinity" :open-on-click="true" :open-on-focus="true"
        @input="updateGroupCompany" placeholder="所属公司" />
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="默认部门" prop="dept_ID">
      <treeselect :options="myDeptTree" v-model="addForm.dept_ID" :searchable="false"
        :default-expand-level="Infinity" :open-on-click="true" :open-on-focus="true" @input="updateDeptUser"
        :normalizer="normalizer" placeholder="所属部门" />
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="所属经理" prop="pid">
      <treeselect :options="myDeptUser" v-model="addForm.pid" :searchable="false"
        :default-expand-level="Infinity" :open-on-click="true" :open-on-focus="true"
        :normalizer="normalizer" placeholder="所属经理" />
    </el-form-item>
  </el-col>

如第一项公司列表,我们获取列表后设置options的对象即可。这里面需要定义几个变量 myGroupCompany、myDeptTree、myDeptUser的集合属性。

这里保留了normalizer 映射新属性的做法,不过由于属性名称默认和树控件的属性一致,也可以省略。

在其中更新处理,用到了 @input="updateGroupCompany" 、@input="updateDeptUser" 用于触发更新其他关联内容的事件。

另外一点,我们的新增或者编辑框中v-modal中关联的值,需要设置为null即可。

  addForm: {// 新建表单
    id: '',
    pid: null,
    dept_ID: null,
    company_ID: null,
    ................
  },

在显示弹出对话框,打开新增用户的时候,需要触发获取公司信息列表,如下所示。

    showAdd () {
      this.resetForm('addForm')
      this.initData() //打开新增窗体的时候,初始化公司列表
      this.isAdd = true
    },

而其中initData的函数操作如下所示。

    async initData () {
      var param = {}
      await ou.GetMyGroupCompany(param).then(data => {
        console.log(data.result)
        var newTreedata = getJsonTree(data.result, {
          id: 'id',
          pid: 'pid',
          children: 'children',
          label: 'name'
        });
        this.myGroupCompany = newTreedata
      })
    },

这里调用ou的api进行获取公司信息的操作

import request from '@/utils/request'

import BaseApi from '@/api/base-api'
// 业务类自定义接口实现, 通用的接口已经在BaseApi中定义
class Api extends BaseApi {
  // 获取集团公司列表。如果是超级管理员,返回集团+公司节点;如果是公司管理员,返回其公司节点
  GetMyGroupCompany(data) {
    return request({
      url: this.baseurl + 'GetMyGroupCompany',
      method: 'get',
      params: data
    })
  }    
  ..........
}

而公司信息触发部门更新,我们用如下函数来处理变化。

    async updateGroupCompany (value, instanceId) {
      // console.log(value + '~' + instanceId)

      this.addForm.dept_ID = null //置空控件内容
      if (!this.isEmpty(value)) {
        var param = { parentId: value }
        await user.GetDeptJsTreeJson(param).then(data => {
          this.myDeptTree = data.result
        })
      }
    },

由于User的API中 GetDeptJsTreeJson返回的是符合树控件节点属性名称的,因此可以直接赋值给vue-TreeSelect的opition值。

<treeselect :options="myDeptTree" v-model="addForm.dept_ID" :searchable="false"
   :default-expand-level="Infinity" :open-on-click="true" :open-on-focus="true" @input="updateDeptUser"
   :normalizer="normalizer" placeholder="所属部门" />

而部门选择后,则触发部门用户列表的更新,如下代码所示。

    async updateDeptUser (value, instanceId) {
      // console.log(value + '~' + instanceId)
      this.addForm.pid = null //置空控件内容
      if (!this.isEmpty(value)) {
        var param = { deptId: value }
        await user.GetUserDictJson(param).then(data => {
          this.myDeptUser = data.result
        })
      }
    },

同样,由于由于User的API中 GetUserDictJson 返回的是符合树控件节点属性名称的,因此可以直接赋值给vue-TreeSelect的opition值。

<treeselect :options="myDeptUser" v-model="addForm.pid" :searchable="false"
   :default-expand-level="Infinity" :open-on-click="true" :open-on-focus="true"
   :normalizer="normalizer" placeholder="所属经理" />

3、特殊处理的内容

 前面我们介绍了,如果获取内容和树控件的属性不一致,需要进行转义映射,如下代码所示。

      normalizer (node) {
        if (node.children && !node.children.length) {
          delete node.children
        }
        return {
          id: node.id,
          label: node.label,
          children: node.children,
        }
      },

并在界面代码上指定normalizer处理。

:normalizer="normalizer"

有时候,我们返回的对象集合可能是一个二维列表内容,它本身有id,pid来标识它的层次关系,那么如果我们转换为嵌套列表的话,就可以使用getJsonTree 方法进行转换。

具体操作可以参考:https://blog.csdn.net/unamattin/article/details/77152451 

使用的时候,导入这个类方法即可。

import { getJsonTree } from '@/utils/json-tree.js' // 转换二维表数据为树列表数据的辅助类

如果前面介绍的

    async initData () {
      var param = {}
      await ou.GetMyGroupCompany(param).then(data => {
        console.log(data.result)
        var newTreedata = getJsonTree(data.result, {
          id: 'id',
          pid: 'pid',
          children: 'children',
          label: 'name'
        });
        this.myGroupCompany = newTreedata
      })
    },

如果两个都是嵌套结构的树列表,但是属性名称不同,那么也可以通过map的操作方法,定义一个js函数进行转换即可,转换的代码如下所示。

    getTree () { // 树列表数据获取
      var param = {}
      user.GetMyDeptJsTreeJson(param).then(data => {
        // console.log(data)
        this.treedata = [];// 树列表清空
        var list = data.result
        if (list) {
          this.treedata = list
        }

        //修改另一个Treedata
        const ass = (data) => {
          let item = [];
          data.map((list, i) => {
            let newData = {};
            newData.id = list.id;
            newData.label = list.label;
            newData.children = list.children ? ass(list.children) : null;    //如果还有子集,就再次调用自己
            //如果列表为空,则移除children
            if (list.children && !list.children.length) {
              delete newData.children;
            }
            item.push(newData);
          });
          return item;
        }
        this.selectTreeData = ass(list)
      });
    },

以上就是数据层次结构相同,属性名称不同的时候,进行转换处理的另外一种方式。

当然,我们定义返回列表数据的时候,如果需要用来绑定在树列表中的,也可以在后端WebAPI进行定义好符合格式的数据,避免在前端额外的代码转换。

        /// <summary>
        /// 根据用户获取对应人员层次(给树控件显示的下拉列表)(值为ID)
        /// </summary>
        /// <param name="deptId">用户所在部门</param>
        /// <returns></returns>
        public List<TreeNodeItem> GetUserDictJson(int deptId)
        {
            var itemList = new List<TreeNodeItem>();
            itemList.Insert(0, new TreeNodeItem("-1", "无"));

            var list = BLLFactory<User>.Instance.FindByDept(deptId);
            foreach (var info in list)
            {
                itemList.Add(new TreeNodeItem(info.ID, info.FullName));
            }

            return itemList;
        }

其中 TreeNodeItem 类定义了Id, Label,Children的属性,这样前端就可以直接绑定使用了。

 

 以上就是前后端树列表的绑定处理,以及使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的功能操作,希望大家不吝赐教。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们