SaaS-HRM(3)企业部门管理前后台

本文详细介绍了一个企业组织架构管理系统的设计与实现过程,包括需求分析、数据库表设计、微服务实现、前端展示等方面的内容。系统实现了企业部门的基本CRUD操作,如添加、修改、删除和查询部门信息,以及部门树形结构的展示。

知识点:

理解RBAC模型的基本概念及设计思路
了解SAAS-HRM中权限控制的需求及表结构分析
完成组织机构的基本CRUD操作
完成用户管理的基本CRUD操作
完成角色管理的基本CRUD操作

1 组织机构管理

1.1 需求分析

1.1.1 需求分析

实现企业组织结构管理,实现部门的基本CRUD操作

 1.1.2 数据库表设计

CREATE TABLE `co_department` (
`id` varchar(40) NOT NULL,
`company_id` varchar(255) NOT NULL COMMENT '企业ID',
`pid` varchar(255) DEFAULT NULL COMMENT '父级部门ID',
`name` varchar(255) NOT NULL COMMENT '部门名称',
`code` varchar(255) NOT NULL COMMENT '部门编码',
`category` varchar(255) DEFAULT NULL COMMENT '部门类别',
`manager_id` varchar(255) DEFAULT NULL COMMENT '负责人ID',
`city` varchar(255) DEFAULT NULL COMMENT '城市',
`introduce` text COMMENT '介绍',
`create_time` datetime NOT NULL COMMENT '创建时间',
`manager` varchar(40) DEFAULT NULL COMMENT '部门负责人',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

1.2 微服务实现

1.2.1 实现基本CRUD操作

(1)实体类
在ihrm_common_model工程的com.zdw.ihrm.domain.company 包下创建Department实体类

package com.zdw.ihrm.domain.company;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;

/**
 * (Department)实体类
 */
@Entity
@Table(name = "co_department")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department implements Serializable {
    private static final long serialVersionUID = -9084332495284489553L;
    //ID
    @Id
    private String id;
    /**
     * 父级ID
     */
    private String pid;
    /**
     * 企业ID
     */
    private String companyId;
    /**
     * 部门名称
     */
    private String name;
    /**
     * 部门编码,同级部门不可重复
     */
    private String code;

    /**
     * 负责人ID
     */
    private String managerId;
    /**
     *  负责人名称
     */
    private String manager;

    /**
     * 介绍
     */
    private String introduce;
    /**
     * 创建时间
     */
    private Date createTime;
}

创建查询所有的时候,返回的实体类:DeptListResult

package com.zdw.ihrm.domain.company.response;

import com.zdw.ihrm.domain.company.Company;
import com.zdw.ihrm.domain.company.Department;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

/**
 * Create By zdw on 2019/8/11
 */
@Getter
@Setter
@NoArgsConstructor
public class DeptListResult {
    private String companyId;
    private String companyName;
    private String companyManage;//公司联系人
    private List<Department> depts;

    public DeptListResult(Company company, List depts) {
        this.companyId = company.getId();
        this.companyName = company.getName();
        this.companyManage = company.getLegalRepresentative();//公司联系人
        this.depts = depts;
    }
}

(2)持久化层dao

在ihrm_company工程的包com.zdw.ihrm.company.dao下面创建:DepartmentDao

package com.zdw.ihrm.company.dao;

import com.zdw.ihrm.domain.company.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * Create By zdw on 2019/8/11
 */
public interface DepartmentDao extends JpaRepository<Department,String>,JpaSpecificationExecutor<Department> {
}

(3)业务层

在ihrm_company工程的包com.zdw.ihrm.company.service下面创建:DepartmentService

package com.zdw.ihrm.company.service;

import com.ihrm.common.utils.IdWorker;
import com.zdw.ihrm.company.dao.DepartmentDao;
import com.zdw.ihrm.domain.company.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.List;

/**
 * Create By zdw on 2019/8/11
 */
@Service
public class DepartmentService {
    @Autowired
    private DepartmentDao departmentDao;
    @Autowired
    private IdWorker idWorker;
    /**
     * 添加部门
     */
    public void save(Department department) {
        //填充其他参数
        department.setId(idWorker.nextId() + "");
        department.setCreateTime(new Date());
        departmentDao.save(department);
    }
    /**
     * 更新部门信息
     */
    public void update(Department department) {
        Department sourceDepartment = departmentDao.findById(department.getId()).get();
        sourceDepartment.setName(department.getName());
        sourceDepartment.setPid(department.getPid());
        sourceDepartment.setManagerId(department.getManagerId());
        sourceDepartment.setIntroduce(department.getIntroduce());
        sourceDepartment.setManager(department.getManager());
        departmentDao.save(sourceDepartment);
    }
    /**
     * 根据ID获取部门信息
     *
     * @param id 部门ID
     * @return 部门信息
     */
    public Department findById(String id) {
        Optional<Company> optional = companyDao.findById(id);
        if(optional.isPresent()){
            return optional.get();
        }else{
            return null;
        }
    }

    /**
     * 删除部门
     *
     * @param id 部门ID
     */
    public void delete(String id) {
        departmentDao.deleteById(id);
    }
    /**
     * 获取部门列表
     */
    public List<Department> findAll(String companyId) {
        /**
         * 用户构造查询条件
         *      1.只查询companyId
         *      2.很多的地方都需要根据companyId查询
         *      3.很多的对象中都具有companyId
         *
         */
        Specification<Department> spec = new Specification<Department>() {
            /**
             * 用户构造查询条件
             *      root   :包含了所有的对象数据
             *      cq     :一般不用
             *      cb     :构造查询条件
             */
            public Predicate toPredicate(Root<Department> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                //根据企业id查询
                return cb.equal(root.get("companyId").as(String.class),companyId);
            }
        };
        return departmentDao.findAll(spec);
    }
}

(4)控制层

在ihrm_company工程的包com.zdw.ihrm.company.controller下面创建:DepartmentController

package com.zdw.ihrm.company.controller;

import com.ihrm.common.entity.Result;
import com.ihrm.common.entity.ResultCode;
import com.zdw.ihrm.company.service.CompanyService;
import com.zdw.ihrm.company.service.DepartmentService;
import com.zdw.ihrm.domain.company.Company;
import com.zdw.ihrm.domain.company.Department;
import com.zdw.ihrm.domain.company.response.DeptListResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Create By zdw on 2019/8/11
 */
@CrossOrigin
@RestController
@RequestMapping("/company")
public class DepartmentController {
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private CompanyService companyService;
    /**
     * 添加部门
     */
    @RequestMapping(value = "/departments", method = RequestMethod.POST)
    public Result add(@RequestBody Department department) throws Exception {
        department.setCompanyId("1");//先写死
        departmentService.save(department);
        return Result.SUCCESS();
    }
    /**
     * 修改部门信息
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.PUT)
    public Result update(@PathVariable(name = "id") String id, @RequestBody Department
            department) throws Exception {
        department.setCompanyId("1");//先写死
        department.setId(id);
        departmentService.update(department);
        return Result.SUCCESS();
    }
    /**
     * 删除部门
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.DELETE)
    public Result delete(@PathVariable(name = "id") String id) throws Exception {
        departmentService.delete(id);
        return Result.SUCCESS();
    }
    /**
     * 根据id查询
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.GET)
    public Result findById(@PathVariable(name = "id") String id) throws Exception {
        Department department = departmentService.findById(id);
        return new Result(ResultCode.SUCCESS,department);
    }
    /**
     * 组织架构列表
     */
    @RequestMapping(value = "/departments", method = RequestMethod.GET)
    public Result findAll() throws Exception {
        Company company = companyService.findById("1");
        List<Department> list = departmentService.findAll("1");
        return new Result(ResultCode.SUCCESS,new DeptListResult(company,list));
    }
}

1.2.2 postman测试

1.2.3 抽取公共代码

(1)在模块ihrm_common的pom.xml引入下面的坐标:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    </dependencies>

(2) 公共controller

因为我们很多地方可能都要用到企业id和企业名称,后面甚至还会用到Resquest和Response对象,所以把这部分代码抽取出来,其他的类只要集成该基本的controller,自然就能获取到这些数据。
在ihrm_common模块下的com.ihrm.common.controller 包下添加公共BaseController

package com.ihrm.common.controller;

import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Create By zdw on 2019/8/11
 */
public class BaseController {
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    @ModelAttribute//这个注解的作用:在实例化字类对象的时候,会先执行该方法
    public void setReqAndResp(HttpServletRequest request, HttpServletResponse response)
    {
        this.request = request;
        this.response = response;
    }
    //企业id,(暂时使用1,以后会动态获取)
    public String parseCompanyId() {
        return "1";
    }
    public String parseCompanyName() {
        return "江苏教育股份有限公司";
    }
}

(3) 公共service

因为很多地方都需要根据企业id去查询企业信息,所以我们也可以抽取出来。
ihrm_common模块下的com.ihrm.common.service 包下添加公共BaseService

package com.ihrm.common.service;

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class BaseService<T> {

    protected Specification<T> getSpec(String companyId) {
        Specification<T> spect = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder cb) {
                //根据企业id查询
                return cb.equal(root.get("companyId").as(String.class),companyId);
            }
        };
        return spect;
    }
}

