<template>
<div class="department-container">
<div class="app-container">
<el-card>
<!-- 用一个行列布局 -->
<el-row type="flex" justify="space-between" align="middle" style="height: 40px">
<el-col :span="20">
<span>江苏传智播客教育科技股份有限公司</span>
</el-col>
<el-col :span="4">
<el-row type="flex" justify="end">
<!-- 两个内容 -->
<el-col>负责人</el-col>
<el-col>操作</el-col>
</el-row>
</el-col>
</el-row>
</el-card>
</div>
</div>
</template>
结构树
页面内需要用到一个新的组件<el-tree>
结构树
:data="结构数组"
data绑定结构数组:props=""
重新定义结构数组里面的key:default-expand-all="true"
展开所有子节点 ```vue
<a name="PWc1R"></a>
#### 自定义结构
> 自定义结构 模板 -> 插槽 ->
data是当前行的数据( 一个对象 )
```vue
<template #default="{ data }">
<el-row
type="flex"
justify="space-between"
align="middle"
style="height: 40px; width: 100%;"
>
<el-col :span="20">
<span>{{ data.name }}</span>
</el-col>
<el-col :span="4">
<el-row type="flex" justify="end">
<!-- 两个内容 -->
<el-col>{{ data.manager }}</el-col>
<el-col>
<!-- 下拉菜单 element -->
<el-dropdown>
<span> 操作<i class="el-icon-arrow-down" /> </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>
</el-col>
</el-row>
</template>
import request from '@/utils/request'
export const getDepartmentsApi = () => {
return request({
url: '/company/department'
})
}
<script>
function totree(arr) {
const newArr = []
const map = {}
arr.forEach(item => {
if (!item.children) item.children = []
map[item.id] = item // 添加对应的映射关系
})
arr.forEach(item => {
if (map[item.pid]) {
map[item.pid].children.push(item)
} else {
newArr.push(item)
}
})
// 处理之后的tree数组
return newArr
}
import { getDepartmentsApi } from '@/api/departments'
export default {
data() {
return {
list: [],
defaultProps: {
label: 'name'
}
}
},
mounted () {
this.getDepartments()
},
methods: {
async getDepartments() {
const { data } = await getDepartmentsApi()
// console.log(data)
this.list = totree(data.depts)
}
}
}
</script>
数据处理 -> 平铺转树形
核心逻辑:平铺转树形 寻找父节点的过程 这里就是通过pid去匹配id的过程 实施流程:
- 遍历数组,以数组中的每一项的id作为key 每一项本身作为value形成一个对象map (方便查找)
- 遍历数组 通过pid去匹配id 如果匹配上了 就把当前项目添加道匹配项的children属性中,如果没有发生匹配则代表当前项目本身就是最外层的节点 它没有父节点 直接把它push到treeList中
匹配: === 这里使用的是一个小技巧 对象取值 如果取到了就是匹配上了
// 数据处理 => 结构树
transTree(arr) {
// 传入数组
const map = {}
const treeList = []
arr.forEach(item => {
// map空对象 添加键值对 key为item.id 值为item
map[item.id] = item
// 给每一项都加上一个children 空数组
map[item.id].children = []
})
arr.forEach(item => {
// 取数组的pid 与map的每一项对比 返回true说明对比成功(item.pid === map.id)
// 给匹配当的这一项的 children数组下面 添加 作为子级列表数据
if (map[item.pid]) {
map[item.pid].children.push(item)
} else {
// 返回false 没有pid 说明是第一层的数据不需要匹配
treeList.push(item)
}
})
return treeList
},
操作功能
添加子部门
流程:
- 实现一个弹框打开关闭的交互效果
- 实现的是一个表单 校验 单个校验 + 兜底校验
- 收集表单数据 确定提交接口
- 提交成功之后的后续逻辑 提示用户 更新列表 重置数据 重置校验痕迹
点击添加子部门 打开弹层
native修饰符:某个组件的根元素上绑定原生js事件需要 不加默认是自定义事件
<template>
<div class="department-container">
native修饰符:某个组件的根元素上绑定原生js事件需要 不加默认是自定义事件
<el-dropdown-item @click.native="addDepaart">添加子部门</el-dropdown-item>
<!-- 弹层 -->
<el-dialog
title="提示"
:visible="showDialog"
width="30%"
@close="closeDialog"
>
<span>
内容
</span>
<span slot="footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
showDialog: false
}
},
methods: {
// 新增部门
addDepaart () {
this.showDialog = true
},
// 关闭弹层
closeDialog () {
this.showDialog = false
}
}
}
</script>
<style lang="scss" scoped></style>
// 下拉框数据
export function getEmployeeSimpleApi() {
return request({
url: '/sys/user/simple'
})
}
@open事件的时候获取下拉框列表数据
<template>
<div class="department-container">
<!-- 弹层 -->
<el-dialog
title="提示"
:visible="showDialog"
width="30%"
@close="closeDialog"
@open="getEmployeeSimple"
>
<span>
<el-form label-width="120px" :model="form" :rules="rules">
<el-form-item label="部门名称" prop="name">
<el-input v-model="form.name" style="width:80%" placeholder="1-50个字符" />
</el-form-item>
<el-form-item label="部门编码" prop="code">
<el-input v-model="form.code" style="width:80%" placeholder="1-50个字符" />
</el-form-item>
<el-form-item label="部门负责人" prop="manager">
<el-select v-model="form.manager" style="width:80%" placeholder="请选择">
<el-option v-for="item in managerList" :key="item.id" :label="item.username" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="部门介绍" prop="introduce">
<el-input v-model="form.introduce" style="width:80%" placeholder="1-300个字符" type="textarea" />
</el-form-item>
</el-form>
</span>
<span slot="footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getDepartmentsApi, getEmployeeSimpleApi } from '@/api/departments'
export default {
data() {
return {
// 弹层显隐
showDialog: false,
// 表单数据
form: {
name: '',
code: '',
manager: '',
introduce: ''
},
// 校验规则
rules: {
name: [
{ required: true, message: '部门名称不能为空', trigger: ['blur', 'change'] },
{ min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: ['blur', 'change'] }
],
code: [
{ required: true, message: '部门编码不能为空', trigger: ['blur', 'change'] },
{ min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: ['blur', 'change'] }
],
manager: [
{ required: true, message: '部门负责人不能为空', trigger: ['blur', 'change'] }
],
introduce: [
{ required: true, message: '部门介绍不能为空', trigger: ['blur', 'change'] },
{ min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: ['blur', 'change'] }
]
},
// 下拉框数据
managerList: []
}
},
mounted () {
this.getDepartments()
},
methods: {
// 下拉框数据
async getEmployeeSimple() {
const { data } = await getEmployeeSimpleApi()
console.log(data)
this.managerList = data
},
// 获取组织架构
async getDepartments() {
const { data } = await getDepartmentsApi()
// console.log(data)
this.list = totree(data.depts)
},
// 新增部门
addDepaart () {
this.showDialog = true
},
// 关闭弹层
closeDialog () {
this.showDialog = false
}
}
}
</script>
<style lang="scss" scoped></style>
收集数据处理
接口需要pid 表单无法提供,data代表的是当前行的数据,在点击操作时获取到当前行的 pid
<template>
绑定事件(传参 id)
<el-dropdown-item @click.native="addDepaart(data.id)">添加子部门</el-dropdown-item>
</template>
<script>
export default {
data() {
return {
// 当前行id
currId: null
}
},
methods: {
// 新增部门
addDepaart (id) {
this.currId = id
this.showDialog = true
}
}
}
</script>
<style lang="scss" scoped></style>
clickSubmit () {
this.$refs.formRef.validate(async (value) => {
if (value) {
await addDepartApi({ ...this.form, pid: this.currId })
// 关闭弹层
this.showDialog = false
// 重新获取列表
this.getDepartments()
// 提示成功
this.$message.success('添加部门成功')
// 清空表单&校验规则
this.resetFields()
}
})
},
// 关闭弹层
closeDialog () {
this.showDialog = false
// 清空表单
this.form = {
name: '',
code: '',
manager: '',
introduce: ''
}
// 清空校验规则
this.$refs.formRef.resetFields()
}
编辑功能
流程:
- 1.打开弹层(复用新增时的弹框)
- 获取数据完成回填(回填完毕之后 多一个id值)
- 3.进行具体的表单编辑调用更新接口(根据是否有di作为是否变的判断依据)
/**
* 获取当前数据
* @param {*} id 部门id
* @returns
*/
export const editDepartApi = (id) => request.get(`/company/department/${id}`)
/**
*
* @param {*} data 修改的数据
* @returns
*/
export function updateDepartments(data) {
return request({
url: `/company/department/${data.id}`,
method: 'put',
data
})
}
数据回填
点编辑时传入 部门id 根据id获取当前点击的这一行的数据进行回填
// 编辑
async editDepart(id) {
this.showDialog = true
// 获取数据
const { data } = await editDepartApi(id)
// 数据回填
this.form = data
},
修改数据
与提交公用一个弹层 用form里面是否获取到id来进行判断时提交还是修改
clickSubmit () {
this.$refs.formRef.validate(async (value) => {
if (value) {
if (this.form.id) {
await updateDepartments(this.form)
} else {
await addDepartApi({ ...this.form, pid: this.currId })
}
this.showDialog = false
// 重新获取列表
this.getDepartments()
// 提示成功
this.$message.success(`${this.form.id ? '更新' : '新增'} 部门成功 `)
}
})
删除部门
/**
* 删除部门
* @param {*} id 部门id
* @returns
*/
export const delDepartApi = (id) => request.delete(`/company/department/${id}`)
delDepaart(id) {
this.currId = id
// 确定是否删除
this.$confirm('确定删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消' }).then(() => {
}).then(async() => {
// 点击确定执行的代码
try {
await delDepartApi(id)
// 提示删除成功
this.$message.success('删除部门成功')
// 重新获取列表
this.getDepartments()
} catch (error) {
this.$message.error(error)
}
}).catch(() => {
// 点击取消执行的代码
})
},