【VUE】封装用户树形选择和部门树形选择控件

news2024/12/21 20:33:20

用vue实现封装用户树形选择和部门树形选择控件,采用el-tree。方便各个功能模块的使用和以后的开发。

一、封装用户树形选择控件(userTree.vue)

<template>
	<div  style="padding: 10px;">
		<!-- 选择人员对话框 -->
		<el-input placeholder="输入关键字进行过滤" v-model="filterText">
		</el-input>
		<div v-loading="loading" style="padding:0px 20px;overflow-y: auto;height: 50vh;margin-top: 10px;">
			<el-tree class="filter-tree" :data="treeData" show-checkbox :props="defaultProps"
				:filter-node-method="filterNode" :default-checked-keys="checkedKeys" :check-strictly="singleSelection"
				:default-expanded-keys="checkedKeys" @check="handleCheckChange" ref="tree" node-key="id">
			</el-tree>
			<!--  -->
		</div>
		<div slot="footer" class="dialog-footer" style="text-align: right;padding-top: 20px;">
			<el-button class="border_buttom" size="small" plain @click="cancel">关 闭</el-button>
			<el-button class="press_button" size="small" @click="handleAddDept">确 定</el-button>
		</div>
	</div>
</template>

<script>
import {
	allListUser
} from "@/api/system/user";
import {
	listDept
} from "@/api/system/dept";
export default {
	name: "userTree",
	props: {
	    //选中数据回显
		checkedKeys: {
			type: Array,
			default: () => {
				return [];
			}
		},
		//是否开启单选
		singleSelection: {
			type: Boolean,
			default: () => {
				return false;
			}
		},
	},
	data() {
		return {
			loading:true,
			//是否已勾选判断
			checkIf:false,
			services: [],
			//选人弹窗
			open: false,
			//选人过滤
			filterText: '',
			//树控件数据
			treeData: null,
			defaultProps: {
				children: 'children',
				label: 'label'
			},
			selectedMumberList: [],
		}
	},
	inject: ["selectUser", "closeUserTree"],
	watch: {
		filterText(val) {
			this.$refs.tree.filter(val);
		}
	},
	created() {
		this.getUserTree();
	},
	methods: {
		cancel() {
			this.closeUserTree()
			this.$refs.tree.setCheckedKeys([]);
		},
		filterNode(value, data) {
			if (!value) return true;
			return data.label.indexOf(value) !== -1;
		},
		handleCheckChange(node, list) {
			if (this.singleSelection) {
				if (node.uid != null) {
					this.checkIf=true
					this.selectedMumberList = [];
					//选中事件在选中后执行,当lis中有两个选中时,使用setCheckedKeys方法,选中一个节点
					if (list.checkedKeys.length == 2) {
						this.$refs.tree.setCheckedKeys([node.id]);
					}
					this.selectedMumberList.push({
						uid: node.id,
						label: node.label,
						phonenumber:node.phonenumber
					})
				} else {
					this.$message({
						message: '请选择用户数据',
						type: 'warning'
					});
				}

			} else {
				// 获取选中的子节点列表
				this.checkIf=true
				this.selectedMumberList = this.$refs.tree.getCheckedNodes(true, false);
				this.selectedMumberList = this.selectedMumberList.filter(obj => {
					return obj.uid != null
				})
			}
		},
		/** 确定选择人员 */
		handleAddUser() {
			let arr = []
			let userIds = []
			let phonenumbers = []
			let form = {
				userNames: null,
				userIds: null,
				phonenumbers:null,
			}
			if(this.checkIf){
				this.selectedMumberList.forEach((obj) => {
					arr.push(obj.label);
					userIds.push(obj.uid.replace('u_', ''));
					phonenumbers.push(obj.phonenumber)
				})
				form.userNames = arr.toString()
				form.userIds = userIds.toString()
				form.phonenumbers = phonenumbers.toString()
				this.checkIf=false
				this.selectUser(form)
				this.$refs.tree.setCheckedKeys([])
			}else{
				this.checkIf=false
				this.closeUserTree()
			}
		},
		/** 构建树形数据结构 */
		getUserTree() {
			this.loading=true
			//获取所有部门的数据接口
			listDept().then(res => {
				let deptTree = res.data
				//获取所有用户数据
				allListUser().then((res) => {
					this.userList = []
					for (let i in res.rows) {
						const obj = {
							pid: null,
							id: null,
							uid: null,
							label: null,
							phonenumber:null,
						}
						if (res.rows[i].deptId == null || res.rows[i].deptId == "") {
							obj.pid = -1
						} else {
							obj.pid = res.rows[i].deptId
						}
						//加‘u_’是为了区分部门id和用户id
						obj.id = "u_" + res.rows[i].userId
						obj.uid = "u_" + res.rows[i].userId
						obj.label = res.rows[i].userName
						//可以按需求补充其他字段,如一下为补充电话号码
						obj.phonenumber= res.rows[i].phonenumber||'-'
						this.userList.push(obj)
					}
					this.mapTree(deptTree)
					this.treeData = deptTree
					this.loading=false
				});
			})
		},
		mapTree(data) {
			data.forEach(ditem => { //遍历树 拼入相应的user
				if (this.singleSelection && !ditem.uid) {
					ditem['disabled'] = true
				}
				this.userList.forEach(uitem => {
					if (ditem.id == uitem.pid && ditem.uid == null) {
						if (!ditem.children) {
							ditem.children = []
						}
						ditem.children.push(uitem)
					}
				})
				if (ditem.children) {
					this.mapTree(ditem.children)
				}
			})
		},

	}

};
</script>

