1. <template>
  2. <div class="department-container">
  3. <div class="app-container">
  4. <el-card>
  5. <!-- 用一个行列布局 -->
  6. <el-row type="flex" justify="space-between" align="middle" style="height: 40px">
  7. <el-col :span="20">
  8. <span>江苏传智播客教育科技股份有限公司</span>
  9. </el-col>
  10. <el-col :span="4">
  11. <el-row type="flex" justify="end">
  12. <!-- 两个内容 -->
  13. <el-col>负责人</el-col>
  14. <el-col>操作</el-col>
  15. </el-row>
  16. </el-col>
  17. </el-row>
  18. </el-card>
  19. </div>
  20. </div>
  21. </template>

结构树

页面内需要用到一个新的组件<el-tree>结构树

  • :data="结构数组" data绑定结构数组
  • :props="" 重新定义结构数组里面的key
  • :default-expand-all="true" 展开所有子节点 ```vue
  1. <a name="PWc1R"></a>
  2. #### 自定义结构
  3. > 自定义结构 模板 -> 插槽 ->
  4. data是当前行的数据( 一个对象 )
  5. ```vue
  6. <template #default="{ data }">
  7. <el-row
  8. type="flex"
  9. justify="space-between"
  10. align="middle"
  11. style="height: 40px; width: 100%;"
  12. >
  13. <el-col :span="20">
  14. <span>{{ data.name }}</span>
  15. </el-col>
  16. <el-col :span="4">
  17. <el-row type="flex" justify="end">
  18. <!-- 两个内容 -->
  19. <el-col>{{ data.manager }}</el-col>
  20. <el-col>
  21. <!-- 下拉菜单 element -->
  22. <el-dropdown>
  23. <span> 操作<i class="el-icon-arrow-down" /> </span>
  24. <el-dropdown-menu slot="dropdown">
  25. <el-dropdown-item>添加子部门</el-dropdown-item>
  26. <el-dropdown-item>编辑部门</el-dropdown-item>
  27. <el-dropdown-item>删除部门</el-dropdown-item>
  28. </el-dropdown-menu>
  29. </el-dropdown>
  30. </el-col>
  31. </el-row>
  32. </el-col>
  33. </el-row>
  34. </template>
  1. import request from '@/utils/request'
  2. export const getDepartmentsApi = () => {
  3. return request({
  4. url: '/company/department'
  5. })
  6. }
  1. <script>
  2. function totree(arr) {
  3. const newArr = []
  4. const map = {}
  5. arr.forEach(item => {
  6. if (!item.children) item.children = []
  7. map[item.id] = item // 添加对应的映射关系
  8. })
  9. arr.forEach(item => {
  10. if (map[item.pid]) {
  11. map[item.pid].children.push(item)
  12. } else {
  13. newArr.push(item)
  14. }
  15. })
  16. // 处理之后的tree数组
  17. return newArr
  18. }
  19. import { getDepartmentsApi } from '@/api/departments'
  20. export default {
  21. data() {
  22. return {
  23. list: [],
  24. defaultProps: {
  25. label: 'name'
  26. }
  27. }
  28. },
  29. mounted () {
  30. this.getDepartments()
  31. },
  32. methods: {
  33. async getDepartments() {
  34. const { data } = await getDepartmentsApi()
  35. // console.log(data)
  36. this.list = totree(data.depts)
  37. }
  38. }
  39. }
  40. </script>

数据处理 -> 平铺转树形

核心逻辑:平铺转树形 寻找父节点的过程 这里就是通过pid去匹配id的过程 实施流程:

  1. - 遍历数组,以数组中的每一项的id作为key 每一项本身作为value形成一个对象map (方便查找)
  2. - 遍历数组 通过pid去匹配id 如果匹配上了 就把当前项目添加道匹配项的children属性中,如果没有发生匹配则代表当前项目本身就是最外层的节点 它没有父节点 直接把它pushtreeList

匹配: === 这里使用的是一个小技巧 对象取值 如果取到了就是匹配上了

  1. // 数据处理 => 结构树
  2. transTree(arr) {
  3. // 传入数组
  4. const map = {}
  5. const treeList = []
  6. arr.forEach(item => {
  7. // map空对象 添加键值对 key为item.id 值为item
  8. map[item.id] = item
  9. // 给每一项都加上一个children 空数组
  10. map[item.id].children = []
  11. })
  12. arr.forEach(item => {
  13. // 取数组的pid 与map的每一项对比 返回true说明对比成功(item.pid === map.id)
  14. // 给匹配当的这一项的 children数组下面 添加 作为子级列表数据
  15. if (map[item.pid]) {
  16. map[item.pid].children.push(item)
  17. } else {
  18. // 返回false 没有pid 说明是第一层的数据不需要匹配
  19. treeList.push(item)
  20. }
  21. })
  22. return treeList
  23. },