1.2.4 修改之前的代码

修改DepartmentService,让其集成BaseService,修改findAll方法:

public class DepartmentService extends BaseService<Department> {
    /**
     * 获取部门列表
     */
    public List<Department> findAll(String companyId) {
        /**
         * 用户构造查询条件
         *      1.只查询companyId
         *      2.很多的地方都需要根据companyId查询
         *      3.很多的对象中都具有companyId
         *
         */
//        Specification<Department> spec = new Specification<Department>() {
//            /**
//             * 用户构造查询条件
//             *      root   :包含了所有的对象数据
//             *      cq     :一般不用
//             *      cb     :构造查询条件
//             */
//            public Predicate toPredicate(Root<Department> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
//                //根据企业id查询
//                return cb.equal(root.get("companyId").as(String.class),companyId);
//            }
//        };
        Specification<Department> spec = getSpec(companyId);
        return departmentDao.findAll(spec);
    }
}
修改DepartmentController,让其集成BaseController,修改之后如下:
package com.zdw.ihrm.company.controller;

import com.ihrm.common.controller.BaseController;
import com.ihrm.common.entity.Result;
import com.ihrm.common.entity.ResultCode;
import com.zdw.ihrm.company.service.CompanyService;
import com.zdw.ihrm.company.service.DepartmentService;
import com.zdw.ihrm.domain.company.Company;
import com.zdw.ihrm.domain.company.Department;
import com.zdw.ihrm.domain.company.response.DeptListResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Create By zdw on 2019/8/11
 */