<style>
</style>

二、封装部门选择控件(deptTree.vue)

<template>
	<div style="padding: 10px;">
		<!-- 选择部门对话框 -->
		<el-input placeholder="输入关键字进行过滤" v-model="filterText"> </el-input>
		<div  v-loading="loading"  style="padding:0px 20px;overflow-y: auto;height: 50vh;margin-top: 10px;">
			<el-tree class="filter-tree" :data="treeData" show-checkbox :props="defaultProps"
				:filter-node-method="filterNode" :default-checked-keys="checkedDeptKeys"  default-expand-all
				:check-strictly="singleSelection" :default-expanded-keys="checkedDeptKeys" @check="handleCheckChange"
				ref="tree" node-key="id">
			</el-tree>
		</div>
		<div slot="footer" class="dialog-footer" style="text-align: right;padding-top: 20px;">
			<el-button class="border_buttom" size="small"  plain @click="cancel">关 闭</el-button>
			<el-button class="press_button" size="small" @click="handleAddDept">确 定</el-button>
		</div>
	</div>
</template>

<script>
import {
	listDept
} from "@/api/system/dept";
export default {
	name: "deptTree",
	props: {
	    //选中回显
		checkedDeptKeys: {
			type: Array,
			default: () => {
				return [];
			}
		},
		//是否单选
		singleSelection: {
			type: Boolean,
			default: () => {
				return false;
			}
		},
	},
	data() {
		return {
			loading:true,
			services: [],
			//选人弹窗
			open: false,
			//选人过滤
			filterText: '',
			//树控件数据
			treeData: null,
			defaultProps: {
				children: 'children',
				label: 'label'
			},
			selectedMumberList: [],
			//是否有选择
			checkIf:false,
		}
	},
	inject: ["selectDept", "closeDeptTree"],
	watch: {
		filterText(val) {
			this.$refs.tree.filter(val);
		}
	},
	created() {
		this.getDeptTree();
	},
	methods: {
		cancel() {
			this.closeDeptTree()
			this.$refs.tree.setCheckedKeys([]);
		},
		filterNode(value, data) {
			if (!value) return true;
			return data.label.indexOf(value) !== -1;
		},
		handleCheckChange(node, list) {
			if (this.singleSelection) {
				this.checkIf=true
				this.selectedMumberList = [];
				//node 该节点所对应的对象、list 树目前的选中状态对象
				//选中事件在选中后执行,当lis中有两个选中时,使用setCheckedKeys方法,选中一个节点
				if (list.checkedKeys.length == 2) {
					//单选实现
					this.$refs.tree.setCheckedKeys([node.id]);
				}
				this.selectedMumberList.push({
					id: node.id,
					label: node.label
				})
			} else {
				this.checkIf=true
				// 获取选中的子节点列表
				this.selectedMumberList = this.$refs.tree.getCheckedNodes(true, false);
			}
		},
		/** 选择部门 */
		handleAddDept() {
			let arr = []
			let deptIds = []
			this.selectedMumberList.forEach((obj) => {
				arr.push(obj.label);
				deptIds.push(obj.id);
			})
			let form = {
				deptNames: null,
				deptIds: null
			}
			if(this.checkIf){
				form.deptNames = arr.toString()
				form.deptIds = deptIds.toString()
				this.checkIf=false
				this.selectDept(form)
				this.$refs.tree.setCheckedKeys([]);
			}else{
				this.checkIf=false
				this.closeDeptTree()
			}
			
		},
		/** 构建树形数据结构 */
		getDeptTree() {
			this.loading=true
			listDept().then(res => {
				this.treeData = res.data
				this.loading=false
			})
		},

	}

};
</script>