操作功能

添加子部门

流程:

    1. 实现一个弹框打开关闭的交互效果
    1. 实现的是一个表单 校验 单个校验 + 兜底校验
    1. 收集表单数据 确定提交接口
    1. 提交成功之后的后续逻辑 提示用户 更新列表 重置数据 重置校验痕迹

点击添加子部门 打开弹层

native修饰符:某个组件的根元素上绑定原生js事件需要 不加默认是自定义事件

  1. <template>
  2. <div class="department-container">
  3. native修饰符:某个组件的根元素上绑定原生js事件需要 不加默认是自定义事件
  4. <el-dropdown-item @click.native="addDepaart">添加子部门</el-dropdown-item>
  5. <!-- 弹层 -->
  6. <el-dialog
  7. title="提示"
  8. :visible="showDialog"
  9. width="30%"
  10. @close="closeDialog"
  11. >
  12. <span>
  13. 内容
  14. </span>
  15. <span slot="footer">
  16. <el-button @click="showDialog = false">取消</el-button>
  17. <el-button type="primary">确定</el-button>
  18. </span>
  19. </el-dialog>
  20. </div>
  21. </template>
  22. <script>
  23. export default {
  24. data() {
  25. return {
  26. showDialog: false
  27. }
  28. },
  29. methods: {
  30. // 新增部门
  31. addDepaart () {
  32. this.showDialog = true
  33. },
  34. // 关闭弹层
  35. closeDialog () {
  36. this.showDialog = false
  37. }
  38. }
  39. }
  40. </script>
  41. <style lang="scss" scoped></style>
  1. // 下拉框数据
  2. export function getEmployeeSimpleApi() {
  3. return request({
  4. url: '/sys/user/simple'
  5. })
  6. }

@open事件的时候获取下拉框列表数据

  1. <template>
  2. <div class="department-container">
  3. <!-- 弹层 -->
  4. <el-dialog
  5. title="提示"
  6. :visible="showDialog"
  7. width="30%"
  8. @close="closeDialog"
  9. @open="getEmployeeSimple"
  10. >
  11. <span>
  12. <el-form label-width="120px" :model="form" :rules="rules">
  13. <el-form-item label="部门名称" prop="name">
  14. <el-input v-model="form.name" style="width:80%" placeholder="1-50个字符" />
  15. </el-form-item>
  16. <el-form-item label="部门编码" prop="code">
  17. <el-input v-model="form.code" style="width:80%" placeholder="1-50个字符" />
  18. </el-form-item>
  19. <el-form-item label="部门负责人" prop="manager">
  20. <el-select v-model="form.manager" style="width:80%" placeholder="请选择">
  21. <el-option v-for="item in managerList" :key="item.id" :label="item.username" :value="item.id" />
  22. </el-select>
  23. </el-form-item>
  24. <el-form-item label="部门介绍" prop="introduce">
  25. <el-input v-model="form.introduce" style="width:80%" placeholder="1-300个字符" type="textarea" />
  26. </el-form-item>
  27. </el-form>
  28. </span>
  29. <span slot="footer">
  30. <el-button @click="showDialog = false">取消</el-button>
  31. <el-button type="primary">确定</el-button>
  32. </span>
  33. </el-dialog>
  34. </div>
  35. </template>
  36. <script>
  37. import { getDepartmentsApi, getEmployeeSimpleApi } from '@/api/departments'
  38. export default {
  39. data() {
  40. return {
  41. // 弹层显隐
  42. showDialog: false,
  43. // 表单数据
  44. form: {
  45. name: '',
  46. code: '',
  47. manager: '',
  48. introduce: ''
  49. },
  50. // 校验规则
  51. rules: {
  52. name: [
  53. { required: true, message: '部门名称不能为空', trigger: ['blur', 'change'] },
  54. { min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: ['blur', 'change'] }
  55. ],
  56. code: [
  57. { required: true, message: '部门编码不能为空', trigger: ['blur', 'change'] },
  58. { min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: ['blur', 'change'] }
  59. ],
  60. manager: [
  61. { required: true, message: '部门负责人不能为空', trigger: ['blur', 'change'] }
  62. ],
  63. introduce: [
  64. { required: true, message: '部门介绍不能为空', trigger: ['blur', 'change'] },
  65. { min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: ['blur', 'change'] }
  66. ]
  67. },
  68. // 下拉框数据
  69. managerList: []
  70. }
  71. },
  72. mounted () {
  73. this.getDepartments()
  74. },
  75. methods: {
  76. // 下拉框数据
  77. async getEmployeeSimple() {
  78. const { data } = await getEmployeeSimpleApi()
  79. console.log(data)
  80. this.managerList = data
  81. },
  82. // 获取组织架构
  83. async getDepartments() {
  84. const { data } = await getDepartmentsApi()
  85. // console.log(data)
  86. this.list = totree(data.depts)
  87. },
  88. // 新增部门
  89. addDepaart () {
  90. this.showDialog = true
  91. },
  92. // 关闭弹层
  93. closeDialog () {
  94. this.showDialog = false
  95. }
  96. }
  97. }
  98. </script>
  99. <style lang="scss" scoped></style>

