毕设人力资源系统开发日记——第五天

        首先祝各位同学国庆快乐!这下就可以明目张胆地拖更好几天了。。。OvO

        言归正传,今天的任务是完成组织架构的树形数据展示,以及新增部门的功能。

一. 组织架构数据展示

1. 实现思路

        查阅Element文档,我们选择了 el-tree 这一树形组件,同时还需要对获取的数据进行处理,使其生成树形组件所需要的数据结构。

2. 代码实现

        1.1 树形组件基本结构

        这里的 el-tree 组件涉及到一些常用属性, default-expand-all 表示默认全部展开所有层级,expand-on-click-node 表示点击左侧的小三角才会展开层级,方便我们点击右侧的操作。

        右侧的结构由 template 实现,这里存放负责人和操作下拉菜单。

<div class="app-container">
      <el-tree
        class="filter-tree"
        :data="depts"
        :props="defaultProps"
        default-expand-all
        :expand-on-click-node="false"
      >
        <template #default="{ node, data }">
          <span class="custom-tree-node">
            <span>{{ node.label }}</span>
            <span>
              <span style="margin-right: 20px">{{ data.managerName }}</span>
              <el-dropdown
                trigger="click"
                @command="operateDept($event, data.id)"
              >
                <el-icon size="20px"><Setting /></el-icon>
                <template #dropdown>
                  <el-dropdown-menu>
                    <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>
                </template>
              </el-dropdown>
            </span>
          </span>
        </template>
      </el-tree>
    </div>

         1.2 树形组件数据展示

        树形组件需要的基本数据属性为如下,通过 defaultProps 属性获取定位到所需要的字段,label 为展示的组织名称,如总裁办,人事部等等,而 children 为子节点名称,如事业部下的省份事业部。这两个属性会从绑定的数据中寻找符合的数据渲染到树形组件中,如 name:"总裁办",就会渲染总裁办。

//1.基础属性,子组件名称和标题名
const defaultProps = {
  children: "children",
  label: "name",
  managerName: "managerName",
};

        我们通过接口从服务器获取到数据为下图,是没有层级关系的,如果直接渲染,那就是全部都为一级,所以我们需要进行数据处理。        

        我们需要的数据结构为如下,外层为一级层级,子层级为 children 属性下的又一对象 ,还有层级则依次存入 children 属性下。

 

        这里的处理函数属于工具函数,将来的功能中也可能会复用,所以我们存放在 utils 工具函数文件夹下。

        根据获取到的数据特点,我们知道,pid 属性为层级,所有 pid 为0的数据都为一级层级,而 id 属性为数据的唯一标识,数据的 pid 等于另一数据的 id 时,意味着该 pid 的数据是 id 数据的子级,如上图,财务核算部的 pid 为4,人事部的 id 为4,所以财务核算部为人事部的子级。

        已知规律后,就好下手了。开始我们的思路是通过遍历所有数组,先找到第一层级,也就是 pid 为0的数据,再通过 pid==id 进行筛选,获取第二层级,以此往复。但我们并不知道有多少层级,所以要一直循环,这样的方法是不行的。

export function transListToTreeData(list, value) {
    /* 
        转换为树形数据
        1.首先需要找到初始节点,也就是第一层数据,再一步一步寻找后续节点
        2.数组遍历+递归
    */

    list.forEach(item => {
           //1.找到第一层
           if (item.pid === 0) {
               arr.push(item)
               item.children = []
               //2.找到第二层以
               list.forEach(item2 => {
                   // console.log(item2);
                   if (item2.pid == item.id) {
                       let children = item2
                       item.children.push(children)
                   }
               })
           }
   
       });
    return arr
}

        查看了黑马的视频后,我们才知道可以使用递归。递归会自动进行遍历所有数据,不需要考虑层级问题。同时上面的方法还有一个bug,就是 item.children 如果是赋值语句,每一次遍历会覆盖掉原先的数据,所以只能使用数组方法,而下面的递归则是找到所有符合条件的数据,进行打包,再装填到 children 属性中,所以不会出现覆盖问题。

export function transListToTreeData(list, value) {
    /* 
        转换为树形数据
        1.首先需要找到初始节点,也就是第一层数据,再一步一步寻找后续节点
        2.数组遍历+递归
    */
    let arr = []
    list.forEach(item => {
        if (item.pid === value) {
            arr.push(item)
            //进行递归,寻找到所有符合项后一起添加到children属性
            let children = transListToTreeData(list, item.id)
            item.children = children
        }
    });

    return arr
}

         最后将数据添加到 depts 上,就可以进行自动渲染了。这里使用push的原因是,直接赋值会丧失响应式,可能是我少写了什么配置,下次一定改进。。。

//2.组件数据对象
let depts = reactive([]);
//3.获取组织数据
onMounted(() => {
  getDepartmentData();
});