<style>
</style>

三、控件使用

<template>
	<div>
		<div>
			<el-form ref="form" :model="form" :rules="rules" label-width="90px">
				<el-row :gutter="24">
					<el-col :span="12">
						<el-form-item label="用户1" prop="u1">
							<el-input v-model="form.u1Name" readonly @click.native="handleUser(1)" placeholder="请选择用户1">
								<template slot="append">
									<span class="inco">
										<i class="el-icon-user"></i>
									</span>
								</template>
							</el-input>
						</el-form-item>
					</el-col>
					<el-col :span="12">
						<el-form-item label="部门1" prop="d1Name">
							<el-input v-model="form.d1Name" readonly @click.native="handleDept(1)" placeholder="请输入部门1">
								<template slot="append">
									<span class="inco">
										<i class="el-icon-user"></i>
									</span>
								</template>
							</el-input>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="24">
					<el-col :span="12">
						<el-form-item label="用户2" prop="u2">
							<el-input v-model="form.u2Name" readonly @click.native="handleUser(2)" placeholder="请选择用户2">
								<template slot="append">
									<span class="inco">
										<i class="el-icon-user"></i>
									</span>
								</template>
							</el-input>
						</el-form-item>
					</el-col>
				</el-row>

				<el-row :gutter="24">
					<el-col :span="24">
						<el-form-item label="用户3" prop="u3">
							<el-input v-model="form.u3Name" readonly @click.native="handleUser(3)" type="text"
								placeholder="请选择用户3">
								<template slot="append">
									<span class="inco">
										<i class="el-icon-user"></i>
									</span>
								</template>
							</el-input>
						</el-form-item>
					</el-col>
				</el-row>
				<el-row :gutter="24">
					<el-col :span="24">
						<el-form-item label="用户4" prop="u4">
							<el-input v-model="form.u4Name" readonly @click.native="handleUser(4)" placeholder="请选择用户4">
								<template slot="append">
									<span class="inco">
										<i class="el-icon-user"></i>
									</span>
								</template>
							</el-input>
						</el-form-item>
					</el-col>
				</el-row>
			</el-form>
		</div>
		<el-dialog title="选择人员" :visible.sync="openUserTree" width="500px" append-to-body>
			<userTree v-if="openUserTree" :singleSelection="singleSelection" :checkedKeys="checkedKeys"></userTree>
		</el-dialog>
		<el-dialog title="选择部门" :visible.sync="openDeptTree" width="500px" append-to-body>
			<deptTree :singleSelection="true" :checkedDeptKeys="checkedDeptKeys"></deptTree>
		</el-dialog>
	</div>
</template>

