Преглед на файлове

直接访问fm的表,数据不再存储到数据中台

lixing преди 4 години
родител
ревизия
e9033c4a20
променени са 29 файла, в които са добавени 1613 реда и са изтрити 0 реда
  1. 37 0
      fm-person/src/main/java/com/persagy/fm/common/client/FeignConfig.java
  2. 25 0
      fm-person/src/main/java/com/persagy/fm/common/model/ConvertDmpTool.java
  3. 39 0
      fm-person/src/main/java/com/persagy/fm/common/utils/DmpResultUtil.java
  4. 42 0
      fm-person/src/main/java/com/persagy/fm/department/constant/enums/DeptTypeEnum.java
  5. 39 0
      fm-person/src/main/java/com/persagy/fm/department/constant/enums/ResourceFromEnum.java
  6. 128 0
      fm-person/src/main/java/com/persagy/fm/department/controller/DepartmentController.java
  7. 51 0
      fm-person/src/main/java/com/persagy/fm/department/controller/IDepEnumController.java
  8. 16 0
      fm-person/src/main/java/com/persagy/fm/department/dao/DepartmentMapper.java
  9. 93 0
      fm-person/src/main/java/com/persagy/fm/department/model/ConvertDepartmentTool.java
  10. 49 0
      fm-person/src/main/java/com/persagy/fm/department/model/Department.java
  11. 40 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/AddDepartmentDTO.java
  12. 20 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/DeleteDepartmentDTO.java
  13. 43 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/PageQueryDepartmentDTO.java
  14. 38 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDTO.java
  15. 20 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDetailDTO.java
  16. 16 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentTreeDTO.java
  17. 44 0
      fm-person/src/main/java/com/persagy/fm/department/model/dto/UpdateDepartmentDTO.java
  18. 58 0
      fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentItemVO.java
  19. 58 0
      fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentListItemVO.java
  20. 29 0
      fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentTreeItemVO.java
  21. 31 0
      fm-person/src/main/java/com/persagy/fm/department/service/IDepEnumService.java
  22. 28 0
      fm-person/src/main/java/com/persagy/fm/department/service/IDepTreeService.java
  23. 97 0
      fm-person/src/main/java/com/persagy/fm/department/service/IDepartmentService.java
  24. 44 0
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepEnumServiceImpl.java
  25. 182 0
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepTreeServiceImpl.java
  26. 244 0
      fm-person/src/main/java/com/persagy/fm/department/service/impl/DepartmentServiceImpl.java
  27. 63 0
      fm-person/src/main/java/com/persagy/fm/department/utils/DepDataUtil.java
  28. 17 0
      fm-person/src/main/resources/bootstrap.yml
  29. 22 0
      fm-person/src/main/resources/mapper/DepartmentMapper.xml

+ 37 - 0
fm-person/src/main/java/com/persagy/fm/common/client/FeignConfig.java

@@ -0,0 +1,37 @@
+package com.persagy.fm.common.client;
+
+import feign.Logger;
+import feign.codec.Encoder;
+import feign.form.spring.SpringFormEncoder;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Scope;
+
+import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
+
+@Configuration
+public class FeignConfig {
+
+
+    @Autowired
+    private ObjectFactory<HttpMessageConverters> messageConverters;
+
+
+    @Bean
+    @Primary
+    @Scope(SCOPE_PROTOTYPE)
+    Encoder feignFormEncoder() {
+        return new SpringFormEncoder(new SpringEncoder(this.messageConverters));
+    }
+
+
+    @Bean
+    Logger.Level feignLevel(){
+        return Logger.Level.FULL;
+    }
+}

+ 25 - 0
fm-person/src/main/java/com/persagy/fm/common/model/ConvertDmpTool.java

@@ -0,0 +1,25 @@
+package com.persagy.fm.common.model;
+
+import com.persagy.fm.common.model.RequiredParams;
+import com.persagy.fm.common.model.dto.DmpRequiredParam;
+
+/**
+ * @description:
+ * @author: lixing
+ * @company: Persagy Technology Co.,Ltd
+ * @since: 2021/3/8 2:15 下午
+ * @version: V1.0
+ **/
+public interface ConvertDmpTool {
+    /**
+     * @description: RequiredParams转换为DmpBaseDTO
+     * @param: requiredParams
+     * @return: com.persagy.fm.person.model.dto.DmpBaseDTO
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/3/8 10:46 上午
+     * @version: V1.0
+     */
+    DmpRequiredParam convert2DmpRequiredParam(RequiredParams requiredParams);
+}

+ 39 - 0
fm-person/src/main/java/com/persagy/fm/common/utils/DmpResultUtil.java

@@ -0,0 +1,39 @@
+package com.persagy.fm.common.utils;
+
+import com.persagy.fm.common.response.FmDmpResponseUtil;
+import com.persagy.fm.common.response.FmResponseItem;
+import com.persagy.fm.common.response.FmResponseUtil;
+import com.persagy.fm.department.model.vo.ResponseDepartmentItemVO;
+
+/**
+ * @description:
+ * @author: lixing
+ * @company: Persagy Technology Co.,Ltd
+ * @since: 2021/3/10 11:27 上午
+ * @version: V1.0
+ **/
+public class DmpResultUtil {
+    /**
+     * @description: 处理数据中台创建或更新结果
+     * @param: dmpUpsertResult
+     * @param: id
+     * @param: dmpInterfaceName
+     * @return: com.persagy.fm.common.response.FmResponseItem<com.persagy.fm.person.model.dto.ResponseDepartmentItemVO>
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/3/10 11:26 上午
+     * @version: V1.0
+     */
+    private static FmResponseItem<ResponseDepartmentItemVO> dealDmpUpsertResult(
+            String dmpUpsertResult, Long id, String dmpInterfaceName) {
+        // 处理数据中台返回结果
+        if (FmDmpResponseUtil.isSuccess(dmpUpsertResult)) {
+            ResponseDepartmentItemVO responseDepartmentItemVO = new ResponseDepartmentItemVO();
+            responseDepartmentItemVO.setId(id);
+            return FmResponseUtil.successItem(responseDepartmentItemVO);
+        } else {
+            throw DmpExceptionUtil.rpcException(dmpInterfaceName);
+        }
+    }
+}

+ 42 - 0
fm-person/src/main/java/com/persagy/fm/department/constant/enums/DeptTypeEnum.java

