危险

为之则易,不为则难

0%

04_人资后台

今日目标

✔ 掌握 el-tree 组件的使用。

✔ 完成组织架构的增删改查功能。

组织架构树形结构布局

目标

使用 ElementUI 组件布局组织架构的基本布局。

认识组织架构

image-20200828105046683

一个企业的组织架构是该企业的灵魂,组织架构通常采用树形金字塔式结构,本章节,我们布局出页面的基本结构。

image-20200720010954202

树形组件认识

接下来,实现树形的结构,采用 Element UI 的 tree 组件,相关属性如下。

参数 说明 类型 可选值 默认值
default-expand-all 是否默认展开所有节点 boolean
data 展示数据 array
node-key 每个树节点用来作为唯一标识的属性,在整棵树中应该是唯一的 String
props 配置选项,具体看下表 object

props 对象的配置信息如下。

参数 说明 类型 可选值 默认值
label 指定节点标签为节点对象的某个属性值 string, function(data, node)
children 指定子树为节点对象的某个属性值 string
disabled 指定节点选择框是否禁用为节点对象的某个属性值 boolean, function(data, node)

data 属性是组成树形数据的关键,演示它的使用,官网

1
2
3
4
5
6
<template>
<el-card>
<el-row></el-row>
<el-tree :data="departs"></el-tree>
</el-card>
</template>

改造树形组件的数据和结构

📝 目标:根据固定数据,完成下面的效果,掌握 tree props 属性和作用域插槽的使用。

views/department/index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<template>
<div class="container">
<div class="app-container">
<el-card>
<el-tree :data="departs" :props="defaultProps" :default-expand-all="true">
<!-- #1 el-row -->
<!-- 作用域插槽 slot-scope="obj",接收传递给插槽的数据,obj.data 是每个节点的数据对象-->
<!-- <el-row slot-scope="{ data }" type="flex" align="middle" style="height: 40px; width: 100%"> -->
<!-- 或者 <template v-slot="{ data }"></template> -->
<!-- 或者 <template v-slot:default="{ data }"></template> -->
<!-- 或者 <template #default="{ data }"></template> -->
<template #default="{ data }">
<el-row type="flex" align="middle" style="height: 40px; width: 100%">
<!-- #2 左侧内容 -->
<el-col>
<span>{{ data.name }}</span>
</el-col>
<!-- #3 右侧内容 -->
<el-col :span="4">
<!-- #4 el-row -->
<el-row type="flex">
<!-- #5 left -->
<el-col>{{ data.managerName }}</el-col>
<!-- #6 right -->
<el-col>
<!-- #7 -->
<!-- 放置下拉菜单 -->
<el-dropdown>
<!-- #8 标题 -->
<span>操作<i class="el-icon-arrow-down" /> </span>
<!-- #9 内容,具名插槽 -->
<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>
</el-col>
</el-row>
</template>
</el-tree>
</el-card>
</div>
</div>
</template>
<script>
export default {
name: 'Department',
data() {
return {
departs: [{
name: '总裁办',
managerName: 'zs',
children: [{
name: '董事会',
managerName: 'ls'
}]
},
{
name: '行政部',
managerName: 'ww'
},
{
name: '人事部',
managerName: 'zl'
}
],
defaultProps: {
label: 'name' // 表示显示这个属性对应的值
}
}
}
}
</script>

任务

完成树形结构的显示。

获取加工组织架构数据

目标

获取真实的组织架构数据,并将其转化成树形数据显示在页面上。

封装 API 接口

  1. 封装获取组织架构的请求,api/departments.js
1
2
3
4
5
6
7
import request from '@/utils/request'
// 获取组织架构数据
export function getDepartments() {
return request({
url: '/company/department',
})
}
  1. 在钩子函数中调用接口,views/departments/index.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// #1
import {
getDepartments
} from '@/api/departments'
export default {
name: 'Department',
data() {
return {
// #4 删除初始的数据
departs: [],
defaultProps: {
label: 'name'
}
}
},
created() {
// #2
this.getDepartments()
},
methods: {
// #3
async getDepartments() {
const result = await getDepartments()
this.departs = result
}
}
}