let getDepartmentData = async () => {
  let res = await getDepartment();
  depts.push(transListToTreeData(res, 0)[0]);
};

         2.1 管理员及添加部门操作

        要实现效果为如下。 基本结构在树形组件都已实现。

        添加部门操作是通过一个弹层实现,和之前的修改密码类似,也是 dialog+form 表单的结构。这里我们将其独立为一个组件,方便维护。

<template>
  <div class="container">
    <!-- 放置弹出层 -->
    <el-dialog
      :model-value="showDialog"
      @close="btnCancel"
      title="新增部门"
      width="500px"
    >
      <!-- 表单结构 -->
      <el-form
        ref="addDept"
        :model="formData"
        :rules="rules"
        label-width="120px"
      >
        <el-form-item prop="name" label="部门名称">
          <el-input
            v-model="formData.name"
            placeholder="2-10个字符"
            style="width: 80%"
            size="mini"
          ></el-input>
        </el-form-item>
        <el-form-item prop="code" label="部门编码">
          <el-input
            v-model="formData.code"
            placeholder="2-10个字符"
            style="width: 80%"
            size="mini"
          ></el-input>
        </el-form-item>
        <el-form-item prop="managerId" label="部门负责人">
          <el-select
            v-model="formData.managerId"
            placeholder="请选择负责人"
            style="width: 80%"
            size="mini"
            ><el-option
              v-for="item in managerList"
              :key="item.id"
              :label="item.username"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item prop="introduce" label="部门介绍">
          <el-input
            v-model="formData.introduce"
            type="textarea"
            placeholder="1-100个字符"
            style="width: 80%"
            size="mini"
          ></el-input>
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="btnCancel">取消</el-button>
          <el-button type="primary" @click="btnOk">确定</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

        el-form 表单我们已经熟悉了,四大属性,:model,prop,v-model,:rules。

        这里的校验规则有所不同,我们需要校验是否包含已有数据,后期会连接数据库进行更详细的校验。

//1.表单数据绑定与校验规则
let formData = reactive({
  code: "", //部门编码
  introduce: "", //部门介绍
  managerId: "", //部门负责人
  name: "", //部门名称
  pid: "", //父级项ID
});
let managerList = [];
let rules = {
  code: [
    { required: "true", message: "请输入部门编码", trigger: "blur" },
    { min: 2, max: 10, message: "输入内容应是2-10个字符", trigger: "blur" },
    {
      validator: async (rule, value, callback) => {
        //进行细则校验,查看是否与已有的数据相同
        let result = await getDepartment();
        if (result.some((item) => item.code === value)) {
          return callback(new Error("已有该部门编码"));
        } else {
          callback();
        }
      },
      trigger: "blur",
    },
  ], //部门编码
  introduce: [
    { required: "true", message: "请输入部门介绍", trigger: "blur" },
    { min: 1, max: 100, message: "输入内容应是1-100个字符", trigger: "blur" },
  ], //部门介绍
  managerId: [{ required: "true", message: "请输入负责人", trigger: "blur" }], //部门负责人
  name: [
    { required: "true", message: "请输入部门名称", trigger: "blur" },
    { min: 2, max: 10, message: "输入内容应是2-10个字符", trigger: "blur" },
    {
      validator: async (rule, value, callback) => {
        //进行细则校验,查看是否与已有的数据相同
        let result = await getDepartment();
        if (result.some((item) => item.name === value)) {
          return callback(new Error("已有该部门编码"));
        } else {
          callback();
        }
      },
      trigger: "blur",
    },
  ], //部门名称
};

        这里的表单还需要一个属性,就是 pid ,我们知道 pid 是层级的意思,我们添加部门是需要知道层级的,这样我们才知道要在哪个部门新增。而 pid 是在弹窗组件的父组件中,所以我们采用父子通信进行传值。

        包括 currentNodeId 所在层级id,showDialog 弹窗控制属性,btnCancel 关闭弹窗方法,getDepartmentData 获取部门数据。

<dialog-dept
      :currentNodeId="currentNodeId"
      :showDialog="showDialog"
      @btnCancel="btnCancel"
      @getDepartmentData="getDepartmentData"
    ></dialog-dept>
let props = defineProps(["showDialog", "btnCancel", "currentNodeId"]);
let $emit = defineEmits(["btnCancel", "getDepartmentData"]);

        最后就是点击确定进行重新渲染的工作了。

//3.取消与确定按钮
let addDept = ref();
let btnCancel = () => {
  $emit("btnCancel");
};
let btnOk = () => {
  addDept.value.validate(async (isok) => {
    if (isok) {
      await addDepartment({ ...formData, pid: props.currentNodeId });
      addDept.value.resetFields();
      ElMessage({
        message: "新增部门成功",
        type: "success",
        plain: true,
      });
      $emit("getDepartmentData");
      $emit("btnCancel");
    }
  });
};

二. 今日总结

        今天主要完成了组织架构的部分功能,包括数据展示和新增部门,对数据的处理是一个难题,涉及到了递归思想。以及后面新增部门对父子通信的方法使用,我都不太够熟练,磕磕绊绊很多,还需要多加练习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值