提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
vant2的级联选择器
,组件链接传送门
功能需求,全选和取消全选,只做简单版。
就是两个按钮,一个全选
,一个取消全选
并且只选中 || 取消 当前显示的这个children数组
提示:以下是本篇文章正文内容,下面案例可供参考
由于隐私,这里只能放静态图
这段代码,我封装成了一个components组件,只需要丢到popup弹出框
<van-popup v-model="showChose" closeable close-icon="close" position="right"
:style="{ height: '100%', width: '100%' }">
<ChoseUser v-if="showChose" name="参会" @onCancel="showChose = false" @onConfirm="onConfirmChose">
ChoseUser>
van-popup>
import ChoseUser from "@/components/ChoseUser/general.vue"
export default {
name: "vinit",
components: {
ChoseUser,
},
data() {
return {
showChose:false,
获取返回值
methods:{
// 确定选中人员
onConfirmChose(activeUser) {
console.log(activeUser, '选中人员')
this.showChose = false
// 回显参会人员
this.userOut = activeUser.map(item => item.text).join()
},
}
代码如下(示例):
<template>
<div class="showUser">
<h4 @click="getDeptList">请选择{{ name }}人员h4>
<van-search v-model="searchName" :placeholder="`请输入搜索的${name}人姓名`" />
<van-loading size="24px" v-if="list.length == 0">加载中...van-loading>
<div class="submit">
<van-button type="danger" plain size="small" @click="onSelectAll">全选van-button>
<van-button type="warning" plain size="small" @click="onClearAll">取消全选van-button>
div>
<van-tree-select :items="list | newUserList(searchName)" :active-id.sync="activeId"
:main-active-index.sync="activeIndex" />
<div class="submit">
<van-button type="default" @click="onCancel">取消van-button>
<van-button type="info" @click="onConfirm">确定van-button>
div>
div>
template>
代码如下(示例):
.showUser {
height: 100vh;
box-sizing: border-box;
padding: 30px 0;
h4 {
margin-bottom: 30px;
padding-left: 30px;
font-size: 30px;
}
// 选择器
.van-tree-select {
margin-top: 20px;
height: 70% !important;
.van-sidebar-item--select::before {
background-color: #418AF1;
}
.van-tree-select__item--active {
color: #418AF1;
}
}
.submit {
width: 100%;
display: flex;
justify-content: space-around;
margin: 20px 0;
.van-button {
width: 150px;
}
}
}
先看vant组件所支持的数据格式
它需要的是,一个对象数组,它的对象数据,就是左侧列表,children数据,就是右侧渲染的子级数据列表。
例如下列格式
testList: [
{
id: 1,
text: '湖南',
children:[{
id:101,
text:'长沙'
},{
id:102,
text:'张家界'
}]
}, {
id: 2,
text: '广东',
children:[{
id:201,
text:'深圳'
},{
id:202,
text:'佛山'
}]
},
]
这里我的写法是,获取部门列表,然后点击部门(左侧),再请求右边人员列表。
获取到人员列表后、根据当前index下标,写入到左侧对应部门的children下。代码压缩一下了。
方法大概如下,获取人员数据,按需求修改
getDeptList() {
// 如果有传入id,则zmlk处理, 没有则通用流程处理
let id = this.id || this.mainDept.deptId
deptList(id).then(res => {
let data = res.data
data.forEach(item => {
item.text = item.label
item.children = []
})
// 添加主部门信息,可以查询全部人员
// if (res.data.length > 1) {
// data.unshift({
// id: this.mainDept.deptId,
// text: this.mainDept.deptName,
// children: [],
// })
// }
this.list = data
}).then(() => {
// 获取当前用户信息所在部门,使左侧对应
const userInfo = Cookies.get("userInfo") && JSON.parse(Cookies.get("userInfo"));
const userDeptId = userInfo ? userInfo.deptId : null
// 左侧选中的部门id赋值,有个人信息,赋值,没有则取第一项
this.deptId = userDeptId || this.list[0].id
// 设置选中部门下标为自己的部门
let index = this.list.findIndex(item => item.id === this.deptId)
this.activeIndex = index == -1 ? 0 : index
this.getDeptUserList() // 调用获取部门下人员信息
})
},
// 获取自己部门下人员列表
getDeptUserList() {
// 如果选中部门,有人员列表,则不请求数据
if (this.list[this.activeIndex].children.length > 0) {
return
}
deptUserList(this.deptId).then(res => {
let array = []
res.data.filter(item => {
array.push({
text: item.realName,
id: item.userName,
deptId: item.deptId,
userId: item.userId,
})
})
// 赋值当前选中部门下children的值
this.list[this.activeIndex].children = [...array]
// 赋值全部人员,用于返回给父页面(对象数组)
this.userListAll = [...this.userListAll, ...array]
})
},
因为是一开始没有用户人员,所以我要监听器,左侧列表切换,就需要请求右边人员列表
watch: {
// 要监听的数据,可以是数组、对象、或者普通的变量
activeIndex: {
// immediate: true, // 立即执行,创建页面时就执行一次
// deep: true, // 深度监听,会监听到对象里面的属性改变
handler(newIndex) {
this.deptId = this.list[newIndex].id
this.getDeptUserList()
},
},
},
上面代码是,获取左侧列表和右侧人员列表的方法
,因为是分开获取的。
如果你的是一次性获取来的数组,那就不需要这么繁琐,虽然请求返回值变大了,可能会缓慢、
props: {
name: {
type: String,
default: "处理", // 处理||传阅, 领导||部门
},
// 是否多选,默认多选,
isArray: {
type: Boolean,
default: true
},
},
data() {
return {
activeIndex: 0, // 左侧《下标
activeId: [], //右侧》列表选中项 ids数组
searchName: "", // 搜索过滤
deptId: "", // 部门id,用于查询部门人员
list: [], // ----------------待选列表, 部门+人员子级 children嵌套
flowList: [], // 正在处理人员,用于禁选
userListAll: [], // 所有子级人员
mainDept: null,// 当前用户部门信息
}
},
created() {
this.init()
},
mounted() {
},
methods: {
init(){
this.isArray ? this.activeId = [] : this.activeId = ""
this.getDeptList() // 获取部门列表
}
},
filters: {
// 过滤选择人员
newUserList(list, searchName) {
let arr = []
if (searchName != "") {
list.forEach((item1, index1) => {
arr.push({
text: item1.text,
children: []
})
item1.children.forEach(item2 => {
if (item2.text.toLowerCase().includes(searchName.toLowerCase())) {
arr[index1].children.push({
id: item2.id,
disabled: item2.disabled,
text: item2.text,
})
}
})
})
return arr
} else {
return list
}
}
},
computed: {
activeList() {
let selectedData = []
if (Array.isArray(this.activeId)) {
console.log("计算")
selectedData = this.activeId.map(id => {
// 通过 id 查找对应的数据
return this.userListAll.find(data => data.id == id);
});
}
return selectedData
},
},
子页面代码
// 取消
onCancel() {
this.$emit("onCancel")
},
// 确定
onConfirm() {
this.$emit("onConfirm", this.activeList)
},
全选反选只要变量一致,可以直接拿走使用。
// 全选
onSelectAll() {
console.log('全选')
const currentChildren = this.list[this.activeIndex]?.children || [];
console.log(currentChildren)
const selectedIdsSet = new Set(this.activeId);
currentChildren.forEach(item => {
selectedIdsSet.add(item.id);
});
this.activeId = Array.from(selectedIdsSet);
console.log(this.activeId)
},
// 清空当前页全选
onClearAll() {
const currentChildren = this.list[this.activeIndex]?.children || [];
const selectedIdsSet = new Set(this.activeId);
currentChildren.forEach(item => {
selectedIdsSet.delete(item.id);
});
this.activeId = Array.from(selectedIdsSet);
},
1、在部分人员列表点击
全选
,然后在所有人员列表页可以看到勾选中了所选人员
2、在全部人员列表全选
,然后在部分人员列表取消全选
。切换回全部人员,可以看到也已经取消了部分人员的选中状态。
3、过滤功能
我的全选是获取当前选中项的所有children数据,但是
当我使用了search搜索过滤时,就会误伤。我在所有人员列表,搜索出来3个人,点击全选,结果选中了10个人。
现在修改
在methods下添加过滤方法
filterNewUserList(list, searchName) {
let arr = [];
if (searchName !== "") {
list.forEach((item1, index1) => {
arr.push({
text: item1.text,
children: [],
});
item1.children.forEach((item2) => {
if (
item2.text.toLowerCase().includes(searchName.toLowerCase())
) {
arr[index1].children.push({
id: item2.id,
disabled: item2.disabled,
text: item2.text,
});
}
});
});
return arr;
} else {
return list;
}
},
在computed中添加计算属性变量
filterUserList() {
return this.filterNewUserList(this.list, this.searchName);
},
把list改成filterUserList就好了
清空方法不动,因为真的要清空所有,当前,清空搜索出来的人,也可以,一致修改为filterUserList
<template>
<div class="showUser">
<h4 @click="getDeptList">请选择{{ name }}人员h4>
<van-search v-model="searchName" :placeholder="`请输入搜索的${name}人姓名`" />
<van-loading size="24px" v-if="list.length == 0">加载中...van-loading>
<div class="submit">
<van-button type="danger" plain size="small" @click="onSelectAll">全选van-button>
<van-button type="warning" plain size="small" @click="onClearAll">取消全选van-button>
div>
<van-tree-select :items="list | newUserList(searchName)" :active-id.sync="activeId"
:main-active-index.sync="activeIndex" />
<div class="submit">
<van-button type="default" @click="onCancel">取消van-button>
<van-button type="info" @click="onConfirm">确定van-button>
div>
div>
template>
<script>
import {
deptList, // 查询部门列表
deptUserList, // 查询部门下的用户列表 id
} from "@/api/flow/common.js"
import {
shouwenFormNot, // 收文未办
} from "@/api/flow/shouwen/task.js"
import {
jobFormNot, // 任务
} from "@/api/flow/job/task.js"
import {
sealFormNot, // 公章
} from "@/api/flow/seal/task.js"
import {
carFormNot, // 公车
} from "@/api/flow/car/task.js"
import {
leaveFormNot, // 请假
} from "@/api/flow/leave/task.js"
import {
getToken
} from "@/utils/auth";
import Cookies from "js-cookie"
export default {
name: "vinit",
components: {
},
props: {
name: {
type: String,
default: "处理", // 处理||传阅, 领导||部门
},
// 是否多选,默认多选,
isArray: {
type: Boolean,
default: true
},
// 公文id, 有id查出正在办并禁用,没id查全部人员
formId: {
type: Number
},
// 传入部门id,6185||326, zmlk专用,没传根据自己id查当前能查询到的
id: {
type: String
},
// 选择人员类型,shouwen收文,job任务,seal公章,car公车,leave请假
type: {
type: String,
default: "shouwen",
}
},
data() {
return {
timer: null,//定时器
activeIndex: 0, // 左侧《下标
activeId: [], //右侧》列表选中项 ids数组
searchName: "", // 搜索过滤
deptId: "", // 部门id,用于查询部门人员
list: [], // ----------------待选列表, 部门+人员子级 children嵌套
flowList: [], // 正在处理人员,用于禁选
userListAll: [], // 所有子级人员
mainDept: null,// 当前用户部门信息
}
},
computed: {
activeList() {
let selectedData = []
if (Array.isArray(this.activeId)) {
console.log("计算")
selectedData = this.activeId.map(id => {
// 通过 id 查找对应的数据
return this.userListAll.find(data => data.id == id);
});
}
return selectedData
},
filterUserList() {
return this.filterNewUserList(this.list, this.searchName);
},
},
filters: {
// 过滤选择人员
newUserList(list, searchName) {
let arr = []
if (searchName != "") {
list.forEach((item1, index1) => {
arr.push({
text: item1.text,
children: []
})
item1.children.forEach(item2 => {
if (item2.text.toLowerCase().includes(searchName.toLowerCase())) {
arr[index1].children.push({
id: item2.id,
disabled: item2.disabled,
text: item2.text,
})
}
})
})
return arr
} else {
return list
}
}
},
watch: {
// 要监听的数据,可以是数组、对象、或者普通的变量
activeIndex: {
// immediate: true, // 立即执行,创建页面时就执行一次
// deep: true, // 深度监听,会监听到对象里面的属性改变
handler(newIndex) {
this.deptId = this.list[newIndex].id
this.getDeptUserList()
},
},
},
created() {
this.mainDept = JSON.parse(Cookies.get("mainDept"))
// 发起定时器轮询异步请求
this.timer = setInterval(() => {
// 执行异步请求,获取 token 的新值
// 如果获取到了新值,则更新组件的状态
if (typeof getToken() !== 'undefined') {
this.init()
// 清除定时器
clearInterval(this.timer);
}
}, 30);
},
mounted() {
},
methods: {
init() {
this.isArray ? this.activeId = [] : this.activeId = ""
// 公文id, 有id查出正在办并禁用,没id查全部人员
if (this.formId) {
switch (this.type) {
case "shouwen":
this.getShouwenList()
break;
case "job":
this.getJobList()
break;
case "seal":
this.getSealList()
break;
case "car":
this.getCarList()
break;
case "leave":
this.getLeaveList()
break;
}
} else {
this.getDeptList() // 获取部门列表
}
},
// 全选
onSelectAll() {
const currentChildren = this.filterUserList[this.activeIndex]?.children || [];
console.log(currentChildren)
const selectedIdsSet = new Set(this.activeId);
currentChildren.forEach(item => {
selectedIdsSet.add(item.id);
});
this.activeId = Array.from(selectedIdsSet);
console.log(this.activeId)
},
// 清空当前页全选
onClearAll() {
const currentChildren = this.list[this.activeIndex]?.children || [];
const selectedIdsSet = new Set(this.activeId);
currentChildren.forEach(item => {
selectedIdsSet.delete(item.id);
});
this.activeId = Array.from(selectedIdsSet);
},
// 取消
onCancel() {
this.$emit("onCancel")
},
// 确定
onConfirm() {
this.$emit("onConfirm", this.activeList)
},
// 获取部门列表
getDeptList() {
// 如果有传入id,则zmlk处理, 没有则通用流程处理
let id = this.id || this.mainDept.deptId
deptList(id).then(res => {
let data = res.data
// 如果传参为部门,过滤领导id
if (this.name == "部门") {
data = res.data.filter(item => {
return item.id != 6185
})
}
data.forEach(item => {
item.text = item.label
item.children = []
})
// 添加主部门信息,可以查询全部人员
if (res.data.length > 1) {
data.unshift({
id: this.mainDept.deptId,
text: this.mainDept.deptName,
children: [],
})
}
this.list = data
}).then(() => {
const userInfo = Cookies.get("userInfo") && JSON.parse(Cookies.get("userInfo"));
const userDeptId = userInfo ? userInfo.deptId : null
this.deptId = userDeptId || this.list[0].id
console.log('当前部门id', this.deptId)
// zmlk\通用的请求部门人员判断
if (this.id) {
this.deptId = this.list[0].id // 文秘查询专用
} else {
this.deptId = this.deptId // 自己的部门id
}
// 设置选中部门下标为自己的部门
let index = this.list.findIndex(item => item.id === this.deptId)
this.activeIndex = index == -1 ? 0 : index
this.getDeptUserList()
})
},
// 获取自己部门下人员列表
getDeptUserList() {
// 如果选中部门,有人员列表,则不请求数据
if (this.list[this.activeIndex].children.length > 0) {
return
}
deptUserList(this.deptId).then(res => {
let array = []
res.data.filter(item => {
let bool = false
for (const element of this.flowList) {
(element.userName == item.userName) && (bool = true)
}
array.push({
text: item.realName,
id: item.userName,
disabled: bool,
userName: item.userName,
realName: item.realName,
deptId: item.deptId,
userId: item.userId,
})
})
// 赋值当前选中部门下children的值
this.list[this.activeIndex].children = [...array]
// 赋值全部人员
this.userListAll = [...this.userListAll, ...array]
})
},
filterNewUserList(list, searchName) {
let arr = [];
if (searchName !== "") {
list.forEach((item1, index1) => {
arr.push({
text: item1.text,
children: [],
});
item1.children.forEach((item2) => {
if (
item2.text.toLowerCase().includes(searchName.toLowerCase())
) {
arr[index1].children.push({
id: item2.id,
disabled: item2.disabled,
text: item2.text,
});
}
});
});
return arr;
} else {
return list;
}
},
// 收文待办
getShouwenList() {
shouwenFormNot(this.formId).then(res => {
this.flowList = [...res.data]
this.getDeptList()
})
},
// 任务
getJobList() {
jobFormNot(this.formId).then(res => {
this.flowList = [...res.data]
this.getDeptList()
})
},
// 公章
getSealList() {
sealFormNot(this.formId).then(res => {
this.flowList = [...res.data]
this.getDeptList()
})
},
// 公车
getCarList() {
carFormNot(this.formId).then(res => {
this.flowList = [...res.data]
this.getDeptList()
})
},
// 请假
getLeaveList() {
leaveFormNot(this.formId).then(res => {
this.flowList = [...res.data]
this.getDeptList()
})
},
},
}
script>
<style scoped lang="less">
.showUser {
height: 100vh;
box-sizing: border-box;
padding: 30px 0;
h4 {
margin-bottom: 30px;
padding-left: 30px;
font-size: 30px;
}
// 选择器
.van-tree-select {
margin-top: 20px;
height: 70% !important;
.van-sidebar-item--select::before {
background-color: #418AF1;
}
.van-tree-select__item--active {
color: #418AF1;
}
}
.submit {
width: 100%;
display: flex;
justify-content: space-around;
margin: 20px 0;
.van-button {
width: 150px;
}
}
}
style>