将数组数据转化成树形结构

image-20200721010931214

  1. 封装一个工具方法,utils/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 其他删除...
export function transListToTreeData(list, rootValue) {
const arr = []
list.forEach((item) => {
if (item.pid === rootValue) {
// 找到之后,就要去找 item 下面有没有子节点
const children = transListToTreeData(list, item.id)
if (children.length) {
// 如果 children 的长度大于 0,说明找到了子节点
item.children = children
}
arr.push(item) // 将内容加入到数组中
}
})
return arr
}
  1. 调用转化方法,转化树形结构,src/views/department/index.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...
// #1
import {
transListToTreeData
} from '@/utils'
export default {
// ...
methods: {
async getDepartments() {
// ...
// #2
this.departs = transListToTreeData(result, 0)
}
}
}

array to tree

需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 原始数组
const list = [{
id: 'a',
pid: '',
name: '总裁办'
},
{
id: 'b',
pid: '',
name: '行政部'
},
{
id: 'c',
pid: '',
name: '财务部'
},
{
id: 'd',
pid: 'c',
name: '财务核算部'
},
{
id: 'e',
pid: 'c',
name: '税务管理部'
},
{
id: 'f',
pid: 'e',
name: '税务管理 A 部'
},
{
id: 'g',
pid: 'e',
name: '税务管理 B 部'
},
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 期望结果
const list = [{
id: 'a',
pid: '',
name: '总裁办'
},
{
id: 'b',
pid: '',
name: '行政部'
},
{
id: 'c',
pid: '',
name: '财务部',
children: [{
id: 'd',
pid: 'c',
name: '财务核算部'
},
{
id: 'e',
pid: 'c',
name: '税务管理部',
children: [{
id: 'f',
pid: 'e',
name: '税务管理 A 部'
},
{
id: 'g',
pid: 'e',
name: '税务管理 B 部'
},
],
},
],
},
]

确定 ROOT_ID

🍜 先确定 ROOT_ID 为 '' ,把 pid 等于 ROOT_ID 的添加到新数组的第一层。

🤔 思路:封装方法 fn1,从 list 中查找,【谁】(数组的某一项 item)的 pid 等于根 id 的(根 id 就是 ROOT_ID),就把这个【谁】添加到数组中。

1
2
3
4
5
6
7
8
9
10
11
const ROOT_ID = ''

function fn1(list) {
const arr = []
list.forEach(item => {
if (item.pid === ROOT_ID) {
arr.push(item)
}
})
return arr;
}

查找条件可能会变化,为了方便后续的处理,改造上面代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const ROOT_ID = ''

function fn1(list, id = ROOT_ID) {
const arr = []
// 从 list 中继续找,谁的 pid 等于根 id 的
list.forEach((item) => {
if (item.pid === id) {
arr.push(item)
}
})
return arr
}
const result = fn1(list)
console.log(result)

找 item 的 children

🤔 添加进去的 item 项可能还有 children,所以添加之前先找添加进去的这个 item 有没有 children,有 children 的话就把这个 children 挂到 item 上之后再进行添加。

🤔 那么怎么找 children 呢?

😀 思路:封装方法 fn2,从 list 中查找,【谁】的 pid 等于 item 的 id 的,就把这个【谁】添加到数组中,最后把整个数组作为添加进去的 item 的 children。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const ROOT_ID = ''

function fn1(list, id = ROOT_ID) {
const arr = []
list.forEach((item) => {
if (item.pid === id) {
const children = fn2(list, item.id)
if (children.length) {
item.children = children
}
arr.push(item)
}
})
return arr
}

function fn2(list, id) {
const arr = []
list.forEach((item) => {
if (item.pid === id) {
arr.push(item)
}
})
return arr
}

const result = fn1(list, '')
console.log(result)

找 item 的 children

添加进去的 item 项可能还有 children,所以添加之前先找有没有 children,怎么找 children 呢?

思路:封装方法 fn3,从 list 中查找,【谁】的 pid 等于 item 的 id 的,就把这个【谁】添加到数组中,最后把整个数组作为添加进去的 item 的 children。

递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const ROOT_ID = ''

function fn(list, id = ROOT_ID) {
const arr = []
list.forEach(item => {
if (item.pid === id) {
const children = fn(list, item.id)
if (children.length) {
item.children = children
}
arr.push(item)
}
})
return arr;
}
const arr = fn(list)
console.log(arr)

performant-array-to-tree

1
2
3
4
5
6
7
import {
arrayToTree
} from 'performant-array-to-tree'
arrayToTree(arr, {
parentId: 'pid',
dataField: null
})

组织架构删除部门功能

目标

实现操作功能的删除功能。

封装删除部门接口

封装删除功能模块, api/departments.js

1
2
3
4
5
6
export function delDepartments(id) {
return request({
url: `/company/department/${id}`,
method: 'delete',
})
}

注册下拉菜单事件

监听下拉菜单的点击事件并传递相关参数, views/departments/index.vue

1
2
3
4
5
6
7
8
9
10
<!-- #1 @command -->
<el-dropdown @command="operateDepts($event, data.id)">
<span> 操作<i class="el-icon-arrow-down" /> </span>
<el-dropdown-menu slot="dropdown">
<!-- #2 command -->
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...
export default {
name: 'Department',
// ...
methods: {
// ...
operateDepts(type, id) {
if (type === 'add') {
// 添加子部门的操作
} else if (type === 'edit') {
// 编辑部门的操作
} else {
// 删除操作
}
}
}
}

调用删除部门接口

删除之前,提示用户是否删除,然后调用删除接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// ...
import {
delDepartments
} from '@/api/departments'
export default {
name: 'Department',
// ...
methods: {
// ...
operateDepts(type) {
if (type === 'add') {} else if (type === 'edit') {} else {
// 删除操作
this.$confirm('确定要删除该部门吗').then(() => {
// 如果点击了确定就会进入then
return delDepartments(id) // 返回 promise 对象
}).then(() => {
// 如果删除成功了,就会进入这里
this.getDepartments()
}).catch(err => {
// 取消走这儿
console.log(err)
})
}
}
}
}

组织架构新增部门弹框

目标

实现新增部门功能的组件创建。

封装新增接口

封装新增部门的 api 模块, api/departments.js

1
2
3
4
5
6
7
export function addDepartments(data) {
return request({
url: '/company/department',
method: 'post',
data,
})
}

新建新增弹层

  1. 构建一个新增部门的窗体组件,views/department/components/add-dept.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
<!-- 新增部门的弹层 -->
<el-dialog title="新增部门" visible>
<!-- 表单组件 el-form,通过 label-width 设置 label 的宽度 -->
<!-- 匿名插槽 -->
<el-form label-width="120px">
<el-form-item label="部门名称">
<el-input style="width:80%" placeholder="1-50个字符" />
</el-form-item>
<el-form-item label="部门编码">
<el-input style="width:80%" placeholder="1-50个字符" />
</el-form-item>
<el-form-item label="部门负责人">
<!-- <el-select style="width:80%" placeholder="请选择" /> -->
</el-form-item>
<el-form-item label="部门介绍">
<el-input style="width:80%" placeholder="1-300个字符" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<!-- el-dialog 有专门放置底部操作栏的插槽,具名插槽 -->
<el-row slot="footer" type="flex" justify="center">
<!-- 列被分为 24 -->
<el-col :span="6">
<el-button type="primary" size="small">确定</el-button>
<el-button size="small">取消</el-button>
</el-col>
</el-row>
</el-dialog>
</template>
  1. 引入新增弹框组件,departments/index.vue
1
2
3
4
5
6
import AddDept from './components/add-dept'
export default {
components: {
AddDept
},
}
1
2
3
4
<div class="container">
<div class="app-container"></div>
<add-dept />
</div>

点击显示弹层

📝 目标:点击新增子部门时显示弹层组件。

  1. 用外界传递过来的 showDialog 属性控制组件的显示或者隐藏,views/departments/components/add-dept.vue
1
2
3
4
5
6
7
8
9
10
// 需要传入一个 props 变量来控制显示或者隐藏
export default {
name: 'AddDept',
props: {
showDialog: {
type: Boolean,
default: false
}
}
}

把 showDialog 变量和 el-dialog 组件的 visible 属性进行绑定。

1
<el-dialog title="新增部门" :visible="showDialog"></el-dialog>
  1. 父组件定义并传递控制窗体显示的变量 showDialogviews/departments/index.vue
1
<add-dept :show-dialog="showDialog" />
1
2
3
4
5
6
7
8
9
10
export default {
name: 'Department',
// ...
data() {
return {
// ...
showDialog: false
}
},
}
  1. 当点击新增部门时,弹出组件,views/departments/tree-tools.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
name: 'Department',
// ...
methods: {
// ...
operateDepts(type, id) {
if (type === 'add') {
// 显示弹框
this.showDialog = true
} else if (type === 'edit') {
// ...
} else {
// ...
}
}
}
}
  1. 关闭弹框。

