人资项目day06-组织架构树形结构布局
Posted 初学者--峰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了人资项目day06-组织架构树形结构布局相关的知识,希望对你有一定的参考价值。
使用element-UI组件布局组织架构的基本布局
认识组织架构
一个企业的组织架构是该企业的灵魂,组织架构多常采用树形金字塔式结构,本章节,我们布局出页面的基本结构
实现组织架构的头部内容
首先实现头部的结构,采用element的行列布局
<!-- 实现页面的基本布局 -->
<el-card class="tree-card">
<!-- 用了一个行列布局 -->
<el-row type="flex" justify="space-between" align="middle" style="height: 40px">
<el-col>
<span>江苏传智播客教育科技股份有限公司</span>
</el-col>
<el-col :span="4">
<el-row type="flex" justify="end">
<!-- 两个内容 -->
<el-col>负责人</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-menu>
</el-dropdown>
</el-col>
</el-row>
</el-col>
</el-row>
<!-- 下面就是树形控件内容了 -->
</el-card>
树形组件认识
接下来,实现树形的结构,采用element的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) | — | — |
isLeaf | 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效 | boolean, function(data, node) | — | — |
data是组成树形数据的关键,如下的数据便能构建树形数据
[
label: '一级 1',
children: [
label: '二级 1-1',
children: [
label: '三级 1-1-1'
]
]
,
label: '一级 2',
children: [
label: '二级 2-1',
children: [
label: '三级 2-1-1'
]
,
label: '二级 2-2',
children: [
label: '三级 2-2-1'
]
]
,
label: '一级 3',
children: [
label: '二级 3-1',
children: [
label: '三级 3-1-1'
]
,
label: '二级 3-2',
children: [
label: '三级 3-2-1'
]
]
]
实现树形的静态组织架构
由此,我们首先实现静态数据的组织架构
<!--放置一个属性 这里的props和我们之前学习的父传子 的props没关系-->
<el-tree :data="departs" :props="defaultProps" />
export default
data()
return
defaultProps:
label: 'name'
,
departs: [
name: '总裁办', children: [ name: '董事会' ] ,
name: '行政部' ,
name: '人事部'
]
接下来,对每个层级节点增加显示内容,此时需要用到tree的插槽
<template>
<div class="dashboard-container">
<div class="app-container">
<!-- 实现页面的基本布局 -->
<el-card>
<!--省略了头部内容-->
<!--放置一个属性 这里的props和我们之前学习的父传子 的props没关系-->
<el-tree :data="departs" :props="defaultProps" :default-expand-all="true">
<!-- 传入内容 插槽内容 会循环多次 有多少节点 就循环多少次 -->
<!-- 作用域插槽 slot-scope="obj" 接收传递给插槽的数据 data 每个节点的数据对象-->
<el-row slot-scope="data" type="flex" justify="space-between" align="middle" style="width:100%;height:40px;">
<!-- 左侧内容 -->
<el-col>
<span> data.name </span>
</el-col>
<!-- 右侧内容 -->
<el-col :span="4">
<el-row type="flex" justify="end">
<el-col> data.manager </el-col>
<el-col>
<!-- 放置下拉菜单 -->
<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>
</el-tree>
</el-card>
</div>
</div>
</template><script>
export default
name: 'Departments',
data()
return
defaultProps:
label: 'name'
,
departs: [
name: '总裁办', manager: '曹操', children: [ name: '董事会', manager: '曹丕' ] ,
name: '行政部', manager: '刘备' ,
name: '人事部', manager: '孙权'
]
</script><style> </style>
将树形的操作内容单独抽提成组件
将树形的操作内容单独抽提成组件
封装单独的树操作栏组件
通过第一个章节,我们发现,树形的顶级内容实际和子节点的内容是一致的,此时可以将该部分抽提成一个组件,节省代码
组件 src/views/departments/components/tree-tools.vue
<template>
<el-row type="flex" justify="space-between" align="middle" style="height: 40px;width: 100%">
<el-col>
<!-- 名称应该变成 对应的节点中的name -->
<span> treeNode.name </span>
</el-col>
<el-col :span="4">
<el-row type="flex" justify="end">
<!-- 两个内容 -->
<el-col> treeNode.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>
<script>
// 该组件需要对外开放属性 外部需要提供一个对象 对象里需要有name manager
export default
// props可以用数组来接收数据 也可以用对象来接收
// props: props属性: 配置选项
props:
// 定义一个props属性
treeNode:
type: Object, // 对象类型
required: true // 要求对方使用您的组件的时候 必须传treeNode属性 如果不传 就会报错
</script>
在组织架构中应用操作栏组件
接下来,在src/views/departments/index.vue
进行代码的简化
<template>
<div class="dashboard-container">
<div class="app-container">
<!-- 实现页面的基本布局 -->
<el-card class="tree-card">
<!-- 用了一个行列布局 -->
<!-- 缺少treeNode -->
<tree-tools :tree-node="company" />
<!--放置一个属性 这里的props和我们之前学习的父传子 的props没关系-->
<el-tree :data="departs" :props="defaultProps" default-expand-all>
<!-- 说明el-tree里面的这个内容 就是插槽内容 => 填坑内容 => 有多少个节点循环多少次 -->
<!-- scope-scope 是 tree组件传给每个节点的插槽的内容的数据 -->
<!-- 顺序一定是 执行slot-scope的赋值 才去执行 props的传值 -->
<tree-tools slot-scope=" data " :tree-node="data" />
</el-tree>
</el-card>
</div>
</div>
</template>
获取组织架构数据,并进行树形处理
获取真实的组织架构数据,并将其转化成树形数据显示在页面上
封装API接口,获取组织架构数据
在钩子函数中调用接口
import TreeTools from './components/tree-tools'
import getDepartments from '@/api/departments'
export default
components:
TreeTools
,
data()
return
company: , // 就是头部的数据结构
departs: [],
defaultProps:
label: 'name' // 表示 从这个属性显示内容
,
created()
this.getDepartments() // 调用自身的方法
,
methods:
async getDepartments()
const result = await getDepartments()
this.company = name: result.companyName, manager: '负责人'
this.departs = result.depts // 需要将其转化成树形结构
console.log(result)
将数组数据转化成树形结构
我们需要将列表型的数据,转化成树形数据,这里需要用到递归算法
封装一个工具方法,src/utils/index.js
/** *
*
* 将列表型的数据转化成树形数据 => 递归算法 => 自身调用自身 => 一定条件不能一样, 否则就会死循环
* 遍历树形 有一个重点 要先找一个头儿
* ***/
export function tranListToTreeData(list, rootValue)
var arr = []
list.forEach(item =>
if (item.pid === rootValue)
// 找到之后 就要去找 item 下面有没有子节点
const children = tranListToTreeData(list, item.id)
if (children.length)
// 如果children的长度大于0 说明找到了子节点
item.children = children
arr.push(item) // 将内容加入到数组中
)
return arr
调用转化方法,转化树形结构
this.company = name: result.companyName, manager: '负责人' // 这里定义一个空串 因为 它是根 所有的子节点的数据pid 都是 ""
this.departs = tranListToTreeData(result.depts, '')
删除部门功能实现
封装删除接口,注册下拉菜单事件
在tree-tools组件中,监听下拉菜单的点击事件 src/views/departments/index.vue
<el-dropdown @command="operateDepts">
<span>
操作<i class="el-icon-arrow-down" />
</span>
<!-- 下拉菜单 -->
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="add">添加子部门</el-dropdown-item>
<!-- 编辑部门和删除部门只会在子节点上显示 -->
<el-dropdown-item v-if="!isRoot" command="edit">编辑部门</el-dropdown-item>
<el-dropdown-item v-if="!isRoot" command="del">删除部门</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
dropdown下拉菜单的监听事件command
// 操作节点调用的方法
operateDepts(type)
if (type === 'add')
// 添加子部门的操作
else if (type === 'edit')
// 编辑部门的操作
else
// 删除操作
调用删除接口,通知父组件更新数据
删除之前,提示用户是否删除,然后调用删除接口
// 操作节点调用的方法
operateDepts(type)
if (type === 'add')
// 添加子部门的操作
else if (type === 'edit')
// 编辑部门的操作
else
// 删除操作
this.$confirm('确定要删除该部门吗').then(() =>
// 如果点击了确定就会进入then
return delDepartments(this.treeNode.id) // 返回promise对象
).then(() =>
// 如果删除成功了 就会进入这里
)
通过自定义事件this.$emit
的方式来进行
// 如果删除成功了 就会进入这里
this.$emit('delDepts') // 触发自定义事件
this.$message.success('删除部门成功')
父组件监听事件 src/views/department/index.vue
<tree-tools slot-scope="obj" :tree-node="obj.data" @delDepts="getDepartments" />
新增部门功能-建立组件
封装新增接口,新建组件中的弹层结构
我们需要构建一个新增部门的窗体组件 src/views/department/components/add-dept.vue
其中的交互设计如下
<template>
<!-- 新增部门的弹层 -->
<el-dialog title="新增部门">
<!-- 表单组件 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>
点击新增子部门显示弹层组件
我们需要用属性控制组件的显示或者隐藏
// 需要传入一个props变量来控制 显示或者隐藏 props:
showDialog:
type: Boolean,
default: false
<el-dialog title="新增部门" :visible="showDialog">
在departments/index.vue
中引入该组件
import AddDept from './components/add-dept' // 引入新增部门组件
export default
components: AddDept
定义控制窗体显示的变量showDialog
data()
return
showDialog: false // 显示窗体
,
<!-- 放置新增弹层组件 -->
<add-dept :show-dialog="showDialog" />
子组件触发新增事件· src/views/departments/tree-tools.vue
if (type === 'add')
// 添加子部门的操作
// 告诉父组件 显示弹层
this.$emit('addDepts', this.treeNode) // 为何传出treeNode 因为是添加子部门 需要当前部门的数据
父组件监听事件
2处添加
<tree-tools slot-scope="data" :tree-node="data" @delDepts="getDepartments" @addDepts="addDepts" />
<tree-tools :tree-node="company" :is-root="true" @delDepts="getDepartments" @addDepts="addDepts" />
方法中弹出层,记录在哪个节点下添加子部门
addDepts(node)
this.showDialog = true // 显示弹层
// 因为node是当前的点击的部门, 此时这个部门应该记录下来,
this.node = node
完成新增部门的规则校验
完成新增表单的基本校验条件
部门名称(name):必填 1-50个字符 / 同级部门中禁止出现重复部门
部门编码(code):必填 1-50个字符 / 部门编码在整个模块中都不允许重复
部门负责人(manager):必填
部门介绍 ( introduce):必填 1-300个字符
定义数据结构
formData:
name: '', // 部门名称
code: '', // 部门编码
manager: '', // 部门管理者
introduce: '' // 部门介绍
,
完成表单校验需要的前置条件
-
el-form配置model和rules属性
-
el-form-item配置prop属性
-
表单进行v-model双向绑定
配置新增表单的基本校验规则
data()
return
// 定义表单数据
formData:
name: '', // 部门名称
code: '', // 部门编码
manager: '', // 部门管理者
introduce: '' // 部门介绍
,
// 定义校验规则
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'
],
manager: [ required: true, message: '部门负责人不能为空', trigger: 'blur' ],
introduce: [
required: true, message: '部门介绍不能为空', trigger: 'blur' ,
trigger: 'blur', min: 1, max: 300, message: '部门介绍要求1-50个字符'
]
部门名称和部门编码的自定义校验
部门名称和部门编码的规则 有两条我们需要通过自定义校验函数validator
来实现
在校验名称和编码时,要获取最新的组织架构,这也是我们这里trigger采用blur的原因,因为change对于访问的频率过高,我们需要控制访问频率
部门名称不能和同级别
的重复,这里注意,我们需要找到所有同级别的数据,进行校验,所以还需要另一个参数pid
props:
// 用来控制窗体是否显示或者隐藏
showDialog:
type: Boolean,
default: false
,
// 当前操作的节点
treeNode:
type: Object,
default: null
,
<add-dept :show-dialog="showDialog" :tree-node="node" />
根据当前部门id,找到所有子部门相关的数据,判断是否重复
// 现在定义一个函数 这个函数的目的是 去找 同级部门下 是否有重复的部门名称
const checkNameRepeat = async(rule, value, callback) =>
// 先要获取最新的组织架构数据
const depts = await getDepartments()
// depts是所有的部门数据
// 如何去找技术部所有的子节点
const isRepeat = depts.filter(item => item.pid === this.treeNode.id).some(item => item.name === value)
isRepeat ? callback(new Error(`同级部门下已经有$value的部门了`)) : callback()
检查部门编码的过程同理
// 检查编码重复
const checkCodeRepeat = async(rule, value, callback) =>
// 先要获取最新的组织架构数据
const depts = await getDepartments()
const isRepeat = depts.some(item => item.code === value && value) // 这里加一个 value不为空 因为我们的部门有可能没有code
isRepeat ? callback(new Error(`组织架构中已经有部门使用$value编码`)) : callback()
在规则中定义
// 定义校验规则
rules:
name: [
required: true, message: '部门名称不能为空', trigger: 'blur' ,
min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: 'blur' ,
// 自定义函数的形式校验
trigger: 'blur',validator: checkNameRepeat
],
code: [
required: true, message: '部门编码不能为空', trigger: 'blur' ,
min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: 'blur' ,
trigger: 'blur',validator: checkCodeRepeat
],
manager: [ required: true, message: '部门负责人不能为空', trigger: 'blur' ],
introduce: [
required: true, message: '部门介绍不能为空', trigger: 'blur' ,
trigger: 'blur', min: 1, max: 300, message: '部门介绍要求1-50个字符'
]
处理首部内容的pid数据
在最根级的tree-tools
组件中,由于treenode属性中没有id,id便是undefined,但是通过undefined进行等值判断是寻找不到对应的根节点的, 所以在传值时,我们将id属性设置为 “”
src/views/departments/index.vue
async getDepartments()
const result = await getDepartments()
this.departs = tranListToTreeData(result.depts, '')
this.company = name: result.companyName, manager: '负责人', id: ''
清洁代码,清洁架构和清洁项目布局/项目结构
我已经阅读过Robert C. Martin的干净代码和干净的架构(尚未完成),但我还不太了解。如果我有干净的代码,我也有干净的架构吗?如果我有干净的代码和干净的架构,我是否有良好的项目结构?那么,他们之间有什么不同呢?干净的代码,干净的架构和良好的项目结构。它们之间的关系是什么或它们如何相关,我如何才能获得良好的项目结构,干净的架构和干净的代码?谢谢。
“清洁架构”是关于“子系统”与软件系统组件之间的界限和依赖关系。它有助于构建代码以实现可变性。通过以下“清洁建筑”将为您提供“良好”的项目结构。
有关“清洁架构”如何使您的项目结构“尖叫”的更多详细信息,请参阅我的博客系列:http://www.plainionist.net/Implementing-Clean-Architecture-Scream/
“清洁代码”是关于“子系统”,组件,类和功能的实现。它有助于构建代码以实现可读性和可维护性。
以上是关于人资项目day06-组织架构树形结构布局的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud Alibaba商城实战项目基础篇(day03)