最近在改造原有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组件实现公司-部门-人员级联下拉列表的功能操作,希望大家不吝赐教。

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

  1. ERP-非财务人员的财务培训教(四)------公司/部门的成本与费用控制

    一.损益表.资产负责表 二.成本分类 ----成本习性 三.成本核算模式 四.成本控制原则 第四部分 公司/部门的成本与费用控制   一.损益表.资产负责表   项目 Items 产品销售收入 Sal ...

  2. ERP-非财务人员的财务培训教(三)------公司/部门预算编制与评价

    一.预算管理中的行为问题 二.编制预算中的问题 三.经营计划与预算制度                第一节 经营目标      第二节 预算编制的内容及说明      第三节 推行预算制度的组织 第 ...

  3. 为公司架构一套高质量的 Vue UI 组件库

    有没有曾遇过,产品要我们实现一个功能,但是 iview 或者 elementui 不支持,我们然后义正言辞的说,不好意思,组件库不支持,没法做到. 有没有曾和设计师争论得面红耳赤,其实也是因为组件库暂 ...

  4. ERP-非财务人员的财务培训教(二)------如何评价公司/部门经营业绩

    一.财务比率分析 第一节  流动性比率 第二节  经营比率 第三节  资本结构比率 第四节  获利能力比率 第五节  现金流量比率 第六节  获现能力比率 二.财务比率金字塔 第二部分   如何评价公 ...

  5. 16款优秀的Vue UI组件库推荐

    16款优秀的Vue UI组件库推荐 Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基 ...

  6. 自定义Vue&Element组件,实现用户选择和显示

    在我们很多前端业务开发中,往往为了方便,都需要自定义一些用户组件,一个是减少单一页面的代码,提高维护效率:二个也是方便重用.本篇随笔介绍在任务管理操作中,使用自定义Vue&Element组件, ...

  7. 如何抽象一个 Vue 公共组件

    之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...

  8. 2、公司部门的组成 - CEO之公司管理经验谈

    今天讲讲公司部门的组成.公司部门一般是根据公司业务来进行划分的,IT企业和其它企业的部门划分有一定的区别.企业部门的划分还是比较重要的,部门主要明确各部门所具有的自己的职责.这里对IT企业的部门做了一 ...

  9. vue 同一个组件的跳转, 返回时保留原来的下拉位置

    1,需求分析 公司的项目有这样一个需求: 同一个list组件,根据传过来的listId渲染成多个页面,每个页面都可以下拉.在返回到不同的list页面时,要保留当时下拉的位置. 说的我自己都有点懵逼了, ...

随机推荐

  1. 【python接口自动化】- 正则用例参数化

    ​ 我们在做接口自动化的时候,处理接口依赖的相关数据时,通常会使用正则表达式来进行提取相关的数据. ​ 正则表达式,又称正规表示式.正规表示法.正规表达式.规则表达式.常规表示法(Regular Ex ...

  2. 将项目加载到tomcat中的时候报错:Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 Web modules

    转自:http://jingwang0523.blog.163.com/blog/static/9090710320113294551497/ 最近在用eclipse做项目,新建项目时什么都贪新,用最 ...

  3. 【Notes_9】现代图形学入门——光线追踪(基本原理)

    跟着闫令琪老师的课程学习,总结自己学习到的知识点 课程网址GAMES101 B站课程地址GAMES101 课程资料百度网盘[提取码:0000] 目录 光线追踪 为什么要光线追踪 soft shadow ...

  4. 小白养成记——Linux中的用户和权限管理

    1.用户组管理 每个用户都属于一个用户组,系统可以对一个用户组中的所有用户进行集中管理. 在创建用户时,如果未指定组,则系统会创建一个与用户名同名的组. 以下是关于用户组管理的一些基本命令: 新建用户 ...

  5. 用Python来控制Autocad的打印------以Pycomcad为例

    from pycomcad import * #以pycomcad作为接口库为例 import win32com acad=Autocad() 打印最重要的设置都在上面的界面中,下面对这些个界面,用P ...

  6. Linux安装jdk(两种方式)

    最近在研究大数据方面的东西,业务场景是从设备采集数据经过处理然后存放DB. 建设上面的环境第一步肯定是安装jdk,所以和大家一起学一下基本知识centos7.5安装jdk1.8. 安装jdk有两种方法 ...

  7. JUnit5学习之七:参数化测试(Parameterized Tests)进阶

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. Shiro反序列化漏洞检测、dnslog

    目录 信息收集 poc 参考 信息收集 poc # pip install pycrypto import sys import base64 import uuid from random impo ...

  9. AOP面试造火箭始末

    本文已整理致我的github地址,欢迎大家 star 支持一下 这是一个困扰我司由来已久的难题,Dubbo 了解过吧,对外提供的服务可能有多个方法,一般我们为了不给调用方埋坑,会在每个方法里把所有异常 ...

  10. 【HTB系列】Beep

    出品|MS08067实验室(www.ms08067.com) 这次挑战的是 HTB 的第5台靶机:Beep,评分很高,难度中等 靶机描述 Beep 运行了大量的服务,这对正确发掘入口点有一定的挑战,由 ...