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

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

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

html 复制代码
<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)

html 复制代码
<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>

三、控件使用

html 复制代码
<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、其他应该没有技术难点。

相关推荐
唐叔在学习10 分钟前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
程序员_三木14 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
ALISHENGYA30 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
顾平安1 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网1 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工1 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
沈剑心1 小时前
如何在鸿蒙系统上实现「沉浸式」页面?
前端·harmonyos
一棵开花的树,枝芽无限靠近你2 小时前
【PPTist】组件结构设计、主题切换
前端·笔记·学习·编辑器
m0_748237052 小时前
Chrome 关闭自动添加https
前端·chrome
prall2 小时前
实战小技巧:下划线转驼峰篇
前端·typescript