给 el-dialog 组件绑定 @close 事件, src/views/department/components/add-dept.vue

1
<el-dialog title="新增部门" :visible="showDialog" @close="btnCancel"></el-dialog>
1
2
3
4
5
6
7
8
9
export default {
name: 'AddDept',
// ...
methods: {
btnCancel() {
this.$emit('update:showDialog', false)
}
}
}

父组件添加 .sync 修饰符(可以简化事件监听和赋值的操作), src/views/department/index.vue

1
<add-dept :show-dialog.sync="showDialog" />

组织架构新增部门校验

目标

完成新增部门功能的规则校验和数据提交部分。

数据收集和基础校验

  1. 准备变量和规则,views/departments/components/add-dept.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
export default {
name: 'AddDept',
// ...
data() {
return {
// 定义表单数据
formData: {
name: '', // 部门名称,必填 1-50 个字符,同级部门中禁止出现重复部门
code: '', // 部门编码,必填 1-50 个字符,部门编码在整个模块中都不允许重复
managerId: '', // 部门管理者,必填
introduce: '', // 部门介绍,必填 1-300 个字符
pid: ''
},
// 定义校验规则
rules: {
name: [{
required: true,
message: '部门名称不能为空',
trigger: 'blur'
},
{
min: 1,
max: 50,
message: '部门名称要求1-50个字符',
trigger: 'blur'
}
],
code: [{
required: true,
message: '部门编码不能为空',
trigger: 'blur'
},
{
min: 1,
max: 50,
message: '部门编码要求1-50个字符',
trigger: 'blur'
}
],
managerId: [{
required: true,
message: '部门负责人不能为空',
trigger: 'change'
}],
introduce: [{
required: true,
message: '部门介绍不能为空',
trigger: 'blur'
},
{
trigger: 'blur',
min: 1,
max: 300,
message: '部门介绍要求1-50个字符'
}
]
}
}
},
}
  1. 把上面的数据和规则与视图进行绑定。
  • el-form 组件配置 model 和 rules 属性。

  • el-form-item 组件配置 prop 属性。

  • 给表单组件 el-input 等进行 v-model 双向绑定。