收集数据处理

接口需要pid 表单无法提供,data代表的是当前行的数据,在点击操作时获取到当前行的 pid

  1. <template>
  2. 绑定事件(传参 id)
  3. <el-dropdown-item @click.native="addDepaart(data.id)">添加子部门</el-dropdown-item>
  4. </template>
  5. <script>
  6. export default {
  7. data() {
  8. return {
  9. // 当前行id
  10. currId: null
  11. }
  12. },
  13. methods: {
  14. // 新增部门
  15. addDepaart (id) {
  16. this.currId = id
  17. this.showDialog = true
  18. }
  19. }
  20. }
  21. </script>
  22. <style lang="scss" scoped></style>
  1. clickSubmit () {
  2. this.$refs.formRef.validate(async (value) => {
  3. if (value) {
  4. await addDepartApi({ ...this.form, pid: this.currId })
  5. // 关闭弹层
  6. this.showDialog = false
  7. // 重新获取列表
  8. this.getDepartments()
  9. // 提示成功
  10. this.$message.success('添加部门成功')
  11. // 清空表单&校验规则
  12. this.resetFields()
  13. }
  14. })
  15. },
  1. // 关闭弹层
  2. closeDialog () {
  3. this.showDialog = false
  4. // 清空表单
  5. this.form = {
  6. name: '',
  7. code: '',
  8. manager: '',
  9. introduce: ''
  10. }
  11. // 清空校验规则
  12. this.$refs.formRef.resetFields()
  13. }

编辑功能

流程:

  • 1.打开弹层(复用新增时的弹框)
    1. 获取数据完成回填(回填完毕之后 多一个id值)
  • 3.进行具体的表单编辑调用更新接口(根据是否有di作为是否变的判断依据)
  1. /**
  2. * 获取当前数据
  3. * @param {*} id 部门id
  4. * @returns
  5. */
  6. export const editDepartApi = (id) => request.get(`/company/department/${id}`)
  7. /**
  8. *
  9. * @param {*} data 修改的数据
  10. * @returns
  11. */
  12. export function updateDepartments(data) {
  13. return request({
  14. url: `/company/department/${data.id}`,
  15. method: 'put',
  16. data
  17. })
  18. }

数据回填

点编辑时传入 部门id 根据id获取当前点击的这一行的数据进行回填

  1. // 编辑
  2. async editDepart(id) {
  3. this.showDialog = true
  4. // 获取数据
  5. const { data } = await editDepartApi(id)
  6. // 数据回填
  7. this.form = data
  8. },

修改数据

与提交公用一个弹层 用form里面是否获取到id来进行判断时提交还是修改

  1. clickSubmit () {
  2. this.$refs.formRef.validate(async (value) => {
  3. if (value) {
  4. if (this.form.id) {
  5. await updateDepartments(this.form)
  6. } else {
  7. await addDepartApi({ ...this.form, pid: this.currId })
  8. }
  9. this.showDialog = false
  10. // 重新获取列表
  11. this.getDepartments()
  12. // 提示成功
  13. this.$message.success(`${this.form.id ? '更新' : '新增'} 部门成功 `)
  14. }
  15. })

删除部门

  1. /**
  2. * 删除部门
  3. * @param {*} id 部门id
  4. * @returns
  5. */
  6. export const delDepartApi = (id) => request.delete(`/company/department/${id}`)
  1. delDepaart(id) {
  2. this.currId = id
  3. // 确定是否删除
  4. this.$confirm('确定删除吗?', '提示', {
  5. confirmButtonText: '确定',
  6. cancelButtonText: '取消' }).then(() => {
  7. }).then(async() => {
  8. // 点击确定执行的代码
  9. try {
  10. await delDepartApi(id)
  11. // 提示删除成功
  12. this.$message.success('删除部门成功')
  13. // 重新获取列表
  14. this.getDepartments()
  15. } catch (error) {
  16. this.$message.error(error)
  17. }
  18. }).catch(() => {
  19. // 点击取消执行的代码
  20. })
  21. },