@@ -0,0 +1,42 @@
+package com.persagy.fm.department.constant.enums;
+
+/**
+ * 部门类型
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 3:00 下午
+ */
+public enum DeptTypeEnum {
+    /**
+     * 部门类型
+     */
+    GROUP("0", "集团"),
+    CENTER("1", "中心"),
+    AREA("2", "区域"),
+    COMPANY("3", "分公司"),
+    DEPT("4", "部门");
+
+    private String type;
+    private String desc;
+
+    DeptTypeEnum(String type, String desc) {
+        this.type = type;
+        this.desc = desc;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+}

+ 39 - 0
fm-person/src/main/java/com/persagy/fm/department/constant/enums/ResourceFromEnum.java

@@ -0,0 +1,39 @@
+package com.persagy.fm.department.constant.enums;
+
+/**
+ * 数据来源
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 3:03 下午
+ */
+public enum ResourceFromEnum {
+    /**
+     * 数据来源
+     */
+    USER_CREATE("0", "手动创建"),
+    OA("1", "oa同步");
+
+    private String type;
+    private String desc;
+
+    ResourceFromEnum(String type, String desc) {
+        this.type = type;
+        this.desc = desc;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+}

+ 128 - 0
fm-person/src/main/java/com/persagy/fm/department/controller/DepartmentController.java

@@ -0,0 +1,128 @@
+package com.persagy.fm.department.controller;
+
+import com.persagy.fm.common.constant.enums.BoolEnum;
+import com.persagy.fm.department.service.IDepTreeService;
+import com.persagy.fm.department.service.IDepartmentService;
+import com.persagy.fm.department.service.impl.DepartmentServiceImpl;
+
+import com.persagy.fm.department.utils.DepDataUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import com.persagy.fm.department.model.*;
+import com.persagy.fm.department.model.vo.*;
+import com.persagy.fm.department.model.dto.*;
+import com.persagy.fm.common.response.*;
+import org.springframework.util.CollectionUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 部门控制层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:17
+ */
+@Api(tags = "部门")
+@Validated
+@RestController
+@RequestMapping("departments")
+public class DepartmentController {
+    @Autowired
+    private IDepartmentService departmentService;
+    @Autowired
+    private IDepTreeService depTreeService;
+
+    @ApiOperation(value = "创建部门")
+    @PostMapping("/create")
+    public FmResponseItem<FmResponseUpsertVO> createDepartment(
+            @Valid @RequestBody AddDepartmentDTO addDepartmentDTO) {
+        Long id = departmentService.createDepartment(addDepartmentDTO);
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(id));
+    }
+
+    @ApiOperation(value = "部门详情")
+    @PostMapping("/get")
+    public FmResponseItem<ResponseDepartmentItemVO> queryDepartmentDetail(
+            @Valid @RequestBody QueryDepartmentDetailDTO queryDepartmentDetailDTO) {
+        Department department = departmentService.queryDepartmentDetail(queryDepartmentDetailDTO.getId());
+        ResponseDepartmentItemVO responseDepartmentItemVO = ConvertDepartmentTool.INSTANCE.convert2ResponseItemDTO(department);
+        return FmResponseUtil.successItem(responseDepartmentItemVO);
+    }
+
+
+    @ApiOperation(value = "更新部门")
+    @PostMapping("/update")
+    public FmResponseItem<FmResponseUpsertVO> updateDepartment(
+            @Valid @RequestBody UpdateDepartmentDTO updateDepartmentDTO) {
+        departmentService.updateDepartment(updateDepartmentDTO);
+        return FmResponseUtil.successItem(new FmResponseUpsertVO(updateDepartmentDTO.getId()));
+    }
+
+
+    @ApiOperation(value = "删除部门")
+    @PostMapping("/delete")
+    public FmResponseMsg deleteDepartment(
+            @RequestBody @Valid DeleteDepartmentDTO deleteDepartmentDTO) {
+        departmentService.deleteDepartment(deleteDepartmentDTO.getId());
+        return FmResponseUtil.successMsg("删除成功");
+    }
+
+
+    @ApiOperation(value = "部门列表")
+    @PostMapping("/query")
+    public FmResponseContent<List<ResponseDepartmentListItemVO>> queryDepartment(
+            @Valid @RequestBody QueryDepartmentDTO queryDepartmentDTO) {
+        List<Department> departmentList = departmentService.queryDepartmentList(queryDepartmentDTO);
+        List<ResponseDepartmentListItemVO> resultList = ConvertDepartmentTool.INSTANCE.convert2List(departmentList);
+
+        /* 处理返回结果中是否包含子部门的业务 */
+        if (CollectionUtils.isEmpty(departmentList)) {
+            return FmResponseUtil.successContent(resultList);
+        }
+        // 获取部门的子部门
+        List<Long> deptIds = departmentList.stream().
+                map(Department::getId).
+                collect(Collectors.toList());
+        List<Department> sonDeps = departmentService.queryDepListByParentIds(deptIds);
+        Map<Long, List<Department>> parentIdMap = DepDataUtil.sonDeps2ParentIdMap(sonDeps);
+        resultList.forEach(item -> {
+            // 如果map中包含部门的id,代表部门有子部门
+            if (DepDataUtil.hasChildren(item.getId(), parentIdMap)) {
+                item.setHasChildren(BoolEnum.TRUE.getType());
+            } else {
+                item.setHasChildren(BoolEnum.FALSE.getType());
+            }
+        });
+        return FmResponseUtil.successContent(resultList);
+    }
+
+    //@ApiOperation(value = "部门列表, 分页查询")
+    //@PostMapping("/query")
+    //public FmResponseContent<List<ResponseDepartmentListItemVO>> queryDepartment(
+    //        @Valid @RequestBody PageQueryDepartmentDTO pageQueryDepartmentDTO) {
+    //    IPage<ResponseDepartmentListItemVO> pagedList = departmentService.pageQueryDepartment(pageQueryDepartmentDTO);
+    //    IPage<ResponseDepartmentListItemVO> pagedResultList = pagedList.convert(item -> {
+    //        try {
+    //           return ConvertDepartmentTool.INSTANCE.convert2ResponseListItemDTO(item);
+    //        } catch (Exception e) {
+    //            throw new IllegalArgumentException("分页查询,Department实体类转换为列表对象发生异常", e);
+    //        }
+    //    });
+    //    return FmResponseUtil.successContent(pagedResultList);;
+    //}
+
+    @ApiOperation(value = "部门树")
+    @PostMapping("/tree")
+    public FmResponseContent<List<ResponseDepartmentTreeItemVO>> queryDepartmentTree(
+            @Valid @RequestBody QueryDepartmentTreeDTO queryDepartmentTreeDTO) {
+        List<ResponseDepartmentTreeItemVO> responseDepTreeItems = depTreeService.queryDepartmentTree(queryDepartmentTreeDTO);
+        return FmResponseUtil.successContent(responseDepTreeItems);
+    }
+}
+

+ 51 - 0
fm-person/src/main/java/com/persagy/fm/department/controller/IDepEnumController.java

@@ -0,0 +1,51 @@
+package com.persagy.fm.department.controller;
+
+import com.persagy.fm.common.model.dto.EnumQueryDTO;
+import com.persagy.fm.common.model.vo.EnumVO;
+import com.persagy.fm.common.response.FmResponseContent;
+import com.persagy.fm.common.response.FmResponseUtil;
+import com.persagy.fm.department.service.IDepEnumService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.assertj.core.util.Lists;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * @author lixing
+ * @version V1.0 2021/3/12 6:36 下午
+ **/
+@RestController
+@Validated
+@RequestMapping("/departments/enums")
+@Api(tags = "部门枚举控制层")
+public class IDepEnumController {
+    @Autowired
+    IDepEnumService depEnumService;
+
+    @PostMapping("/get")
+    @ApiOperation(value="查询")
+    public FmResponseContent<List<EnumVO>> queryEnum(
+            @Valid @RequestBody EnumQueryDTO enumQueryDTO) {
+        String type = enumQueryDTO.getType();
+        List<EnumVO> resultList = Lists.newArrayList();
+        switch (type){
+            case "dept_type":
+                resultList = depEnumService.queryDepTypeEnum();
+                break;
+            case "resource_from":
+                resultList = depEnumService.queryDepResourceFromEnum();
+                break;
+            default:
+                break;
+        }
+        return FmResponseUtil.successContent(resultList);
+    }
+}

+ 16 - 0
fm-person/src/main/java/com/persagy/fm/department/dao/DepartmentMapper.java

@@ -0,0 +1,16 @@
+package com.persagy.fm.department.dao;
+
+import com.persagy.fm.department.model.Department;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 部门(Department)dao层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:18
+ */
+@Mapper
+public interface DepartmentMapper extends BaseMapper<Department> {
+
+}

+ 93 - 0
fm-person/src/main/java/com/persagy/fm/department/model/ConvertDepartmentTool.java

@@ -0,0 +1,93 @@
+package com.persagy.fm.department.model;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+import com.persagy.fm.department.model.vo.*;
+import com.persagy.fm.department.model.dto.*;
+
+import java.util.List;
+
+/**
+ * 部门(Department) dto、vo、do转换工具类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19 2021-03-11 15:09:19
+ */
+@Mapper
+public interface ConvertDepartmentTool {
+
+    ConvertDepartmentTool INSTANCE = Mappers.getMapper(ConvertDepartmentTool.class);
+
+    /**
+     * 实体转换为ResponseItemVO
+     *
+     * @param department do对象
+     * @return ResponseItemVO
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:19
+     */
+    ResponseDepartmentItemVO convert2ResponseItemDTO(Department department);
+
+    /**
+     * 实体转换为ResponseListItemVO
+     *
+     * @param department do对象
+     * @return ResponseListItemVO
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:19
+     */
+    ResponseDepartmentListItemVO convert2ResponseListItemDTO(Department department);
+
+    /**
+     * 实体列表转换为ResponseListItemVO列表
+     *
+     * @param departmentList do列表
+     * @return ResponseListItemVO列表
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:19
+     */
+    List<ResponseDepartmentListItemVO> convert2List(List<Department> departmentList);
+
+    /**
+     * addDTO转换为实体
+     *
+     * @param addDepartmentDTO addDTO
+     * @return do对象
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:19
+     */
+    Department convertAddDto2Entity(AddDepartmentDTO addDepartmentDTO);
+
+    /**
+     * updateDTO转换为实体
+     *
+     * @param department 更新前的do对象
+     * @param updateDepartmentDTO updateDTO
+     * @return do对象
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:19
+     */
+    Department convertUpdateDto2Entity(@MappingTarget Department department, UpdateDepartmentDTO updateDepartmentDTO);
+
+    /**
+     * 实体列表换为ResponseTreeItemVO列表
+     *
+     * @param depList 部门实体列表
+     * @return ResponseTreeItemVO列表
+     * @author lixing
+     * @version V1.0 2021/3/12 3:09 下午
+     */
+    List<ResponseDepartmentTreeItemVO> convert2Tree(List<Department> depList);
+
+    /**
+     * 实体转换为树节点对象
+     *
+     * @param department do对象
+     * @return 树节点对象
+     * @author lixing
+     * @version V1.0 2021/3/12 4:40 下午
+     */
+    ResponseDepartmentTreeItemVO convert2TreeItemVO(Department department);
+}
+

+ 49 - 0
fm-person/src/main/java/com/persagy/fm/department/model/Department.java

@@ -0,0 +1,49 @@
+package com.persagy.fm.department.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.persagy.fm.common.model.entity.AuditableEntity;
+
+import java.io.Serializable;
+
+/**
+ * 部门(Department)实体类
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:18
+ */
+@Data
+@ApiModel(description = "部门")
+public class Department extends AuditableEntity<Department> implements Serializable {
+    private static final long serialVersionUID = 729299541515891979L;
+
+    @ApiModelProperty("部门名称")
+    private String name;
+
+    @ApiModelProperty("部门类型")
+    private String type;
+
+    @ApiModelProperty("上级部门id")
+    private Long parentId;
+
+    @ApiModelProperty("数据来源")
+    private String resourceFrom;
+
+    @ApiModelProperty("负责人")
+    private String managers;
+
+    @ApiModelProperty("部门全路径")
+    private String fullPath;
+
+    @ApiModelProperty("编制人数")
+    private Integer staffCount;
+
+    public static String PROP_NAME = "name";
+    public static String PROP_TYPE = "type";
+    public static String PROP_PARENT_ID = "parent_id";
+    public static String PROP_RESOURCE_FROM = "resource_from";
+    public static String PROP_MANAGERS = "managers";
+    public static String PROP_FULL_PATH = "full_path";
+    public static String PROP_STAFF_COUNT = "staff_count";
+}

+ 40 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/AddDepartmentDTO.java

@@ -0,0 +1,40 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:18
+ */
+@Data
+@ApiModel(value = "创建部门入参")
+public class AddDepartmentDTO {
+    @ApiModelProperty(value = "部门名称", required = true)
+    @NotNull(message = "部门名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "部门类型", required = true)
+    @NotNull(message = "部门类型不能为空")
+    private String type;
+
+    @ApiModelProperty(value = "上级部门id", required = true)
+    @NotNull(message = "上级部门id不能为空")
+    private Long parentId;
+
+    @ApiModelProperty(value = "数据来源", required = true)
+    private String resourceFrom;
+
+    @ApiModelProperty(value = "负责人", required = true)
+    private String managers;
+
+    @ApiModelProperty(value = "部门全路径", required = true)
+    private String fullPath;
+
+    @ApiModelProperty(value = "编制人数", required = true)
+    private Integer staffCount;
+}

+ 20 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/DeleteDepartmentDTO.java

@@ -0,0 +1,20 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19
+ */
+@Data
+@ApiModel(value = "删除部门入参")
+public class DeleteDepartmentDTO {
+    @NotNull(message = "id不能为空")
+    @ApiModelProperty(value = "id", required = true)
+    private Long id;
+
+}

+ 43 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/PageQueryDepartmentDTO.java

@@ -0,0 +1,43 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import com.persagy.fm.common.model.dto.PageDTO;
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19
+ */
+@Data
+@ApiModel(value = "分页查询部门入参")
+public class PageQueryDepartmentDTO extends PageDTO {
+    @ApiModelProperty(value = "id", required = true)
+    private Long id;
+
+    @ApiModelProperty(value = "部门名称", required = true)
+    private String name;
+
+    @ApiModelProperty(value = "部门类型", required = true)
+    private String type;
+
+    @ApiModelProperty(value = "上级部门id", required = true)
+    private String parentId;
+
+    @ApiModelProperty(value = "数据来源", required = true)
+    private String resourceFrom;
+
+//    @ApiModelProperty(value = "负责人", required = true)
+//    private String managers;
+//
+//    @ApiModelProperty(value = "部门全路径", required = true)
+//    private String fullPath;
+//
+//    @ApiModelProperty(value = "编制人数", required = true)
+//    private Integer staffCount;
+//
+//    @ApiModelProperty(value = "是否包含下级部门", required = true)
+//    private String hasChildren;
+
+}

+ 38 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDTO.java

@@ -0,0 +1,38 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19
+ */
+@Data
+@ApiModel(value = "查询部门入参")
+public class QueryDepartmentDTO {
+    @ApiModelProperty(value = "部门名称", required = true)
+    private String name;
+
+    @ApiModelProperty(value = "部门类型", required = true)
+    private String type;
+
+    @ApiModelProperty(value = "上级部门id", required = true)
+    private Long parentId;
+
+    @ApiModelProperty(value = "数据来源", required = true)
+    private String resourceFrom;
+
+//    @ApiModelProperty(value = "负责人", required = true)
+//    private String managers;
+//
+//    @ApiModelProperty(value = "部门全路径", required = true)
+//    private String fullPath;
+//
+//    @ApiModelProperty(value = "编制人数", required = true)
+//    private Integer staffCount;
+//
+//    @ApiModelProperty(value = "是否包含下级部门", required = true)
+//    private String hasChildren;
+
+}

+ 20 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentDetailDTO.java

@@ -0,0 +1,20 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:18
+ */
+@Data
+@ApiModel(value = "获取部门详情入参")
+public class QueryDepartmentDetailDTO {
+    @NotNull(message = "id不能为空")
+    @ApiModelProperty(value = "id", required = true)
+    private Long id;
+
+}

+ 16 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/QueryDepartmentTreeDTO.java

@@ -0,0 +1,16 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021/3/12 4:31 下午
+ */
+@Data
+@ApiModel(value = "查询部门树入参")
+public class QueryDepartmentTreeDTO {
+    @ApiModelProperty("选中的树节点")
+    private Long checkedId;
+}

+ 44 - 0
fm-person/src/main/java/com/persagy/fm/department/model/dto/UpdateDepartmentDTO.java

@@ -0,0 +1,44 @@
+package com.persagy.fm.department.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+
+import lombok.Data;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:18
+ */
+@Data
+@ApiModel(value = "更新部门入参")
+public class UpdateDepartmentDTO {
+    @ApiModelProperty(value = "id", required = true)
+    @NotNull(message = "id不能为空")
+    private Long id;
+
+    @ApiModelProperty(value = "部门名称", required = true)
+    @NotNull(message = "部门名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "部门类型", required = true)
+    @NotNull(message = "部门类型不能为空")
+    private String type;
+
+    @ApiModelProperty(value = "上级部门id", required = true)
+    @NotNull(message = "上级部门id不能为空")
+    private String parentId;
+
+    @ApiModelProperty(value = "数据来源", required = true)
+    private String resourceFrom;
+
+    @ApiModelProperty(value = "负责人", required = true)
+    private String managers;
+
+    @ApiModelProperty(value = "部门全路径", required = true)
+    private String fullPath;
+
+    @ApiModelProperty(value = "编制人数", required = true)
+    private Integer staffCount;
+}

+ 58 - 0
fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentItemVO.java

@@ -0,0 +1,58 @@
+package com.persagy.fm.department.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19
+ */
+@Data
+@ApiModel(value = "部门返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseDepartmentItemVO {
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("部门名称")
+    private String name;
+
+    @ApiModelProperty("部门类型")
+    private String type;
+
+    @ApiModelProperty("上级部门id")
+    private String parentId;
+
+    @ApiModelProperty("数据来源")
+    private String resourceFrom;
+
+    @ApiModelProperty("负责人")
+    private String managers;
+
+    @ApiModelProperty("部门全路径")
+    private String fullPath;
+
+    @ApiModelProperty("编制人数")
+    private Integer staffCount;
+
+    @ApiModelProperty("是否包含下级部门")
+    private String hasChildren;
+
+    @ApiModelProperty("创建人")
+    private String creator;
+
+    @ApiModelProperty("创建时间")
+    private Date creationTime;
+
+    @ApiModelProperty("最后修改人")
+    private String modifier;
+
+    @ApiModelProperty("最后修改时间")
+    private Date modifiedTime;
+
+}

+ 58 - 0
fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentListItemVO.java

@@ -0,0 +1,58 @@
+package com.persagy.fm.department.model.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:19
+ */
+@Data
+@ApiModel(value = "部门列表返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseDepartmentListItemVO {
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("部门名称")
+    private String name;
+
+    @ApiModelProperty("部门类型")
+    private String type;
+
+    @ApiModelProperty("上级部门id")
+    private String parentId;
+
+    @ApiModelProperty("数据来源")
+    private String resourceFrom;
+
+    @ApiModelProperty("负责人")
+    private String managers;
+
+    @ApiModelProperty("部门全路径")
+    private String fullPath;
+
+    @ApiModelProperty("编制人数")
+    private Integer staffCount;
+
+    @ApiModelProperty("是否包含下级部门")
+    private String hasChildren;
+
+    @ApiModelProperty("创建人")
+    private String creator;
+
+    @ApiModelProperty("创建时间")
+    private Date creationTime;
+
+    @ApiModelProperty("最后修改人")
+    private String modifier;
+
+    @ApiModelProperty("最后修改时间")
+    private Date modifiedTime;
+
+}

+ 29 - 0
fm-person/src/main/java/com/persagy/fm/department/model/vo/ResponseDepartmentTreeItemVO.java

@@ -0,0 +1,29 @@
+package com.persagy.fm.department.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author lixing
+ * @version V1.0 2021/3/12 4:31 下午
+ */
+@Data
+@ApiModel(value = "部门列表返回结果参数")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ResponseDepartmentTreeItemVO {
+    @ApiModelProperty("id")
+    private Long id;
+
+    @ApiModelProperty("部门名称")
+    private String name;
+
+    @ApiModelProperty("是否包含下级部门")
+    private String hasChildren;
+
+    @ApiModelProperty("子部门信息")
+    private List<ResponseDepartmentTreeItemVO> children;
+}

+ 31 - 0
fm-person/src/main/java/com/persagy/fm/department/service/IDepEnumService.java

@@ -0,0 +1,31 @@
+package com.persagy.fm.department.service;
+
+import com.persagy.fm.common.model.vo.EnumVO;
+
+import java.util.List;
+
+/**
+ * 部门枚举类接口
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 6:21 下午
+ **/
+public interface IDepEnumService {
+    /**
+     * 部门类型枚举
+     *
+     * @return 部门类型枚举列表
+     * @author lixing
+     * @version V1.0 2021/3/12 6:29 下午
+     */
+    List<EnumVO> queryDepTypeEnum();
+
+    /**
+     * 部门数据来源枚举
+     *
+     * @return 部门数据来源枚举列表
+     * @author lixing
+     * @version V1.0 2021/3/12 6:35 下午
+     */
+    List<EnumVO> queryDepResourceFromEnum();
+}

+ 28 - 0
fm-person/src/main/java/com/persagy/fm/department/service/IDepTreeService.java

@@ -0,0 +1,28 @@
+package com.persagy.fm.department.service;
+
+
+import com.persagy.fm.department.model.dto.QueryDepartmentTreeDTO;
+import com.persagy.fm.department.model.vo.ResponseDepartmentTreeItemVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import java.util.List;
+
+/**
+ * 部门树接口
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 11:48 上午
+ **/
+public interface IDepTreeService {
+
+    /**
+     * 查询部门树
+     *
+     * @param queryDepartmentTreeDTO 部门树查询条件
+     * @return 树节点列表(ResponseTreeItemVO列表)
+     * @author lixing
+     * @version V1.0 2021/3/12 11:53 上午
+     */
+    List<ResponseDepartmentTreeItemVO> queryDepartmentTree(QueryDepartmentTreeDTO queryDepartmentTreeDTO);
+}

+ 97 - 0
fm-person/src/main/java/com/persagy/fm/department/service/IDepartmentService.java

@@ -0,0 +1,97 @@
+package com.persagy.fm.department.service;
+
+import com.persagy.fm.department.model.*;
+import com.persagy.fm.department.model.dto.*;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 部门(Department) service接口
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:09:17
+ */
+public interface IDepartmentService {
+
+    /**
+     * 创建部门
+     *
+     * @param addDepartmentDTO 创建部门入参
+     * @return Long 部门主键
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    Long createDepartment(AddDepartmentDTO addDepartmentDTO);
+
+    /**
+     * 部门详情
+     *
+     * @param id 主键
+     * @return 部门do类
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    Department queryDepartmentDetail(Long id);
+
+    /**
+     * 更新部门
+     *
+     * @param updateDepartmentDTO 更新部门入参
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    void updateDepartment(UpdateDepartmentDTO updateDepartmentDTO);
+
+    /**
+     * 删除部门
+     *
+     * @param id 主键
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    void deleteDepartment(Long id);
+
+    /**
+     * 查询部门
+     *
+     * @param queryDepartmentDTO 查询部门入参
+     * @return List<Department>
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    List<Department> queryDepartmentList(QueryDepartmentDTO queryDepartmentDTO);
+
+    /**
+     * 分页查询部门
+     *
+     * @param pageQueryDepartmentDTO 分页查询入参
+     * @return IPage<Department>
+     * @author lixing
+     * @version V1.0 2021-03-11 15:09:17
+     */
+    IPage<Department> pageQueryDepartment(PageQueryDepartmentDTO pageQueryDepartmentDTO);
+
+    /**
+     * 查询一组父部门的所有子部门
+     *
+     * @param parentDeptList 父部门列表
+     * @return 子部门列表
+     * @author lixing
+     * @version V1.0 2021/3/12 4:22 下午
+     */
+    List<Department> getSonDeps(List<Department> parentDeptList);
+
+    /**
+     * 根据父部门id列表查询这些父部门的所有子部门
+     *
+     * @param parentIds 父部门id列表
+     * @return 子部门列表
+     * @author lixing
+     * @version V1.0 2021/3/12 4:23 下午
+     */
+    List<Department> queryDepListByParentIds(List<Long> parentIds);
+}

+ 44 - 0
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepEnumServiceImpl.java

@@ -0,0 +1,44 @@
+package com.persagy.fm.department.service.impl;
+
+import com.persagy.fm.common.model.vo.EnumVO;
+import com.persagy.fm.department.constant.enums.DeptTypeEnum;
+import com.persagy.fm.department.constant.enums.ResourceFromEnum;
+import com.persagy.fm.department.service.IDepEnumService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 部门枚举service层
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 6:49 下午
+ **/
+@Service
+public class DepEnumServiceImpl implements IDepEnumService {
+    @Override
+    public List<EnumVO> queryDepTypeEnum() {
+        List<EnumVO> resultList = new ArrayList<>(DeptTypeEnum.values().length);
+        Arrays.asList(DeptTypeEnum.values()).forEach(deptTypeEnum -> {
+            EnumVO enumVO = new EnumVO();
+            enumVO.setKey(deptTypeEnum.getType());
+            enumVO.setValue(deptTypeEnum.getDesc());
+            resultList.add(enumVO);
+        });
+        return resultList;
+    }
+
+    @Override
+    public List<EnumVO> queryDepResourceFromEnum() {
+        List<EnumVO> resultList = new ArrayList<>(ResourceFromEnum.values().length);
+        Arrays.asList(ResourceFromEnum.values()).forEach(resourceFromEnum -> {
+            EnumVO enumVO = new EnumVO();
+            enumVO.setKey(resourceFromEnum.getType());
+            enumVO.setValue(resourceFromEnum.getDesc());
+            resultList.add(enumVO);
+        });
+        return resultList;
+    }
+}

+ 182 - 0
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepTreeServiceImpl.java

@@ -0,0 +1,182 @@
+package com.persagy.fm.department.service.impl;
+
+import com.google.common.collect.Lists;
+import com.persagy.fm.common.constant.enums.BoolEnum;
+import com.persagy.fm.department.model.ConvertDepartmentTool;
+import com.persagy.fm.department.model.Department;
+import com.persagy.fm.department.model.dto.QueryDepartmentTreeDTO;
+import com.persagy.fm.department.model.vo.ResponseDepartmentTreeItemVO;
+import com.persagy.fm.department.service.IDepTreeService;
+import com.persagy.fm.department.service.IDepartmentService;
+import com.persagy.fm.department.utils.DepDataUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 部门树业务层
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 11:49 上午
+ */
+@Service
+public class DepTreeServiceImpl implements IDepTreeService {
+    /**
+     * 部门树默认显示3级
+     */
+    private static final int SHOW_LEVEL = 3;
+
+    @Autowired
+    private IDepartmentService departmentService;
+
+    /**
+     * 初始化树节点数据
+     *
+     * @return map 需要展示的每一层级的部门:level -> depList
+     * @author lixing
+     * @version V1.0 2021/3/12 11:58 上午
+     */
+    private Map<Integer, List<Department>> initTreeData(QueryDepartmentTreeDTO queryDepartmentTreeDTO) {
+        if (queryDepartmentTreeDTO.getCheckedId() != null) {
+            // TODO: 2021/3/9
+            return null;
+        } else {
+            return initDefaultTreeData();
+        }
+    }
+
+    /**
+     * 初始化默认树
+     *
+     * @return 需要展示的每一层级的部门:level -> depList
+     * @author lixing
+     * @version V1.0 2021/3/12 12:00 下午
+     */
+    private Map<Integer, List<Department>> initDefaultTreeData() {
+        Map<Integer, List<Department>> levelDepListMap = new HashMap<>(SHOW_LEVEL);
+
+        // TODO: 2021/3/9 根据当前登录人获取根节点
+        // 部门树根节点的父节点id
+        Long rootParentId = 0L;
+        List<Long> rootDeps = Lists.newArrayList(rootParentId);
+
+        return initDefaultTreeData(levelDepListMap, 0, rootDeps);
+    }
+
+    /**
+     * 初始化一层树节点,递归方法,外部调用入参为(0, null)
+     *
+     * @param levelDepListMap level -> depList
+     * @param level           当前层级
+     * @param parentDepIdList 上一层部门Id列表
+     * @return 需要展示的每一层级的部门:level -> depList
+     * @author lixing
+     * @version V1.0 2021/3/12 12:02 下午
+     */
+    public Map<Integer, List<Department>> initDefaultTreeData(
+            Map<Integer, List<Department>> levelDepListMap, int level, List<Long> parentDepIdList) {
+        if (CollectionUtils.isEmpty(parentDepIdList)) {
+            return levelDepListMap;
+        }
+        levelDepListMap.put(level, departmentService.queryDepListByParentIds(parentDepIdList));
+
+        if (level < SHOW_LEVEL) {
+            List<Department> departments = levelDepListMap.get(level);
+            departments = departments == null ? Lists.newArrayList() : departments;
+            List<Long> depIds = departments.stream().map(Department::getId).collect(Collectors.toList());
+            initDefaultTreeData(levelDepListMap, level + 1, depIds);
+        }
+
+        return levelDepListMap;
+    }
+
+    /**
+     * 获取节点的子节点,追加到部门树
+     *
+     * @param levelParentIdMap level -> { parentId -> depList }
+     * @param treeItem 节点
+     * @param level 节点的下一级,例如根节点的下一级为 1
+     * @author lixing
+     * @version V1.0 2021/3/12 3:12 下午
+     */
+    public void setChildren(
+            Map<Integer, Map<Long, List<Department>>> levelParentIdMap,
+            ResponseDepartmentTreeItemVO treeItem, int level) {
+        Map<Long, List<Department>> parentIdMap = levelParentIdMap.get(level);
+        parentIdMap = parentIdMap != null ? parentIdMap : new HashMap<>(0);
+        List<Department> departments = parentIdMap.get(treeItem.getId());
+        List<ResponseDepartmentTreeItemVO> children = ConvertDepartmentTool.INSTANCE.convert2Tree(departments);
+
+        if (CollectionUtils.isEmpty(children)) {
+            treeItem.setHasChildren(BoolEnum.FALSE.getType());
+        } else {
+            treeItem.setHasChildren(BoolEnum.TRUE.getType());
+        }
+
+        // 如果目前显示等级已经大于预设的显示等级,或者当前节点没有子节点了,就停止递归
+        if (level >= SHOW_LEVEL || CollectionUtils.isEmpty(children)) {
+            return;
+        }
+
+        treeItem.setChildren(children);
+        for (ResponseDepartmentTreeItemVO child : children) {
+            setChildren(levelParentIdMap, child, level + 1);
+        }
+    }
+
+    /**
+     * 查询部门树
+     *
+     * @author lixing
+     * @version V1.0 2021/3/12 11:57 上午
+     */
+    @Override
+    public List<ResponseDepartmentTreeItemVO> queryDepartmentTree(
+            QueryDepartmentTreeDTO queryDepartmentTreeDTO) {
+
+        Map<Integer, List<Department>> levelDeptListMap = initTreeData(queryDepartmentTreeDTO);
+
+        // 如果checkedId为空,默认展示三级节点
+        // 如果checkedId不为空,展示到选中的节点所在等级 (>=3级)
+        if (CollectionUtils.isEmpty(levelDeptListMap)) {
+            return Lists.newArrayList();
+        }
+        List<Department> rootList = levelDeptListMap.get(0);
+        if (CollectionUtils.isEmpty(rootList)) {
+            return Lists.newArrayList();
+        }
+
+        // levelDeptListMap 转换为 levelParentIdMap
+        Map<Integer, Map<Long, List<Department>>> levelParentIdMap = covert2LevelParentIdMap(levelDeptListMap);
+
+        List<ResponseDepartmentTreeItemVO> result = ConvertDepartmentTool.INSTANCE.convert2Tree(rootList);
+        result.forEach(treeItem -> {
+            setChildren(levelParentIdMap, treeItem, 1);
+        });
+
+        return result;
+    }
+
+    /**
+     * level -> depList 转换为 level -> { parentId -> deptList }
+     *
+     * @param levelDeptListMap level -> depList
+     * @author lixing
+     * @version V1.0 2021/3/12 2:43 下午
+     */
+    private Map<Integer, Map<Long, List<Department>>> covert2LevelParentIdMap(
+            Map<Integer, List<Department>> levelDeptListMap) {
+        Map<Integer, Map<Long, List<Department>>> levelParentIdMap = new HashMap<>(levelDeptListMap.size());
+        levelDeptListMap.forEach((level, depList) -> {
+            Map<Long, List<Department>> parentIdMap = DepDataUtil.sonDeps2ParentIdMap(depList);
+            levelParentIdMap.put(level, parentIdMap);
+        });
+        return levelParentIdMap;
+    }
+
+}

+ 244 - 0
fm-person/src/main/java/com/persagy/fm/department/service/impl/DepartmentServiceImpl.java

@@ -0,0 +1,244 @@
+package com.persagy.fm.department.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.Lists;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.fm.common.constant.enums.ValidEnum;
+import com.persagy.fm.common.model.RequiredParamsStorage;
+import com.persagy.fm.common.model.dto.Sort;
+import com.persagy.fm.department.constant.enums.ResourceFromEnum;
+import com.persagy.fm.department.dao.DepartmentMapper;
+import com.persagy.fm.department.model.ConvertDepartmentTool;
+import com.persagy.fm.department.model.Department;
+import com.persagy.fm.department.model.dto.AddDepartmentDTO;
+import com.persagy.fm.department.model.dto.PageQueryDepartmentDTO;
+import com.persagy.fm.department.model.dto.QueryDepartmentDTO;
+import com.persagy.fm.department.model.dto.UpdateDepartmentDTO;
+import com.persagy.fm.department.service.IDepartmentService;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 部门(Department) service层
+ *
+ * @author lixing
+ * @version V1.0 2021-03-11 15:10:35
+ */
+@Service
+public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department>
+        implements IDepartmentService {
+
+    @Override
+    public Long createDepartment(AddDepartmentDTO addDepartmentDTO) {
+        // 校验部门名称重复
+        checkDuplicateDeptName(addDepartmentDTO);
+
+        Department department = ConvertDepartmentTool.INSTANCE.convertAddDto2Entity(addDepartmentDTO);
+
+        // 设置默认值
+        setDefaultValue(department);
+
+        save(department);
+        return department.getId();
+    }
+
+    /**
+     * 如果某些字段没有赋值,使用默认的值
+     *
+     * @param department 部门实体
+     * @author lixing
+     * @version V1.0 2021/3/12 12:29 下午
+     */
+    private void setDefaultValue(Department department) {
+        if (StringUtils.isBlank(department.getResourceFrom())) {
+            department.setResourceFrom(ResourceFromEnum.USER_CREATE.getType());
+        }
+
+        if (department.getParentId() == null) {
+            department.setParentId(0L);
+        }
+
+        department.setCreator(RequiredParamsStorage.getUserId());
+    }
+
+    /**
+     * 校验部门名称是否重复
+     *
+     * @author lixing
+     * @version V1.0 2021/3/12 10:49 上午
+     */
+    private void checkDuplicateDeptName(AddDepartmentDTO addDepartmentDTO) {
+        // 拼装查询参数
+        QueryDepartmentDTO queryDepartmentDTO = new QueryDepartmentDTO();
+        queryDepartmentDTO.setName(addDepartmentDTO.getName());
+        queryDepartmentDTO.setParentId(addDepartmentDTO.getParentId());
+
+        // 查询
+        List<Department> departments = queryDepartmentList(queryDepartmentDTO);
+
+        // 处理查询结果
+        if (!CollectionUtils.isEmpty(departments)) {
+            throw new BusinessException(ResponseCode.B0300.getCode(), "创建部门失败,部门名称重复");
+        }
+    }
+
+    @Override
+    public Department queryDepartmentDetail(Long id) {
+        Department department = getById(id);
+        if (department == null) {
+            throw new IllegalArgumentException("查看Department详情时发生异常,找不到要查看的记录,id=" + id);
+        }
+        return department;
+    }
+
+    @Override
+    public void updateDepartment(UpdateDepartmentDTO updateDepartmentDTO) {
+        Department department = getById(updateDepartmentDTO.getId());
+        department = ConvertDepartmentTool.INSTANCE.convertUpdateDto2Entity(department, updateDepartmentDTO);
+        department.setModifier(RequiredParamsStorage.getUserId());
+        updateById(department);
+    }
+
+    /**
+     * 校验部门是否可删除
+     *
+     * @param id 部门主键
+     * @return 部门do类
+     * @author lixing
+     * @version V1.0 2021/3/12 11:02 上午
+     */
+    public Department checkDeletable(Long id) {
+        if (id == null) {
+            throw new IllegalArgumentException("删除Department时发生异常,主键为空");
+        }
+
+        Department department = getById(id);
+
+        if (department == null) {
+            throw new IllegalArgumentException("删除Department时发生异常,找不到要删除的数据,id:" + id);
+        }
+
+        // 查询部门是否有子部门
+        QueryDepartmentDTO queryDepartmentDTO = new QueryDepartmentDTO();
+        queryDepartmentDTO.setParentId(id);
+        List<Department> departments = queryDepartmentList(queryDepartmentDTO);
+
+        if (!CollectionUtils.isEmpty(departments)) {
+            throw new BusinessException(ResponseCode.A10000.getCode(), "当前部门包含子部门,不可删除");
+        }
+
+        // TODO: 2021/3/9   部门包含员工时,不可删除
+
+        return department;
+    }
+
+    @Override
+    public void deleteDepartment(Long id) {
+        // 校验部门是否可删除
+        Department department = checkDeletable(id);
+
+        department.setValid(ValidEnum.FALSE.getType());
+        updateById(department);
+    }
+
+    @Override
+    public List<Department> queryDepartmentList(QueryDepartmentDTO queryDepartmentDTO) {
+        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(Department.PROP_VALID, ValidEnum.TRUE.getType());
+        // 默认按创建时间倒序排序
+        queryWrapper.orderBy(true, true, Department.PROP_CREATIONTIME);
+        if (queryDepartmentDTO != null) {
+
+            if (StringUtils.isNotEmpty(queryDepartmentDTO.getName())) {
+                queryWrapper.like(Department.PROP_NAME, queryDepartmentDTO.getName());
+            }
+
+            if (StringUtils.isNotEmpty(queryDepartmentDTO.getType())) {
+                queryWrapper.eq(Department.PROP_TYPE, queryDepartmentDTO.getType());
+            }
+
+            if (queryDepartmentDTO.getParentId() != null) {
+                queryWrapper.eq(Department.PROP_PARENT_ID, queryDepartmentDTO.getParentId());
+            }
+
+            if (StringUtils.isNotEmpty(queryDepartmentDTO.getResourceFrom())) {
+                queryWrapper.eq(Department.PROP_RESOURCE_FROM, queryDepartmentDTO.getResourceFrom());
+            }
+        }
+        return list(queryWrapper);
+    }
+
+    @Override
+    public IPage<Department> pageQueryDepartment(PageQueryDepartmentDTO pageQueryDepartmentDTO) {
+        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(Department.PROP_VALID, ValidEnum.TRUE.getType());
+        // 这里认为pageQueryDTO是经过校验的,肯定包含分页信息
+        IPage<Department> pageParam = new Page<>(pageQueryDepartmentDTO.getPage(), pageQueryDepartmentDTO.getSize(), true);
+        // 排序信息
+        if (CollectionUtils.isEmpty(pageQueryDepartmentDTO.getOrders())) {
+            // 默认按创建时间倒序排序
+            queryWrapper.orderBy(true, true, Department.PROP_CREATIONTIME);
+        } else {
+            List<Sort> orders = pageQueryDepartmentDTO.getOrders();
+            for (Sort sort : orders) {
+                // 将驼峰转换为下划线格式
+                sort.setColumn(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, sort.getColumn()));
+                queryWrapper.orderBy(true, sort.isAsc(), sort.getColumn());
+            }
+        }
+
+        if (StringUtils.isNotEmpty(pageQueryDepartmentDTO.getName())) {
+            queryWrapper.like(Department.PROP_NAME, pageQueryDepartmentDTO.getName());
+        }
+
+        if (StringUtils.isNotEmpty(pageQueryDepartmentDTO.getType())) {
+            queryWrapper.eq(Department.PROP_TYPE, pageQueryDepartmentDTO.getType());
+        }
+
+        if (StringUtils.isNotEmpty(pageQueryDepartmentDTO.getParentId())) {
+            queryWrapper.eq(Department.PROP_PARENT_ID, pageQueryDepartmentDTO.getParentId());
+        }
+
+        if (StringUtils.isNotEmpty(pageQueryDepartmentDTO.getResourceFrom())) {
+            queryWrapper.eq(Department.PROP_RESOURCE_FROM, pageQueryDepartmentDTO.getResourceFrom());
+        }
+
+        return getBaseMapper().selectPage(pageParam, queryWrapper);
+    }
+
+    @Override
+    public List<Department> getSonDeps(List<Department> parentDeptList) {
+        if (CollectionUtils.isEmpty(parentDeptList)) {
+            return Lists.newArrayList();
+        } else {
+            List<Long> parentIds = parentDeptList.stream().map(Department::getId).collect(Collectors.toList());
+            List<Department> sonDeps = queryDepListByParentIds(parentIds);
+            return sonDeps == null ? Lists.newArrayList() : sonDeps;
+        }
+    }
+
+    @Override
+    public List<Department> queryDepListByParentIds(List<Long> parentIds) {
+        // 拼装查询条件
+        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(Department.PROP_VALID, ValidEnum.TRUE.getType());
+        // 按创建时间倒序排序
+        queryWrapper.orderBy(true, true, Department.PROP_CREATIONTIME);
+
+        if (CollectionUtils.isEmpty(parentIds)) {
+            throw new IllegalArgumentException("根据父节点查询子部门,parentIds为空");
+        }
+        queryWrapper.in(Department.PROP_PARENT_ID, parentIds);
+
+        return list(queryWrapper);
+    }
+}

+ 63 - 0
fm-person/src/main/java/com/persagy/fm/department/utils/DepDataUtil.java

@@ -0,0 +1,63 @@
+package com.persagy.fm.department.utils;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.persagy.fm.department.model.Department;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 部门数据工具类
+ *
+ * @author lixing
+ * @version V1.0 2021/3/12 3:06 下午
+ **/
+public class DepDataUtil {
+
+    /**
+     * 子部门列表转换为:子部门parentId -> 子部门列表的map
+     *
+     * @param sonDeps 子部门列表
+     * @return map 子部门parentId -> 子部门列表
+     * @author lixing
+     * @version V1.0 2021/3/12 2:49 下午
+     */
+    public static Map<Long, List<Department>> sonDeps2ParentIdMap(List<Department> sonDeps) {
+        if (CollectionUtils.isEmpty(sonDeps)) {
+            return Maps.newHashMap();
+        }
+
+        Map<Long, List<Department>> result = new HashMap<>(sonDeps.size());
+        sonDeps.forEach(sonDep -> {
+            List<Department> departments = result.get(sonDep.getParentId());
+            if (departments == null) {
+                departments = Lists.newArrayList(sonDep);
+                result.put(sonDep.getParentId(), departments);
+            } else {
+                departments.add(sonDep);
+            }
+        });
+
+        return result;
+    }
+
+
+    /**
+     * 判断一个部门是否为一组部门中某些部门的父部门
+     *
+     * @param depId 需要判断的父部门id
+     * @param parentIdMap 子部门parentId -> 子部门列表
+     * @return boolean
+     * @author lixing
+     * @version V1.0 2021/3/12 3:21 下午
+     */
+    public static boolean hasChildren(Long depId, Map<Long, List<Department>> parentIdMap) {
+        if (depId == null) {
+            return false;
+        }
+        return parentIdMap.get(depId) != null;
+    }
+}

+ 17 - 0
fm-person/src/main/resources/bootstrap.yml

@@ -0,0 +1,17 @@
+spring:
+  application:
+    name: fm-person
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://192.168.100.210:33306/fm_person?useUnicode=true&characterEncoding=utf-8&mysqlEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: 123456
+    type: com.alibaba.druid.pool.DruidDataSource
+
+server:
+  port: ${SERVER_PORT:8814}
+
+#mybatis-plus:
+#  mapper-locations: classpath*:/mapper/*Mapper.xml
+#  typeAliasesPackage: com.persagy.fm.test.model.entity
+

+ 22 - 0
fm-person/src/main/resources/mapper/DepartmentMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.persagy.fm.department.dao.DepartmentDao">
+    <resultMap id="DepartmentMap" type="com.persagy.fm.department.model.Department">
+        <result column="id" property="id"/>
+        <result column="name" property="name"/>
+        <result column="type" property="type"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="resource_from" property="resourceFrom"/>
+        <result column="managers" property="managers"/>
+        <result column="full_path" property="fullPath"/>
+        <result column="staff_count" property="staffCount"/>
+        <result column="has_children" property="hasChildren"/>
+        <result column="ts" property="ts"/>
+        <result column="creator" property="creator"/>
+        <result column="creation_time" property="creationTime"/>
+        <result column="modifier" property="modifier"/>
+        <result column="modified_time" property="modifiedTime"/>
+        <result column="valid" property="valid"/>
+    </resultMap>
+</mapper>
+