部门名称和部门编码

📝 目标:完成部门名称和部门编码的自定义校验,部门名称不能和 同级别 的重复。

🤔 思考:添加时,部门名称的规则是什么?部门编码的规则是什么?

  1. 获取最新的部门数据,判断是否重复。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import {
getDepartments
} from '@/api/departments'
export default {
name: 'AddDept',
// ...
data() {
const checkNameRepeat = async (rule, value, callback) => {
const result = await getDepartments()
const isRepeat = result.some((item) => item.name === value)
isRepeat ? callback(new Error(`当前已经有${value}的部门了`)) : callback()
}
return {
// ...
// 定义校验规则
rules: {
// ...
name: [
// ...
{
trigger: 'blur',
validator: checkNameRepeat
}
],
}
}
},
}
  1. 检查部门编码的过程同理。

获取部门负责人的数据

目标

获取新增表单中的部门负责人下拉数据。

内容

  1. 封装获取部门负责人的接口,api/departments.js
1
2
3
4
5
export function getManagerList() {
return request({
url: '/sys/user/simple',
})
}
  1. 组件初始化完毕后调用获取员工列表的方法,views/departments/add-dept.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// #1
import {
getManagerList
} from '@/api/departments'
export default {
name: 'AddDept',
data() {
return {
// ...
// #2
managerList: [],
}
},
created() {
this.getManagerList()
},
methods: {
// ...
// #3 获取员工简单列表数据
async getManagerList() {
this.managerList = await getManagerList()
},
},
}
  1. 渲染数据。
