学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/humanResourceIntelligentManagementProject
觉得有帮助的同学,可以点心心支持一下哈
树组件应用
<!-- 展示树形结构 --><!-- default-expand-all默认展开所有节点 --><el-tree default-expand-all :data="depts" :props="defaultProps" />depts: [{name: '传智教育',children: [{name: '总裁办'},{name: '行政部'},{name: '人事部',children: [{name: '财务核算部'},{name: '税务管理部'},{name: '薪资管理部'}]}]}],defaultProps: {label: 'name', // 要显示的字段的名字children: 'children' // 读取子节点的字段名}
树组件自定义结构
<!-- 节点结构 --><el-rowstyle="width: 100%; height: 40px"type="flex"justify="space-between"align="middle"><el-col>传智教育</el-col><el-col :span="4"><span class="tree-manager">管理员</span><el-dropdown><!-- 显示区域内容 --><span class="el-dropdown-link">操作<i class="el-icon-arrow-down el-icon--right" /></span><!-- 下拉菜单内容 --><el-dropdown-menu slot="dropdown"><el-dropdown-item>添加子部门</el-dropdown-item><el-dropdown-item>编辑部门</el-dropdown-item><el-dropdown-item>删除</el-dropdown-item></el-dropdown-menu></el-dropdown></el-col></el-row>.tree-manager {width: 50px;display: inline-block;margin: 10px;
}
节点作用域插槽
<!-- 节点结构 --><!-- v-slot="{node,data}"只能作用在template --><template v-slot="{ data }"><el-rowstyle="width: 100%; height: 40px"type="flex"justify="space-between"align="middle"><el-col>{{ data.name }}</el-col><el-col :span="4"><span class="tree-manager">{{ data.managerName }}</span><el-dropdown><!-- 显示区域内容 --><span class="el-dropdown-link">操作<i class="el-icon-arrow-down el-icon--right" /></span><!-- 下拉菜单内容 --><el-dropdown-menu slot="dropdown"><el-dropdown-item>添加子部门</el-dropdown-item><el-dropdown-item>编辑部门</el-dropdown-item><el-dropdown-item>删除</el-dropdown-item></el-dropdown-menu></el-dropdown></el-col></el-row></template>depts: [{name: '传智教育',managerName: '管理员',children: [{name: '总裁办',managerName: '张三'},{name: '行政部',managerName: '李四'},{name: '人事部',managerName: '王五',children: [{name: '财务核算部',managerName: '杜威'},{name: '税务管理部',managerName: '杨旭'},{name: '薪资管理部',managerName: '李生根'}]}]}],defaultProps: {label: 'name', // 要显示的字段的名字children: 'children' // 读取子节点的字段名}
获取组织架构数据
/**** 获取组织架构数据**/
export function getDepartment () {return request({url: '/company/department',method: 'GET'})
}created () {this.getDepartment() // 调用获取数据接口},methods: {async getDepartment () {const result = await getDepartment()this.depts = result}}
递归转化树形结构
通过对返回数据的观察,可以发现子节点的pid是父节点的id,可以通过这个对返回数据进行处理
分析数据的关联关系
封装递归函数根据关系转化层级结构
递归特点:
①一般用来处理未知层级的数据
②递归要有跳出条件
③自身调用自身时参数不能重复
/*** 列表型数据转化树形*/
export function transListToTreeData (list, rootValue) {const arr = []list.forEach(item => {if (item.pid === rootValue) {// 找到了匹配的节点arr.push(item)// 当前节点的id和当前节点的子节点的pid是相等的const children = transListToTreeData(list, item.id)item.children = children // 将子节点赋值给当前节点}})return arr
}
添加子部门
新建弹层组件
<el-dropdown @command="operateDept"><!-- 显示区域内容 --><span class="el-dropdown-link">操作<i class="el-icon-arrow-down el-icon--right" /></span><!-- 下拉菜单内容 --><el-dropdown-menu slot="dropdown"><el-dropdown-item command="add">添加子部门</el-dropdown-item><el-dropdown-item command="edit">编辑部门</el-dropdown-item><el-dropdown-item command="del">删除</el-dropdown-item></el-dropdown-menu>
</el-dropdown><!-- 放置弹层内容 --><!-- sync表示会接收子组件的事件 update:showDialog,值=>属性--><add-dept :show-dialog.sync="showDialog" />// 操作部门的方法operateDept (type) {if (type === 'add') {// 添加子部门this.showDialog = true}}
封装弹层组件
<template><el-dialog title="新增部门" :visible="showDialog" @close="close"><!-- 放置弹层内容 --></el-dialog>
</template><script>
export default {props: {showDialog: {type: Boolean,default: false}},methods: {close () {// 修改父组件的值,子传父// .sync会自动监听update:showDialog事件this.$emit('update:showDialog', false)}}
}
</script><style></style>
表单结构
<el-form label-width="120px"><el-form-item label="部门名字"><el-input placeholder="2-10个字符" style="width: 80%" size="mini" /></el-form-item><el-form-item label="部门编码"><el-input placeholder="2-10个字符" style="width: 80%" size="mini" /></el-form-item><el-form-item label="部门负责人"><el-selectv-model="formData.managerId"placeholder="请选择负责人"style="width: 80%"size="mini"></el-form-item><el-form-item label="部门介绍"><el-inputplaceholder="1-100个字符"type="textarea":row="4"style="width: 80%"size="mini"/></el-form-item><el-form-item><el-row type="flex" justify="center"><el-col :span="12"><el-button type="primary" size="mini">确定</el-button><el-button size="mini">取消</el-button></el-col></el-row></el-form-item></el-form>
表单校验
formData: {code: '', // 部门编码introduce: '', // 部门介绍managerId: '', // 部门负责人名字name: '', // 部门名称pid: '' // 部门父级部门id},rules: {name: [{ required: true, message: '部门名称不能为空', trigger: 'blur' },{min: 2,max: 10,message: '部门名称的长度为2-10个字符',trigger: 'blur'}], // 部门名称code: [{ required: true, message: '部门编码不能为空', trigger: 'blur' },{min: 2,max: 10,message: '部门编码的长度为2-10个字符',trigger: 'blur'}], // 部门编码introduce: [{ required: true, message: '部门负责人不能为空', trigger: 'blur' },{min: 1,max: 10,message: '部门介绍的长度为1-100个字符',trigger: 'blur'}], // 部门介绍managerId: [{ required: true, message: '部门介绍不能为空', trigger: 'blur' }] // 部门负责人名字}
业务校验
自定义规则
{trigger: 'blur',// 自定义校验模式validator: async (rule, value, callback) => {// value就是输入的编码const result = await getDepartment()// result数组中是否存在value值if (result.some(item => item.name === value)) {callback(new Error('部门中已经有该名称了'))} else {callback()}}}
负责人数据
label表示下拉菜单所显示的数据,v-model的值为当前被选中的el-option的 value 属性值
/**** 获取部门负责人数据*/
export function getManagerList () {return request({url: '/sys/user/simple',method: 'GET'})
}managerList: [],created () {this.getManagerList()},methods: {async getManagerList () {this.managerList = await getManagerList()}}<!-- 下拉选项 循环负责人数据 label表示显示的字段 value表示存储的字段--><el-optionv-for="item in managerList":key="item.id":label="item.username":value="item.id"/>
记录部门Id
<!-- $event 实参 表示类型 --><el-dropdown @command="operateDept($event, data.id)">// 操作部门的方法operateDept (type, id) {if (type === 'add') {// 添加子部门this.showDialog = truethis.currentNodeId = id}}<!-- 放置弹层内容 --><!-- sync表示会接收子组件的事件 update:showDialog,值=>属性--><add-dept :current-node-id="currentNodeId" :show-dialog.sync="showDialog" />//组件接收id currentNodeId: {type: Number,default: null}
确认取消
/**** 新增组织*/
export function addDepartment (data) {return request({url: '/company/department',method: 'POST',data})
}btnOk () {this.$refs.addDept.validate(async isOk => {if (isOk) {await addDepartment({...this.formData,pid: this.currentNodeId})// 通知父组件更新this.$emit('updateDepartment')// 提示信息this.$message.success('新增部门成功')this.close()}})}, close () {// 修改父组件的值,子传父// .sync会自动监听update:showDialog事件this.$refs.addDept.resetFields() // 重置表单this.$emit('update:showDialog', false)}<!-- 放置弹层内容 --><!-- sync表示会接收子组件的事件 update:showDialog,值=>属性--><add-dept:current-node-id="currentNodeId":show-dialog.sync="showDialog"@updateDepartment="getDepartment"/>
编辑部门
弹出层获取数据
/**** 获取部门详情*/
export function getDepartmentDetail (id) {return request({url: `/company/department/${id}`,method: 'GET'})
}<!-- ref 可以获取dom实例对象 ref 也可以获取自定义组件的实例对象 --><add-deptref="addDept":current-node-id="currentNodeId":show-dialog.sync="showDialog"@updateDepartment="getDepartment"/>
if (type === 'edit') {// 编辑部门this.showDialog = truethis.currentNodeId = id // 记录id 要用它获取数据// 更新props是异步动作,直接调用子组件的方法是同步方法// 所以这里要使用$this.$nextTick方法等数据都处理完,在执行方法// 要在子组件获取数据// 父组件调用子组件的方法来获取数据this.$nextTick(() => {this.$refs.addDept.getDepartmentDetail() // this.$refs.addDept})}// 获取组织的详情async getDepartmentDetail () {this.formData = await getDepartmentDetail(this.currentNodeId)}
编辑表单校验
let result = await getDepartment()// 判断是否是编辑模式if (this.formData.id) {// 编辑场景result = result.filter(item => item.id !== this.formData.id)}
确认取消
标题不是表单所以不能绑定v-model事件,使用计算属性进行更新
/**** 更新部门*/
export function updateDepartment (data) {return request({url: `/company/department/${data.id}`,method: 'PUT',data})
}<el-dialog :title="showTitle" :visible="showDialog" @close="close">// 标题不是表单所以不能绑定v-model事件,使用计算属性进行更新computed: {showTitle () {return this.formData.id ? '编辑部门' : '新增部门'}}close () {// 修改父组件的值,子传父// .sync会自动监听update:showDialog事件// resetFields只能重置在模板中绑定的数据this.formData = {code: '', // 部门编managerListintroduce: '', // 部门介绍managerId: '', // 部门负责人名字name: '', // 部门名称pid: '' // 部门父级部门id}this.$refs.addDept.resetFields() // 重置表单this.$emit('update:showDialog', false)}btnOk () {this.$refs.addDept.validate(async isOk => {if (isOk) {let msg = '新增'// 通过formData中id判断属于什么场景if (this.formData.id) {// 编辑场景await updateDepartment(this.formData)msg = '更新'} else {// 新增场景await addDepartment({...this.formData,pid: this.currentNodeId})}// 通知父组件更新this.$emit('updateDepartment')// 提示信息this.$message.success(`${msg}新增部门成功`)this.close()}})},
删除部门
/**** 删除部门*/
export function delDepartment (id) {return request({url: `/company/department/${id}`,method: 'DELETE'})
}// 删除部门this.$confirm('您确定要删除该部门吗').then(async () => {await delDepartment(id)// 提示消息this.$message.success('删除部门成功')this.getDepartment()})