学习源码可以看我的个人前端学习笔记 (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-row
style="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-row
style="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-select
v-model="formData.managerId"
placeholder="请选择负责人"
style="width: 80%"
size="mini"
>
</el-form-item>
<el-form-item label="部门介绍">
<el-input
placeholder="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-option
v-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 = true
this.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-dept
ref="addDept"
:current-node-id="currentNodeId"
:show-dialog.sync="showDialog"
@updateDepartment="getDepartment"
/>
if (type === 'edit') {
// 编辑部门
this.showDialog = true
this.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: '', // 部门编managerList
introduce: '', // 部门介绍
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()
})