@CrossOrigin
@RestController
@RequestMapping("/company")
public class DepartmentController extends BaseController {
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private CompanyService companyService;
    /**
     * 添加部门
     */
    @RequestMapping(value = "/departments", method = RequestMethod.POST)
    public Result add(@RequestBody Department department) throws Exception {
        //department.setCompanyId("1");//先写死
        department.setCompanyId(parseCompanyId());//通过父类获取企业的id
        departmentService.save(department);
        return Result.SUCCESS();
    }
    /**
     * 修改部门信息
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.PUT)
    public Result update(@PathVariable(name = "id") String id, @RequestBody Department
            department) throws Exception {
        //department.setCompanyId("1");//先写死
        department.setCompanyId(parseCompanyId());//通过父类获取企业的id
        department.setId(id);
        departmentService.update(department);
        return Result.SUCCESS();
    }
    /**
     * 删除部门
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.DELETE)
    public Result delete(@PathVariable(name = "id") String id) throws Exception {
        departmentService.delete(id);
        return Result.SUCCESS();
    }
    /**
     * 根据id查询
     */
    @RequestMapping(value = "/departments/{id}", method = RequestMethod.GET)
    public Result findById(@PathVariable(name = "id") String id) throws Exception {
        Department department = departmentService.findById(id);
        return new Result(ResultCode.SUCCESS,department);
    }
    /**
     * 组织架构列表
     */
    @RequestMapping(value = "/departments", method = RequestMethod.GET)
    public Result findAll() throws Exception {
        String companyId = parseCompanyId();//通过父类获取企业的id
        Company company = companyService.findById(companyId);
        List<Department> list = departmentService.findAll(companyId);
        return new Result(ResultCode.SUCCESS,new DeptListResult(company,list));
    }
}

1.3 组织机构前端实现

1.3.1 创建组织机构模块

在前端代码的目录(我的目录是:D:\IDEA\IDEAWorkspace\SaaS-HRM\UI_code\project-saas-hrm-vue-master\src\)下,创建组织机构模块:module-departments,在它的下面创建相关的子目录,具体结构如下:

其中的components目录是空的,pages目录放置的是我们的vue视图,router目录下面是路由规则文件index.js,store下面的app.js也是空的,index.js是跟demo目录里面的差不多的:

router目录下的index.js文件内容如下:

import Layout from '@/module-dashboard/pages/layout'
const _import = require('@/router/import_' + process.env.NODE_ENV)

export default [
  {
    root: true,
    path: '/departments',
    component: Layout,
    redirect: 'noredirect',
    name: 'departments',
    meta: {
      title: '公司组织架构管理',
      icon: 'architecture'
    },
    children: [
      {
        path: 'index',
        component: _import('departments/pages/index'),
        name: 'organizations-index',
        meta: {title: '公司组织架构', icon: 'architecture', noCache: true}
      }
    ]
  }
]

1.3.2 注册刚才的模块到项目中

在src/main.js中,注册刚才的模块:

import departments from '@/module-departments/' //刚新添加的 企业组织架构管理

Vue.use(departments, store)  //注册  刚新添加的 企业组织架构管理

1.3.3 配置请求后台的API

在 /src/api/base/ 创建departments.js作为组织机构管理的API公共接口方法

import {createAPI, createFormAPI} from '@/utils/request'  //导入相关工具类,框架自己提供的

//第一个参数/company是请求路径(路径可以是完全路径,也可以是部分路径,因为我们在config/dev.env.js下面有前缀配置),
//  BASE_API: '"http://localhost:9001/"'     第二参数是请求方式,第三个参数请求的参数数据
export const list = data => createAPI('/company/departments', 'get', data) //查询企业对应的所有组织机构

export const save = data => createAPI('/company/departments', 'post', data) //保存

export const update = data => createAPI('/company/departments/'+data.id, 'put', data) //修改

export const deleteById = data => createAPI('/company/departments/'+data.id, 'delete', data) //删除

export const findById = data => createAPI('/company/departments/'+data.id, 'get', data) //根据id查询

export const saveOrUpdate = data => {return data.id?update(data):save(data)}  //新增或删除
// data代表请求的对象,${data.id}表示从请求的对象中取出id属性

 