<script>
    //引用用户选择和部门选择树形控件
	import userTree from "/src/components/deptUserTree/userTree.vue"
	import deptTree from "/src/components/deptUserTree/deptTree.vue"

	export default {
		name: "myPage",
		components: {
			userTree,
			deptTree,
		},
		data() {
			return {

				//用户tree打开
				openUserTree: false,
				//部门tree打开
				openDeptTree: false,
				//用户tree数据回显
				checkedKeys: [],
				//部门tree数据回显
				checkedDeptKeys: [],
				// 表单参数
				form: {},
				//选人控件是否单选
				singleSelection: false,
			};
		},
		created() {

		},
		//父子组件方法触发的关键
		provide() {
			return {
				selectUser: this.selectUser,
				closeUserTree: this.closeUserTree,
				selectDept: this.selectDept,
				closeDeptTree: this.closeDeptTree,
			};
		},
		methods: {
			//点击选人输入框,通过i区分不同的字段的处理
			handleUser(i) {
				this.userFlag = i
				this.checkedKeys = []
				this.singleSelection = false
				if (this.userFlag == 1) {
					this.singleSelection = true
					if (this.form.u1Name != null) {
						this.checkedKeys = this.form.u1.split(',')
					}
				} else if (this.userFlag == 2) {
					this.singleSelection = true
					if (this.form.u2Name != null) {
						this.checkedKeys = this.form.u2.split(',')
					}
				} else if (this.userFlag == 3) {
					if (this.form.u3Name != null) {
						this.checkedKeys = this.form.u3.split(',')
					}
				} else if (this.userFlag == 4) {
					if (this.form.u4Name != null) {
						this.checkedKeys = this.form.u4.split(',')
					}
				}
				//处理数据回显赋值
				if (this.checkedKeys != []) {
					this.checkedKeys.forEach((item, index) => {
						this.checkedKeys[index] = "u_" + this.checkedKeys[index]
					})
				}
				this.openUserTree = true
			},
			//选人确定赋值
			selectUser(e) {
				if (this.userFlag == 1) {
					this.form.u1 = e.userIds
					this.form.u1Name = e.userNames
				} else if (this.userFlag == 2) {
					this.form.u2 = e.userIds
					this.form.u2Name = e.userNames
					//赋值联系方式
					this.form.u2Way = e.phonenumbers
				} else if (this.userFlag == 3) {
					this.form.u3 = e.userIds
					this.form.u3Name = e.userNames
				} else if (this.userFlag == 4) {
					this.form.u4 = e.userIds
					this.form.u4Name = e.userNames
				}
				this.openUserTree = false
			},
			//关闭组件
			closeUserTree() {
				this.openUserTree = false
			},
			//点击选部门输入框
			handleDept(i) {
				this.deptFlag = i
				this.checkedDeptKeys = []
				if (this.deptFlag == 1) {
					if (this.form.d1Name != null) {
					    //处理部门回显选中的到控件里
						this.checkedDeptKeys = this.form.d1.split(',')
					}
				}
				this.openDeptTree = true
			},
			//选择部门
			selectDept(e) {
				if (this.deptFlag == 1) {
					this.form.d1 = e.deptIds
					this.form.d1Name = e.deptNames
				}
				this.openDeptTree = false
			},
			//关闭部门选择组件
			closeDeptTree() {
				this.openDeptTree = false
			},
			// 表单重置
			reset() {
				this.form = {
					u1: null,
					u1Name: null,
					u2: null,
					u2Name: null,
					u3: null,
					u3Name: null,
					u4: null,
					u4Name: null,
					d1: null,
					d1Name: null,
				};
				this.resetForm("form");
			},
		}
	};
</script>

<style scoped lang="scss">

</style>

三、代码分析

自己看代码的注释吧,重点主要是
1、数据结构的构建,获取用户数据和部门数据接口时按照自己的相关字段调整,还有一些数据权限问题按自己需求规避。
2、父子组件方法的调用,因为会存在各种前端标签包裹问题,目前代码只是简单样例,因此采用了provide()来处理。
3、其他应该没有技术难点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216372.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传输层协议UDP详解

目录 一. 知识准备 1.1 传输层 1.2 重识端口号 二. UDP协议 三. UDP协议特点 一. 知识准备 1.1 传输层 前面已经讲过&#xff0c;HTTP协议是应用层协议&#xff0c;在此之前&#xff0c;我们短暂的认为HTTP是直接通过应用层与外界通信的。但是我们要知道&…

新手爬虫DAY1

这个错误信息表明在你的Python程序中&#xff0c;re.search() 函数没有找到预期的匹配项&#xff0c;因此返回了 None。当你尝试在 None 对象上调用 group(1) 方法时&#xff0c;Python 抛出了一个 AttributeError。 具体来说&#xff0c;错误发生在 pc.py 文件的第6行&#x…

《RECONX: RECONSTRUCT ANY SCENE FROM SPARSEVIEWS WITH VIDEO DIFFUSION MODEL》论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2408.16767 项目地址&#xff1a;GitHub - liuff19/ReconX: ReconX: Reconstruct Any Scene from Sparse Views with Video Diffusion Model ---------------------------------------------------------------------------------…

Open-WebUI

Open-WebUI特点⭐ ️直观的界面&#xff1a;聊天界面从 ChatGPT 中汲取灵感&#xff0c;确保用户友好的体验。响应式设计&#xff1a;在桌面和移动设备上享受无缝体验。⚡快速响应&#xff1a;享受快速响应的性能。轻松设置&#xff1a;使用 Docker 或 Kubernetes&#xff08;…

【自然语言处理】Encoder-Decoder模型中Attention机制的引入

在 Encoder-Decoder 模型中引入 Attention 机制&#xff0c;是为了改善基本Seq2Seq模型的性能&#xff0c;特别是当处理长序列时&#xff0c;传统的Encoder-Decoder模型容易面临信息压缩的困难。Attention机制可以帮助模型动态地选择源序列中相关的信息&#xff0c;从而提高翻译…

硬盘文件误删:原因、恢复方案与预防措施

