若依Ruoyi选人组件(选择用户回显)
选人/用户组件是系统中最常用的选择组件,找了很多ruoyi的选人组件,发现都不是很完善,最后选择了一个自己觉得不错的使用完善,在原来的基础上进行性能优化以及添加了回显功能等。
效果图
组件代码部分
<template>
<template><div><el-dialog:title="'人员选择' + (type == 'multiple' ? '(多选)' : '(单选)')":visible.sync="open":width="width || '900px'":height="height || '650px'":before-close="handleClose"append-to-body><!-- <div>选择的数据:{{selectData}}</div> --><div class="selectBox"><div class="bottomBox" v-show="showSearch"><el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"><el-row><el-col :span="6"><el-form-item label="用户姓名" prop="nickName"><el-inputv-model="queryParams.nickName"placeholder="请输入用户姓名"clearablestyle="width: 140px"size="mini"@keyup.enter.native="getList"/></el-form-item></el-col><el-col :span="6"><el-form-item label="用户账号" prop="userName"><el-inputv-model="queryParams.userName"placeholder="请输入用户账号"clearablestyle="width: 140px"size="mini"@keyup.enter.native="getList"/></el-form-item></el-col><el-col :span="6"><el-form-item label="手机号码" prop="phonenumber"><el-inputv-model="queryParams.phonenumber"placeholder="请输入手机号码"clearablestyle="width: 140px"size="mini"@keyup.enter.native="getList"/></el-form-item></el-col><el-col :span="6"><el-form-item><el-button type="primary" icon="el-icon-search" size="mini" @click="getList">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button></el-form-item></el-col></el-row></el-form><br><br><br></div><div class="topBox"><div class="leftBox"><div class="contentBox"><div class="leftBox_title">组织架构</div><div style="padding: 4px;margin-bottom: 4px;"><el-inputv-model="deptName"placeholder="请输入部门名称"clearablesize="mini"prefix-icon="el-icon-search"></el-input></div><div class="treeBox"><el-tree:data="deptOptions":props="defaultProps":expand-on-click-node="false":filter-node-method="filterNode"ref="tree"node-key="id"default-expand-allhighlight-current@node-click="handleNodeClick"/></div></div></div><div class="leftBox"><div class="contentBox"><div class="leftBox_title">人员选择<el-button v-if="type == 'multiple'" class="leftBox_title_do" style="right: 70px" type="text"size="mini" @click="handleCheckedNodeAll(true)">全选</el-button><el-button v-if="type == 'multiple'" class="leftBox_title_do" type="text" size="mini"@click="handleCheckedNodeAll(false)">全不选</el-button></div><div class="peopleBox"><div class="peopleList"><el-checkbox-group ref="peopleCheckBoxes" v-model="checkedUsers" @change="handleCheckedUsersChange":max="type == 'single' ? 1 : 2147483647"><el-checkboxv-for="item in userList":label="item.userName":key="item.userName"class="peopleCard"><div class="avatarBox"><!-- <img v-if="item.avatar && item.avatar != ''" :src="item.avatar" class="user-avatar" onerror="οnerrοr=null;if(item) item.avatar = '';"> --><div style="background: #FFA502;" class="user-avatar">{{ item.nickName.substring(0,1) ||item.userName.substring(0,1) || 'User' }}</div></div><div class="peopleInfoBox"><div class="peopleName">{{ item.nickName }}</div><div class="peopleDept">{{ item.dept.deptName || '' }}</div></div></el-checkbox></el-checkbox-group></div></div></div></div><!-- this.checkedUsers --><div class="leftBox"><div class="contentBox"><div class="leftBox_title">已选择人员<el-button v-if="type == 'multiple'" class="leftBox_title_do" type="text" size="mini" @click="clearAll">全部清空</el-button></div><div class="peopleBox"><div class="peopleList"><div v-for="item in selectedUserList" class="peopleCard" :key="item.id"><div class="avatarBox"><!-- <img v-if="item.avatar && item.avatar != ''" :src="item.avatar" class="user-avatar" onerror="οnerrοr=null;if(item) item.avatar = '';"> --><div style="background: #FFA502;" class="user-avatar">{{ item.nickName.substring(0,1) ||item.userName.substring(0,1) || 'User' }}</div></div><div class="peopleInfoBox"><div class="peopleName" style="margin-top:4px">{{ item.nickName }}</div><div class="peopleDept">{{ item.dept.deptName || '' }}</div></div><div class="peopleDeleteBtn" @click="deleteUserByUserName(item.userName)"></div></div></div></div></div></div></div></div><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog></div></template>
<script>
<script>import { listUser, getUser, deptTreeSelect } from '@/api/system/user';import { getToken } from '@/utils/auth'import Treeselect from '@riophae/vue-treeselect';import "@riophae/vue-treeselect/dist/vue-treeselect.css";export default {name: 'PeopleSelect',dicts: ['sys_normal_disable', 'sys_user_sex'],components: { Treeselect },props: {width: {type: String,default: '900px'},height: {type: String,default: '650px'},type: {type: String,default: 'single' //single or multiple},open: {type: Boolean,default: false},selectData:{type: [Array, String],default: () => []}},computed: {},data() {return {loading: false,// open: false,activeName: 'first',defaultProps: {children: 'children',label: 'label'},// 部门树选项deptOptions: undefined,deptName: '',showSearch: true,userList: [],allUserList: [],allUserMap: new Map(),selectedUserList: [],// 查询参数queryParams: {pageNum: 1,pageSize: 2147483647,userName: undefined,nickName: undefined,phonenumber: undefined,status: '0',deptId: undefined},//已选择的用户信息checkedUsers: []}},created() {this.getDeptTree()this.getAllUserList()},watch: {// 根据名称筛选部门树deptName(val) {this.$refs.tree.filter(val)},open(newVal) {if (newVal) {// 1. 筛选出 allUserList 中 userId 存在于 selectData 的用户对象const selectedUsers = this.allUserList.filter(user =>this.selectData.includes(user.userId));// 2. 提取 userName 列表const selecteduserNames = selectedUsers.map(user => user.userName);console.log("提取 userName 列表:",selecteduserNames);// 把 selectData 处理成数组this.checkedUsers = selecteduserNames;// this.updateCheckedUsers();this.selectedUserList = [];this.checkedUsers.forEach(item => {if (this.allUserMap.has(item)) {let u = this.allUserMap.get(item)this.selectedUserList.push(u)}})this.getList();}}},methods: {handleClose(done) {this.$confirm('确认关闭?').then(_ => {this.clearAll();this.cancel();}).catch(_ => {})},handleClick(tab, event) {console.log(tab, event)},//获取选中的人员昵称列表getNickNameList(uns) {let result = []uns.forEach(item => {if (this.allUserMap.has(item)) {result.push(this.allUserMap.get(item).nickName || '')}})return result},//获取选中的人员ID列表getUserIdList(uns) {let result = []uns.forEach(item => {if (this.allUserMap.has(item)) {result.push(this.allUserMap.get(item).userId || '')}})return result},submitForm() {this.$emit('submit', this.checkedUsers, this.getNickNameList(this.checkedUsers), this.getUserIdList(this.checkedUsers)) //返回nickname和userId},cancel() {this.$emit('cancel')},// 筛选节点filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1},// 节点单击事件handleNodeClick(data) {this.queryParams.deptId = data.idthis.getList()},/** 查询部门下拉树结构 */getDeptTree() {deptTreeSelect().then(response => {this.deptOptions = response.data})},// 获取所有用户的列表getAllUserList() {listUser({ pageNum: 1, pageSize: 2147483647, status: '0' }).then(response => {this.allUserList = response.rows || [];this.allUserMap = new Map();this.allUserList.forEach(item => {this.allUserMap.set(item.userName, item) // this.allUserMap.set(item.userId, item) // 2025-05-15 根据用户的id查询对象});this.updateCheckedUsers();this.getList();});},/** 查询用户列表 */getList() {listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {this.userList = response.rows})},/** 重置按钮操作 */resetQuery() {this.resetForm('queryForm')this.queryParams.deptId = undefinedthis.$refs.tree.setCurrentKey(null)this.getList()},handleCheckedUsersChange(val) {this.updateCheckedUsers()},updateCheckedUsers() {this.selectedUserList = [];this.checkedUsers.forEach(item => {if (this.allUserMap.has(item)) {let u = this.allUserMap.get(item)this.selectedUserList.push(u)}})},deleteUserByUserName(username) {for (let i = 0; i < this.checkedUsers.length; i++) {if (this.checkedUsers[i].indexOf(username) != -1) {this.checkedUsers.splice(i, 1)this.updateCheckedUsers()break}}},handleCheckedNodeAll(val) {if (val) { //全选this.userList.forEach(item => {for (let i = 0; i < this.checkedUsers.length; i++) {if (this.checkedUsers[i] == item.userName) { //已存在,跳过return}}//不存在,执行添加this.checkedUsers.push(item.userName)})} else { //全不选this.userList.forEach(item => {for (let i = 0; i < this.checkedUsers.length; i++) {if (this.checkedUsers[i] == item.userName) { //已存在,执行删除this.checkedUsers.splice(i, 1)return}}//不存在,无需操作})}this.updateCheckedUsers()},clearAll() {this.checkedUsers = []this.updateCheckedUsers()}}}</script>
<style>
<style lang="scss" scoped>.selectBox {width: 100%;min-width: 900px;display: flex;flex-direction: column;.topBox {width: 100%;display: flex;margin-top: 0px;.leftBox {width: 280px;height: 400px;margin-right: 10px;-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);display: flex;flex-direction: column;.leftBox_title {width: 100%;height: 40px;font-size: 16px;line-height: 40px;padding-left: 10px;background-color: #f5f5f5;position: relative;.leftBox_title_do {position: absolute;right: 16px;top: 8px;}}.contentBox {width: 100%;}}}.bottomBox {margin-top: 15px;width: 100%;height: 55px;// border: 1px solid #DCDFE6;// -webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);// box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);// overflow-y: auto;.selectPeopleList {width: 100%;display: flex;flex-wrap: wrap;.selectPeopleCard {width: 50px;height: 56px;display: flex;flex-direction: column;align-items: center;margin: 5px 10px;.user-avatar {width: 40px;height: 40px;border-radius: 50%;color: #fff;background: #FFA502;font-size: 14px;text-align: center;line-height: 40px;}.userInfo {width: 100%;display: flex;flex-direction: column;margin-left: 5px;margin-right: 5px;div:nth-child(1) {font-size: 14px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width: 100%;text-align: center;}}}}}}.treeBox {width: 100%;height: 320px;overflow-x: hidden;overflow-y: auto;}.peopleBox {width: 100%;height: 360px;overflow-x: hidden;overflow-y: auto;.peopleList {width: 100%;height: auto;.peopleCard:hover {background-color: #fafafa;transition: .2s;.peopleName {color: #eb6100;}}.peopleCard {width: 100%;height: 48px;border-top: solid #f5f5f5 1px;border-bottom: solid #f5f5f5 1px;padding-left: 8px;display: flex;align-items: center;cursor: pointer;transition: .2s;::v-deep .el-checkbox__label {display: flex;align-items: center;}.avatarBox {width: 40px;height: 40px;.user-avatar {width: 40px;height: 40px;border-radius: 50%;color: #fff;font-size: 16px;text-align: center;line-height: 40px;user-select: none;}}.peopleInfoBox {width: 190px;height: 100%;display: flex;flex-direction: column;padding-left: 8px;.peopleName {width: 100%;height: 20px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;font-size: 16px;line-height: 20px;}.peopleDept {width: 100%;height: 20px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;font-size: 14px;line-height: 20px;color: #999;}}.peopleDeleteBtn {width: 20px;height: 20px;background: url(../../assets/images/delete2.png) no-repeat;background-size: 100% 100%;transition: .2s;}.peopleDeleteBtn:hover {width: 20px;height: 20px;background: url(../../assets/images/delete1.png) no-repeat;background-size: 100% 100%;transition: .2s;}}}}</style>
图标
delete1.png
delete2.png
组件代码使用部分
<template>
<template><div style="padding: 20px;"><PeopleSelect ref="peopleSelect" type="multiple" :isCheck="true" :open="peopleOpen" @cancel="peopleOpen=false" @submit="submitPeople" :selectData="form.userId" /><p>用户Id:<el-input v-model="form.userId" style="width: 300px;"/>用户姓名:<el-input v-model="form.nickName" style="width: 300px;"/>用户账号:<el-input v-model="form.userName" style="width: 300px;"/><el-button type="primary" @click="peopleOpen=true" icon="el-icon-search">选择用户</el-button></p></div>
</template>
<script>
<script>
// 用户选人组件
import PeopleSelect from '@/components/PeopleSelect'export default {name:"usePeopleSelect",components: { PeopleSelect },data() {return {peopleOpen:false,form:{userId:'',userName:'',nickName:'',}}},methods: {//处理用户信息submitPeople(userNameList,nickNameList,userIdList){this.form.userId = userIdList.join(",");//用户IDthis.form.userName = userNameList.join(",");//用户账号this.form.nickName = nickNameList.join(",");//用户姓名this.peopleOpen=false;},}}
</script>
全部代码
<template><div style="padding: 20px;"><PeopleSelect ref="peopleSelect" type="multiple" :isCheck="true" :open="peopleOpen" @cancel="peopleOpen=false" @submit="submitPeople" :selectData="form.userId" /><p>用户Id:<el-input v-model="form.userId" style="width: 300px;"/>用户姓名:<el-input v-model="form.nickName" style="width: 300px;"/>用户账号:<el-input v-model="form.userName" style="width: 300px;"/><el-button type="primary" @click="peopleOpen=true" icon="el-icon-search">选择用户</el-button></p></div>
</template><script>
// 用户选人组件
import PeopleSelect from '@/components/PeopleSelect'export default {name:"usePeopleSelect",components: { PeopleSelect },data() {return {peopleOpen:false,form:{userId:'',userName:'',nickName:'',}}},methods: {//处理用户信息submitPeople(userNameList,nickNameList,userIdList){this.form.userId = userIdList.join(",");//用户IDthis.form.userName = userNameList.join(",");//用户账号this.form.nickName = nickNameList.join(",");//用户姓名this.peopleOpen=false;},}}
</script>
效果
完结~CYSWAN
代码大部分都加上了注释,如果还有看不懂的同学欢迎在评论区讨论