1.3.4 完善index.vue视图

在index.vue视图中,构造企业的部门组织机构树结构,同时添加子部门对话框,实现子部门的增删改查操作,index.vue的完整代码如下:

<template>
  <div class="dashboard-container">
    <div class="app-container">
      <el-card shadow="never">
            <div class='organization-index'>
              <div class='organization-index-top'>
                <div class='main-top-title'>
                  <el-tabs v-model="activeName">
                    <el-tab-pane label="组织结构" name="first"></el-tab-pane>
                    <div class="el-tabs-report">
                      <a class="el-button el-button--primary el-button--mini" title="导出" >导入</a>
                      <a class="el-button el-button--primary el-button--mini" title="导出" >导出</a>
                    </div>
                  </el-tabs>
                </div>
              </div>
              <div style="overflow: scroll;white-space:nowrap"  class="treBox">
                <div class="treeCon clearfix">
                    <span>
                      <i class="fa fa-university" aria-hidden="true"></i>
                      <span ><strong>{{departData.companyName}}</strong></span>
                    </span>
                    <div class="fr">
                      <span class="treeRinfo">
                        <div class="treeRinfo">
                          <span>{{departData.companyManage}}</span>
                          <span>在职  <em class="colGreen" title="在职人数">---</em>&nbsp;&nbsp;(<em class="colGreen" title="正式员工">---</em>&nbsp;/&nbsp;<em class="colRed" title="非正式员工">---</em>)</span>
                        </div>
                        <div class="treeRinfo">
                          <el-dropdown class="item">
                            <span class="el-dropdown-link">
                              操作<i class="el-icon-arrow-down el-icon--right"></i>
                            </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item>
                                  <el-button type="text" @click="handlAdd('')">添加子部门</el-button>
                                </el-dropdown-item>
                              <el-dropdown-item>
                                <el-button type="text" @click="handleList()">查看待分配员工</el-button>
                              </el-dropdown-item>
                            </el-dropdown-menu>
                          </el-dropdown>
                        </div>
                      </span>  
                    </div>
                  </div>

                  <!-- 
                    构造树形列表
                      叶子 <i class="fa fa-male"></i>
                      非叶子 
                        展开 <i class="fa fa-minus-square-o">
                        闭合 <i class="fa fa-plus-square-o">
                    <div class="generalClass" slot-scope="{node,data}" style="width:99%">
                  -->
                  <el-tree :props="{label:'name'}" :data="depts" node-key="id" default-expand-all>
                    <!--
                      node : 是否展开,是否叶子节点
                      data:部门对象   id,name
                     -->
                    <div class="generalClass" slot-scope="{node,data}" style="width:99%">
                        <span>
                           <i v-if="node.isLeaf" class="fa fa-male"></i>
                           <i v-else :class="node.expanded?'fa fa-minus-square-o':'fa fa-plus-square-o'"></i>
                          <span>{{ node.label }}</span>
                        </span>
                         <div class="fr">
                          <span class="treeRinfo">
                            <div class="treeRinfo">
                              <span>{{departData.companyManage}}</span>
                              <span>在职  <em class="colGreen" title="在职人数">---</em>&nbsp;&nbsp;(<em class="colGreen" title="正式员工">---</em>&nbsp;/&nbsp;<em class="colRed" title="非正式员工">---</em>)</span>
                            </div>
                            <div class="treeRinfo">
                              <el-dropdown class="item">
                                <span class="el-dropdown-link">
                                  操作<i class="el-icon-arrow-down el-icon--right"></i>
                                </span>
                                <el-dropdown-menu slot="dropdown">
                                    <el-dropdown-item>
                                      <el-button type="text" @click="handlAdd(data.id)">添加子部门</el-button>
                                    </el-dropdown-item>
                                    <el-dropdown-item>
                                      <el-button type="text" @click="handUpdate(data.id)">查看或修改部门</el-button>
                                    </el-dropdown-item>
                                  <el-dropdown-item>
                                    <el-button type="text" @click="handleList()">查看待分配员工</el-button>
                                  </el-dropdown-item>
                                  <el-dropdown-item>
                                    <el-button type="text" @click="handleDelete(data.id)">删除部门</el-button>
                                  </el-dropdown-item>
                                </el-dropdown-menu>
                              </el-dropdown>
                            </div>
                          </span>  
                        </div>
                      </div>
                    </el-tree>
              </div>
            </div>    
      </el-card>
    </div>
    <!--添加部门对话框-->
    <el-dialog title="编辑部门" :visible.sync="dialogFormVisible">
      <!-- model : 数据模型 -->
      <el-form :model="dept" label-width="120px">
        <el-form-item label="部门名称">
          <el-input v-model="dept.name" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门编码">
          <el-input v-model="dept.code" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门负责人">
          <el-input v-model="dept.manager" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门介绍">
          <el-input v-model="dept.introduce" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveDept">确 定</el-button>
      </div>
    </el-dialog>
</div>
</template>
  