1
2
3
4
<el-select v-model="formData.managerId" style="width:80%" placeholder="请选择">
<!-- 需要循环生成选项,显示的是用户名,存的也是用户名-->
<el-option v-for="item in managerList" :key="item.id" :label="item.username" :value="item.id" />
</el-select>

记录当前点击的数据项

  1. 点击添加子部门按钮时进行记录,src/views/department/index.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export default {
name: 'Department',
// ...
data() {
return {
currentNodeId: null
}
},
methods: {
// ...
operateDepts(type, id) {
if (type === 'add') {
this.currentNodeId = id
this.showDialog = true
} else if (type === 'edit') {
// ...
} else {
// ...
}
}
}
}
  1. 传递 currentNodeId 到新增的子组件,src/views/department/index.vue
1
<add-dept :show-dialog.sync="showDialog" :current-node-id="currentNodeId" />
  1. 子组件进行接收数据,src/views/department/components/add-dept.vue
1
2
3
4
5
6
7
8
9
10
11
export default {
name: 'AddDept',
props: {
// ...
currentNodeId: {
type: Number,
default: null
}
}
// ...
}

组织架构新增部门功能

  1. 给 el-form 定义一个 ref 属性,views/departments/components/add-dept.vue
1
<el-form ref="deptForm" :model="formData" :rules="rules" label-width="120px"></el-form>
1
2
3
4
5
6
7
8
// 点击确定时触发
btnOK() {
this.$refs.deptForm.validate(isOK => {
if (isOK) {
// 表示可以提交了
}
})
}
  1. 校验通过时,调用新增接口,因为是添加子部门,所以子部门的 pid 应该等于当前点击部门的 id。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import {
addDepartments
} from '@/api/departments'

export default {
name: 'AddDept',
// ...
methods: {
// ...
btnOK() {
this.$refs.deptForm.validate(async isOK => {
if (isOK) {
// 表示可以提交了
await addDepartments({
...this.formData,
pid: this.currentNodeId
})
this.$emit('updateDepartment')
this.$message.success('新增部门成功')
this.btnCancel()
}
})
},
}
}
  1. 父组件监听 updateDepartment,views/departments/index.vue
1
<add-dept :show-dialog.sync="showDialog" :current-node-id="currentNodeId" @updateDepartment="getDepartments" />
  1. 关闭弹框时,重置表单和校验规则。
1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
name: 'AddDept',
// ...
methods: {
// ...
btnCancel() {
// 重置内容,并清空校验规则
this.$refs.deptForm.resetFields()
// 关闭
this.$emit('update:showDialog', false)
}
}
}

编辑部门功能数据回写

目标

实现编辑部门的功能。

填充数据

📝 目标:点击编辑按钮时,父组件调用子组件获取详情方法来填充数据。

  1. 封装获取部门信息的接口,api/departments.js
1
2
3
4
5
6
// 获取部门详情
export function getDepartDetail(id) {
return request({
url: `/company/department/${id}`,
})
}
  1. 添加部门的组件中定义获取详情的方法,并把结果赋值给 formData,views/departments/components/add-dept.vue