一、硬盘文件误删现象描述 在日常使用电脑的过程中&#xff0c;硬盘文件误删是一个常见且令人头疼的问题。许多用户在进行文件整理、删除无用资料或进行系统清理时&#xff0c;一不小心就可能将重要文件误删。这些误删的文件可能包括工作文档、学习资料、家庭照片、视频等&…

【含文档】基于Springboot+Vue的采购管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

SpringBoot实现桂林旅游的智能推荐

3系统分析 3.1可行性分析 通过对本桂林旅游景点导游平台实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本桂林旅游景点导游平台采用SSM框架&#xff0c;JAVA作…

基于Docker安装Grafana及其基本功能

Grafana是一款用Go语言开发的开源数据可视化工具&#xff0c;可以做数据监控和数据统计&#xff0c;带有告警功能。 拉取Grafana镜像 docker pull grafana/grafana 运行镜像 docker run -d -p 3000:3000 --namegrafana grafana/grafana 打开浏览器&#xff0c;访问 http://l…

【Vue】Vue2(10)

文章目录 1 过度与动画1.1 Test.vue1.2 Test2.vue1.3 Test3.vue1.4 TodoList_动画&#xff1a;MyItem.vue 2 配置代理服务器2.1 方法一2.2 方法二2.3 vue.config.js2.4 App.vue 3 github搜索案例3.1 静态页面3.2 Search.vue3.3 List.vue3.4 App.vue3.5 main.js3.6 github搜索案…

免费插件集-illustrator插件-Ai插件-路径点到点连线

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;实现简单路径内部点到点连线功能。首先从下载网址下载这款插件 https://download.csdn.net/download/m0_67316550…

打造卓越APP体验:13款界面设计软件推荐

你知道如何选择正确的UI设计软件吗&#xff1f;你知道设计美观的用户界面&#xff0c;及带来良好用户体验的APP&#xff0c;需要什么界面设计软件吗&#xff1f;基于APP界面的功能不同&#xff0c;选择的APP界面设计软件也会有所不同。然而&#xff0c;并不是要把所有APP界面设…

1.2.3 TCP IP模型

TCP/IP模型&#xff08;接网叔用&#xff09; 网络接口层 网络层 传输层 应用层 理念&#xff1a;如果某些应用需要“数据格式转换”“会话管理功能”&#xff0c;就交给应用层的特定协议去实现 tip&#xff1a;数据 局部正确不等于全局正确 但是&#xff0c;数据的 全局正…

docker (desktopcompose) download

docker docker-compose download 百度网盘获取离线包链接release-notes 参考dockerdocker-composewlspowershell

基于Spring Boot的大创项目成本控制系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

Linux下ClamAV源代码安装与使用说明

Linux下ClamAV源代码安装与使用说明 ClamAV(Clam AntiVirus)是一款开源的防病毒工具,广泛应用于Linux平台上的网络安全领域。它以其高效的性能和灵活的配置选项,成为网络安全从业人员的重要工具。ClamAV支持多线程扫描,可以自动升级病毒库,并且支持多个操作系统,包括Li…

扫普通链接二维码打开小程序

1. 2.新增规则&#xff08;注意下载文件到跟目录下&#xff0c;需要建个文件夹放下载的校验文件&#xff09; 3.发布 ps&#xff1a;发布后&#xff0c;只能访问正式版本。体验版本如果加了 测试链接http://xxx/xsc/10 那么http://xxx/xsc/aa.....应该都能访问 例如aa101 aa…

5 -《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战

在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡&#xff08;一台机器上只有一块GPU&#xff09;还是单机多卡&#xff08;一台机器上有多块GPU&#xff09;的硬件配置上启动ChatGLM3-6B模型&#xff0c;其前置环境配置和项目文件是相同的。如果大家对配置过程还…

前端excel的实现方案Luckysheet

一、介绍 Luckysheet是一款纯前端类似excel的在线表格&#xff0c;功能强大、配置简单、完全开源的插件。目前已暂停维护&#xff0c;但是其已有功能大概能满足常见需求的使用。 二、引入 ①cdn引入&#xff08;目前应该已经不支持&#xff0c;可自行尝试&#xff09; <l…

第二十七篇:传输层讲解,TCP系列一

一、传输层的功能 ① 分割与重组数据 传输层也要做数据分割&#xff0c;所以必然也需要做数据重组。 ② 按端口号寻址 IP只能定位数据哪台主机&#xff0c;无法判断数据报文应该交给哪个应用&#xff0c;传输层给每个应用都设置了一个编号&#xff0c;这个编号就是端口&…