<!-- 引入组件 -->
<script>
import {list,saveOrUpdate,findById,deleteById} from '@/api/base/dept'
import commonApi from '@/utils/common'
export default {
  data() {
    return {
      activeName: 'first', 
      departData:{},   //部门对应的公司信息
      depts:[],   //部门列表

      dialogFormVisible:false,//默认不显示添加部门对话框
      parentId:'',//定义要添加的新部门的父id
      dept:{}  //定义添加的部门对象
    }
  },
  methods: {
    //查询部门树型结构
    getDeptList(){
      //调用API方法查询部门列表
      list().then(res => {
        console.log(res)
        this.departData = res.data.data
        //将普通的数据转化为父子结构
        this.depts = commonApi.transformTozTreeFormat(res.data.data.depts);
      })
    },
    //点击  添加子部门
    handlAdd(parentId){
      console.log(parentId)
      this.dialogFormVisible=true;//点击添加子部门,打开对话框
      this.parentId = parentId;
    },
    //添加子部门对话框的 确定  按钮
    saveDept(){
      this.dept.pid = this.parentId;//给新增部门赋 父id的值
      saveOrUpdate(this.dept).then(res => {
          this.$message({
            message: res.data.message,
            type: res.data.success?'success':'error'  //根据返回值来判断提示的是成功消息还是失败消息
          });
          setTimeout(function(){
            if(res.data.success){//如果成功,就重新加载页面
              location.reload();
            }
          },500)//延迟500毫秒,让客户可以看到提示消息
      });
    },
    //点击  查看部门  按钮
    handUpdate(id){
      //调用 根据id查询部门信息的 API 方法,{id:id} 这种写法是因为我们传的都是对象,所以要按对象封装
      findById({id:id}).then(res => {
        this.dialogFormVisible=true;//显示部门对话框
        this.dept = res.data.data;
      })
    },
    //点击 删除部门  按钮
    handleDelete(id){
      //提示客户是否确定要删除
      this.$confirm('是否删除此条记录?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {//then是点击确定要完成的操作
          //调用根据id删除部门的 api 方法
          deleteById({id:id}).then(res=> {
            this.$message({
              message: res.data.message,
              type: res.data.success?'success':'error'
            });
            setTimeout(function(){
              if(res.data.success) {//删除成功,重新加载页面
                location.reload();
              }
            },600)
        })
      })
    }
  },
  created: function() {
    //钩子方法中调用查询列表的方法
    this.getDeptList();
  },
}
</script>
<style rel="stylesheet/scss" lang="scss">
.el-dropdown {
  color: #000000
}
.el-tree-node__content>.el-tree-node__expand-icon {
  padding:0px;
}
.el-tree-node__expand-icon {
  color:#ffffff
}
.generalClassNode {
  padding-left: 20px;
}
.el-tree-node__content{
  font-size: 16px;
  line-height: 36px;
  height:36px;
}
.custom-tree-node{
  padding-left: 20px;
}
.objectTree {
  overflow: auto;
  z-index: 100;
  width: 300px;
  border: 1px solid #dcdfe6;
  margin-top: 5px;
  left: 70px;
}
.el-tabs__content {
  overflow: initial;
}
.boxpad {
  margin-left: -40px;
}
</style>
<style  rel="stylesheet/scss" lang="scss" scoped>
.el-tree-node__expand-icon{
 
}
.el-icon-caret-right{}
.el-tree-node__content{
  font-size: 14px;
  line-height: 36px;
}
.generalClass {
  font-size: 14px;
  line-height: 36px;
  color:#000000
}
.all {
  position: relative;
  min-height: 100%;
  padding-bottom: 200px;
}
.organization-main:after,
.organization-index-top:after {
  display: block;
  clear: both;
  content: '';
  visibility: hidden;
  height: 0;
}
.organization-main {
  font-size: 14px;
  font-size: 14px;
}

.organization-index {
  padding-bottom: 20px;
  margin-left: 20px;
}
.main-top-title {
  padding-left: 20px;
  padding-top: 20px;
  text-align: left;
}

::-webkit-scrollbar-thumb {
  background-color: #018ee8;
  height: 50px;
  outline-offset: -2px;
  outline: 8px solid #fff;
  -webkit-border-radius: 4px;
}
::-webkit-scrollbar-track-piece {
  background-color: #fff;
  -webkit-border-radius: 0;
}
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-thumb:hover {
  background-color: #fb4446;
  height: 50px;
  -webkit-border-radius: 4px;
}
.modal-total {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background: #000;
  z-index: 90;
  opacity: 0.2;
}
.modal {
  width: 400px;
  height: 300px;
  background-color: #ffffff;
  z-index: 999;
  position: absolute;
  left: 45%;
  top: 20%;
  text-align: center;
}
.treBox {
  padding: 30px 120px 0;
}
.organization-index-top {
  position: relative;

  .el-tabs-report {
    position: absolute;
    top: -50px;
    right: 15px;
  }
}
.treeCon {
  border-bottom: 1px solid #cfcfcf;
  padding: 10px 0;
  margin-bottom: 10px;
  .el-dropdown {
    color: #333;
  }
}
.treeRinfo {
  display: inline-block;
}
.treeRinfo span {
  padding-left: 30px;
}
</style>

 