1
2
3
4
5
6
7
import {
getDepartDetail
} from '@/api/departments'
// 获取部门详情
async getDepartDetail() {
this.formData = await getDepartDetail(this.currentNodeId)
}
  1. 父组件中,点击编辑部门按钮时,调用子组件的方法,views/departments/index.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
name: 'Department',
// ...
methods: {
operateDepts(type, id) {
if (type === 'add') {
// ...
} else if (type === 'edit') {
this.currentNodeId = id
this.showDialog = true
this.$refs.addDept.getDepartDetail()
} else {
// ...
}
}
}
}
  1. 处理 props 传递数据异步的问题。
1
this.$nextTick(this.$refs.addDept.getDepartDetail)

根据计算属性显示控制标题

  1. 根据有无 ID,利用计算属性,区分编辑和添加的弹框标题,views/departments/components/add-dept.vue
1
2
3
4
5
computed: {
showTitle() {
return this.formData.id ? '编辑部门' : '新增子部门'
}
},
  1. 绑定。
1
<el-dialog :title="showTitle" :visible="showDialog" @close="btnCancel"></el-dialog>
  1. el-form 中的 resetFields 不能重置非表单中的数据,导致 formData.id 残留,所以在取消的时候手动重置数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
btnCancel() {
// resetFields 只能重置表单上的数据,非表单上的比如 id 则不能被重置
this.formData = {
name: '',
code: '',
managerId: '',
introduce: '',
pid: ''
}
// 重置内容,并清空校验规则
this.$refs.deptForm.resetFields()
// 关闭
this.$emit('update:showDialog', false)
}

封装并调用编辑的接口

🤔 思考:点击确定按钮时,如何区分是新增和编辑?

  1. 封装编辑部门接口,api/departments.js
1
2
3
4
5
6
7
8
// 编辑部门
export function updateDepartments(data) {
return request({
url: `/company/department/${data.id}`,
method: 'put',
data,
})
}
  1. 点击确定时,进行场景区分,views/departments/components/add-dept.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export default {
name: 'AddDept',
// ...
methods: {
// ...
btnOK() {
this.$refs.deptForm.validate(async isOK => {
if (isOK) {
// 表示可以提交了
if (this.formData.id) {
await updateDepartments(this.formData)
} else {
await addDepartments({
...this.formData,
pid: this.currentNodeId
})
}
this.$emit('updateDepartment')
this.$message.success(`${this.formData.id ? '编辑' : '新增'}部门成功`)
this.btnCancel()
}
})
}
}
}

校验规则支持编辑场景

发现原来的校验规则和编辑部门有些冲突,所以需要进一步处理,编辑时 name 和 code 的校验规则应该是怎样的?

views/departments/components/add-dept.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const checkNameRepeat = async (rule, value, callback) => {
let result = await getDepartments()
// 编辑场景
if (this.formData.id) {
result = result.filter(item => item.id !== this.formData.id)
}
const isRepeat = result.some((item) => item.name === value)
isRepeat ? callback(new Error(`当前已经有${value}的部门了`)) : callback()
}
const checkCodeRepeat = async (rule, value, callback) => {
let result = await getDepartments()
// 编辑场景
if (this.formData.id) {
result = result.filter(item => item.id !== this.formData.id)
}
const isRepeat = result.some((item) => item.code === value)
isRepeat ? callback(new Error(`当前已经有${value}的编码了`)) : callback()
}

至此,整个组织架构,我们完成了读取 / 新增部门 / 删除部门 / 编辑部门。

给数据获取添加进度条

目标

由于获取数据的延迟性,为了更好的体验,可以利用 Element UI 提供的 v-loading 指令给页面加一个进度提示。

内容

  1. 定义 loading 变量,views/departments/index.vue
1
2
3
4
5
data() {
return {
loading: false
}
}
  1. 获取数据前后设置变量。
1
2
3
4
5
6
async getDepartments() {
this.loading = true
const result = await getDepartments()
this.departs = transListToTreeData(result.depts, 0)
this.loading = false
}
  1. 赋值变量给 v-loading 指令。
1
<el-card v-loading="loading"></el-card>