[Vue] vue2 mobile terminal, vant2 uses van-tree-select classification selection to implement [select all], [cancel all selection], [search and filter current children], only affects the currently displayed children, and removes duplicates


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


Preface

vant2的级联选择器, component link portal
Insert image description here
functional requirements, select all and deselect all, only a simple version.
There are two buttons, one and 全选one, 取消全选
and only select || Cancel the currently displayed children array.


提示:以下是本篇文章正文内容,下面案例可供参考

1. Page code

Due to privacy, only static images can be posted here.

Insert image description here
I encapsulated this code into a components component and only need to throw it intopopup弹出框

1. Parent page code

<!-- 选择人员弹出框 -->
<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>

2.js method

import ChoseUser from "@/components/ChoseUser/general.vue"
export default {
    
    
	name: "vinit",
	components: {
    
    
		ChoseUser,
	},
	data() {
    
    
		return {
    
    
			showChose:false,

Get return value

methods:{
    
    
	// 确定选中人员
	onConfirmChose(activeUser) {
    
    
		console.log(activeUser, '选中人员')
		this.showChose = false
		// 回显参会人员
		this.userOut = activeUser.map(item => item.text).join()
	},
}

2. Subcomponent code

1.Page

The code is as follows (example):

<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>

2. Style code

The code is as follows (example):

.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;
        }
    }

}

3. js code

Let’s first look at the data formats supported by the vant component

Insert image description here

What it needs is an object array, its object data is the list on the left, and the children data is the child data list rendered on the right.
For example, the following format

testList: [
    {
    
    
        id: 1,
        text: '湖南',
        children:[{
    
    
            id:101,
            text:'长沙'
        },{
    
    
            id:102,
            text:'张家界'
        }]
    }, {
    
    
        id: 2,
        text: '广东',
        children:[{
    
    
            id:201,
            text:'深圳'
        },{
    
    
            id:202,
            text:'佛山'
        }]
    },
]

The way I write it here is to get the department list, then click on the department (on the left), and then request the personnel list on the right .
After obtaining the personnel list, according to the current index subscript, write it to the children of the corresponding department on the left. The code has been compressed.

The method is roughly as follows: obtain personnel data and modify it as needed

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]
    })
},

Because there are no user personnel at the beginning, I need a listener. To switch the list on the left, I need to request the personnel list on the right.

watch: {
    
    
    // 要监听的数据,可以是数组、对象、或者普通的变量
    activeIndex: {
    
    
        // immediate: true, // 立即执行,创建页面时就执行一次
        // deep: true, // 深度监听,会监听到对象里面的属性改变
        handler(newIndex) {
    
    
            this.deptId = this.list[newIndex].id
            this.getDeptUserList()
        },
    },
},

上面代码是,获取左侧列表和右侧人员列表的方法, because they are obtained separately.
If yours is an array obtained at once, it does not need to be so cumbersome. Although the request return value becomes larger, it may be slow and slow.

key code

1. Subcomponent variables

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() // 获取部门列表
    }
},

2. Search filters

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
        }
    }
},

3. Return the object array to the parent page

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
    },
},

4.Confirmation and cancellation methods

Subpage code

// 取消
onCancel() {
    
    
    this.$emit("onCancel")
},
// 确定
onConfirm() {
    
    
    this.$emit("onConfirm", this.activeList)
},

The cancellation method is to close through the parent page
Insert image description here

5. Select all and reverse the selection

Select all and reverse selection as long as the variables are consistent, you can directly take them away and use them.

// 全选
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);
},

Summarize

Let’s look at the case diagram
Insert image description here

1. Click on the partial personnel list 全选, and then on the all personnel list page you can see that the selected person is selected.
2. On the all personnel list 全选, then on the partial personnel list 取消全选. Switching back to all personnel, you can see that some personnel have also been deselected.
3. Filter function
Insert image description here

Fix bug

My selection all is to get all the children data of the currently selected item, but
when I use search search filtering, it will be accidentally damaged. I searched for 3 people in the list of all people, clicked to select all, and 10 people were selected.

Modify now

在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);
},

Modify the above selection method
Insert image description here

Just change the list to filterUserList

The clearing method does not change, because we really want to clear everything. Currently, we can also clear the searched people, and change it to filterUserList.

The complete code is as follows (the part needs to be deleted for free)

<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>

Guess you like

Origin blog.csdn.net/qq_51055690/article/details/132617155