1.3.5 抽取组件

      组件(Component)是Vue.js 最强大的功能。可以通过将不同的业务拆分为不同的组件进行开发,让代码更加优雅提供可读性。当然也可以封装可重用的代码,通过传入对象的不同,实现组件的复用。

(1)抽取新增/修改页面到 /module-departments/components/add.vue 中

<template>
    <!--添加部门对话框-->
    <el-dialog title="编辑部门" :visible.sync="dialogFormVisible">
      <!-- model : 数据模型 -->
      <el-form :model="dept" label-width="120px">
        <el-form-item label="部门名称">
          <el-input v-model="dept.name" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门编码">
          <el-input v-model="dept.code" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门负责人">
          <el-input v-model="dept.manager" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门介绍">
          <el-input v-model="dept.introduce" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveDept">确 定</el-button>
      </div>
    </el-dialog>
</template>
<script>
import {saveOrUpdate} from '@/api/base/dept'  //引入api方法
export default {
    name:'deptAdd',
    data(){
        return{
            dialogFormVisible:false,//默认不显示添加部门对话框
            parentId:'',//定义要添加的新部门的父id
            dept:{}  //定义添加的部门对象
        }
    },
    methods:{
        //添加子部门对话框的 确定  按钮
        saveDept(){
        this.dept.pid = this.parentId;//给新增部门赋 父id的值
        saveOrUpdate(this.dept).then(res => {
            this.$message({
                message: res.data.message,
                type: res.data.success?'success':'error'  //根据返回值来判断提示的是成功消息还是失败消息
            });
            setTimeout(function(){
                if(res.data.success){//如果成功,就重新加载页面
                location.reload();
                }
            },500)//延迟500毫秒,让客户可以看到提示消息
        });
        }
    }
}
</script>

(2) 在 /module-departments/page/index.vue 中引用组件

导入组件:

import commonApi from '@/utils/common'//写好的公共组件
import deptAdd from './../components/add'  //导入自定义的添加子部门的组件
export default {
  components:{deptAdd},//声明组件
  data() {
    return {
      deptAdd:'deptAdd', //指定组件名称
      activeName: 'first', 
      departData:{},   //部门对应的公司信息
      depts:[],   //部门列表
       // 。。。。
    }
  }

使用组件:

在之前书写添加子部门对话框的地方,使用组件标签引入组件:

<!-- 引入组件 addDept:指定组件
      //v-bind:is (绑定的组件名称)
      //ref : 引用子组件中内容的别名
    -->
    <component v-bind:is="deptAdd" ref="addDept"></component>

改造新增修改方法:

因为现在是要通过父页面来操作组件中的变量,所以需要修改新增和修改子部门的方法:

//点击  添加子部门
    handlAdd(parentId){
      console.log(parentId)
      //this.dialogFormVisible=true;//点击添加子部门,打开对话框
      //this.parentId = parentId;
      //现在是父页面要控制子组件中的变量,通过this.$refs.addDept来操作,(父页面调用子组件中的内容)
      this.$refs.addDept.parentId = parentId;
      this.$refs.addDept.dialogFormVisible = true
    },

//点击  查看部门  按钮
    handUpdate(id){
      //调用 根据id查询部门信息的 API 方法,{id:id} 这种写法是因为我们传的都是对象,所以要按对象封装
      findById({id:id}).then(res => {
        //this.dialogFormVisible=true;//显示部门对话框
        //this.dept = res.data.data;
        //现在是父页面要控制子组件中的变量,通过this.$refs.addDept来操作
        this.$refs.addDept.dept = res.data.data;
        this.$refs.addDept.dialogFormVisible = true
      })
    }

(3)抽取组件后,index.vue的完整代码

<template>
  <div class="dashboard-container">
    <div class="app-container">
      <el-card shadow="never">
            <div class='organization-index'>
              <div class='organization-index-top'>
                <div class='main-top-title'>
                  <el-tabs v-model="activeName">
                    <el-tab-pane label="组织结构" name="first"></el-tab-pane>
                    <div class="el-tabs-report">
                      <a class="el-button el-button--primary el-button--mini" title="导出" >导入</a>
                      <a class="el-button el-button--primary el-button--mini" title="导出" >导出</a>
                    </div>
                  </el-tabs>
                </div>
              </div>
              <div style="overflow: scroll;white-space:nowrap"  class="treBox">
                <div class="treeCon clearfix">
                    <span>
                      <i class="fa fa-university" aria-hidden="true"></i>
                      <span ><strong>{{departData.companyName}}</strong></span>
                    </span>
                    <div class="fr">
                      <span class="treeRinfo">
                        <div class="treeRinfo">
                          <span>{{departData.companyManage}}</span>
                          <span>在职  <em class="colGreen" title="在职人数">---</em>&nbsp;&nbsp;(<em class="colGreen" title="正式员工">---</em>&nbsp;/&nbsp;<em class="colRed" title="非正式员工">---</em>)</span>
                        </div>
                        <div class="treeRinfo">
                          <el-dropdown class="item">
                            <span class="el-dropdown-link">
                              操作<i class="el-icon-arrow-down el-icon--right"></i>
                            </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item>
                                  <el-button type="text" @click="handlAdd('')">添加子部门</el-button>
                                </el-dropdown-item>
                              <el-dropdown-item>
                                <el-button type="text" @click="handleList()">查看待分配员工</el-button>
                              </el-dropdown-item>
                            </el-dropdown-menu>
                          </el-dropdown>
                        </div>
                      </span>  
                    </div>
                  </div>

                  <!-- 
                    构造树形列表
                      叶子 <i class="fa fa-male"></i>
                      非叶子 
                        展开 <i class="fa fa-minus-square-o">
                        闭合 <i class="fa fa-plus-square-o">
                    <div class="generalClass" slot-scope="{node,data}" style="width:99%">
                  -->
                  <el-tree :props="{label:'name'}" :data="depts" node-key="id" default-expand-all>
                    <!--
                      node : 是否展开,是否叶子节点
                      data:部门对象   id,name
                     -->
                    <div class="generalClass" slot-scope="{node,data}" style="width:99%">
                        <span>
                           <i v-if="node.isLeaf" class="fa fa-male"></i>
                           <i v-else :class="node.expanded?'fa fa-minus-square-o':'fa fa-plus-square-o'"></i>
                          <span>{{ node.label }}</span>
                        </span>
                         <div class="fr">
                          <span class="treeRinfo">
                            <div class="treeRinfo">
                              <span>{{departData.companyManage}}</span>
                              <span>在职  <em class="colGreen" title="在职人数">---</em>&nbsp;&nbsp;(<em class="colGreen" title="正式员工">---</em>&nbsp;/&nbsp;<em class="colRed" title="非正式员工">---</em>)</span>
                            </div>
                            <div class="treeRinfo">
                              <el-dropdown class="item">
                                <span class="el-dropdown-link">
                                  操作<i class="el-icon-arrow-down el-icon--right"></i>
                                </span>
                                <el-dropdown-menu slot="dropdown">
                                    <el-dropdown-item>
                                      <el-button type="text" @click="handlAdd(data.id)">添加子部门</el-button>
                                    </el-dropdown-item>
                                    <el-dropdown-item>
                                      <el-button type="text" @click="handUpdate(data.id)">查看或修改部门</el-button>
                                    </el-dropdown-item>
                                  <el-dropdown-item>
                                    <el-button type="text" @click="handleList()">查看待分配员工</el-button>
                                  </el-dropdown-item>
                                  <el-dropdown-item>
                                    <el-button type="text" @click="handleDelete(data.id)">删除部门</el-button>
                                  </el-dropdown-item>
                                </el-dropdown-menu>
                              </el-dropdown>
                            </div>
                          </span>  
                        </div>
                      </div>
                    </el-tree>
              </div>
            </div>    
      </el-card>
    </div>
    <!--添加部门对话框,抽取成组件到components下面的add.vue-->
    <!-- <el-dialog title="编辑部门" :visible.sync="dialogFormVisible"> -->
      <!-- model : 数据模型 -->
      <!--<el-form :model="dept" label-width="120px">
        <el-form-item label="部门名称">
          <el-input v-model="dept.name" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门编码">
          <el-input v-model="dept.code" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门负责人">
          <el-input v-model="dept.manager" autocomplete="off"></el-input>
        </el-form-item>
                <el-form-item label="部门介绍">
          <el-input v-model="dept.introduce" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveDept">确 定</el-button>
      </div>
    </el-dialog> -->

    <!-- 引入组件 addDept:指定组件
      //v-bind:is (绑定的组件名称)
      //ref : 引用子组件中内容的别名
    -->
    <component v-bind:is="deptAdd" ref="addDept"></component>
</div>
</template>
  

<script>
import {list,saveOrUpdate,findById,deleteById} from '@/api/base/dept'
import commonApi from '@/utils/common'//写好的公共组件
import deptAdd from './../components/add'  //导入自定义的添加子部门的组件
export default {
  components:{deptAdd},//声明组件
  data() {
    return {
      deptAdd:'deptAdd', //指定组件名称
      activeName: 'first', 
      departData:{},   //部门对应的公司信息
      depts:[],   //部门列表

      //这三个跟添加子部门相关的三个参数提取到组件中去了,这里可以注释掉
      //dialogFormVisible:false,//默认不显示添加部门对话框
      //parentId:'',//定义要添加的新部门的父id
      //dept:{}  //定义添加的部门对象
    }
  },
  methods: {
    //查询部门树型结构
    getDeptList(){
      //调用API方法查询部门列表
      list().then(res => {
        console.log(res)
        this.departData = res.data.data
        //将普通的数据转化为父子结构
        this.depts = commonApi.transformTozTreeFormat(res.data.data.depts);
      })
    },
    //点击  添加子部门
    handlAdd(parentId){
      console.log(parentId)
      //this.dialogFormVisible=true;//点击添加子部门,打开对话框
      //this.parentId = parentId;
      //现在是父页面要控制子组件中的变量,通过this.$refs.addDept来操作,(父页面调用子组件中的内容)
      this.$refs.addDept.parentId = parentId;
      this.$refs.addDept.dialogFormVisible = true
    },
    //添加子部门对话框的 确定  按钮,这部门代码也抽取到了组件中
    /*saveDept(){
      this.dept.pid = this.parentId;//给新增部门赋 父id的值
      saveOrUpdate(this.dept).then(res => {
          this.$message({
            message: res.data.message,
            type: res.data.success?'success':'error'  //根据返回值来判断提示的是成功消息还是失败消息
          });
          setTimeout(function(){
            if(res.data.success){//如果成功,就重新加载页面
              location.reload();
            }
          },500)//延迟500毫秒,让客户可以看到提示消息
      });
    },*/
    //点击  查看部门  按钮
    handUpdate(id){
      //调用 根据id查询部门信息的 API 方法,{id:id} 这种写法是因为我们传的都是对象,所以要按对象封装
      findById({id:id}).then(res => {
        //this.dialogFormVisible=true;//显示部门对话框
        //this.dept = res.data.data;
        //现在是父页面要控制子组件中的变量,通过this.$refs.addDept来操作
        this.$refs.addDept.dept = res.data.data;
        this.$refs.addDept.dialogFormVisible = true
      })
    },
    //点击 删除部门  按钮
    handleDelete(id){
      //提示客户是否确定要删除
      this.$confirm('是否删除此条记录?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {//then是点击确定要完成的操作
          //调用根据id删除部门的 api 方法
          deleteById({id:id}).then(res=> {
            this.$message({
              message: res.data.message,
              type: res.data.success?'success':'error'
            });
            setTimeout(function(){
              if(res.data.success) {//删除成功,重新加载页面
                location.reload();
              }
            },600)
        })
      })
    }
  },
  created: function() {
    //钩子方法中调用查询列表的方法
    this.getDeptList();
  },
}
</script>
<style rel="stylesheet/scss" lang="scss">
.el-dropdown {
  color: #000000
}
.el-tree-node__content>.el-tree-node__expand-icon {
  padding:0px;
}
.el-tree-node__expand-icon {
  color:#ffffff
}
.generalClassNode {
  padding-left: 20px;
}
.el-tree-node__content{
  font-size: 16px;
  line-height: 36px;
  height:36px;
}
.custom-tree-node{
  padding-left: 20px;
}
.objectTree {
  overflow: auto;
  z-index: 100;
  width: 300px;
  border: 1px solid #dcdfe6;
  margin-top: 5px;
  left: 70px;
}
.el-tabs__content {
  overflow: initial;
}
.boxpad {
  margin-left: -40px;
}
</style>
<style  rel="stylesheet/scss" lang="scss" scoped>
.el-tree-node__expand-icon{
 
}
.el-icon-caret-right{}
.el-tree-node__content{
  font-size: 14px;
  line-height: 36px;
}
.generalClass {
  font-size: 14px;
  line-height: 36px;
  color:#000000
}
.all {
  position: relative;
  min-height: 100%;
  padding-bottom: 200px;
}
.organization-main:after,
.organization-index-top:after {
  display: block;
  clear: both;
  content: '';
  visibility: hidden;
  height: 0;
}
.organization-main {
  font-size: 14px;
  font-size: 14px;
}

.organization-index {
  padding-bottom: 20px;
  margin-left: 20px;
}
.main-top-title {
  padding-left: 20px;
  padding-top: 20px;
  text-align: left;
}

::-webkit-scrollbar-thumb {
  background-color: #018ee8;
  height: 50px;
  outline-offset: -2px;
  outline: 8px solid #fff;
  -webkit-border-radius: 4px;
}
::-webkit-scrollbar-track-piece {
  background-color: #fff;
  -webkit-border-radius: 0;
}
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-thumb:hover {
  background-color: #fb4446;
  height: 50px;
  -webkit-border-radius: 4px;
}
.modal-total {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background: #000;
  z-index: 90;
  opacity: 0.2;
}
.modal {
  width: 400px;
  height: 300px;
  background-color: #ffffff;
  z-index: 999;
  position: absolute;
  left: 45%;
  top: 20%;
  text-align: center;
}
.treBox {
  padding: 30px 120px 0;
}
.organization-index-top {
  position: relative;

  .el-tabs-report {
    position: absolute;
    top: -50px;
    right: 15px;
  }
}
.treeCon {
  border-bottom: 1px solid #cfcfcf;
  padding: 10px 0;
  margin-bottom: 10px;
  .el-dropdown {
    color: #333;
  }
}
.treeRinfo {
  display: inline-block;
}
.treeRinfo span {
  padding-left: 30px;
}
</style>

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值