Просмотр исходного кода

feature: 任务类型同步、详情查询修改

mazq 1 год назад
Родитель
Сommit
88f00df7e6
25 измененных файлов с 1284 добавлено и 11 удалено
  1. 56 0
      dcuc-auth-api/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/IAuthSubTaskTypeFacade.java
  2. 1 1
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/auth/entity/RoleInfo.java
  3. 1 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/auth/entity/zerotrust/RoleOperateContent.java
  4. 86 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ApprovalBaseRespDto.java
  5. 47 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ApprovalResultEnum.java
  6. 25 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/CheckTaskTypeItemResp.java
  7. 33 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ExcelImpTaskType.java
  8. 75 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/TaskTypeInfoDto.java
  9. 20 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/TaskTypeReqDto.java
  10. 33 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/vo/tasktype/AuthSubTaskTypeVo.java
  11. 36 0
      dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/vo/tasktype/TaskTypeTreeVo.java
  12. 1 1
      dcuc-auth-service/pom.xml
  13. 0 9
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/auth/service/impl/RoleInfoService.java
  14. 34 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/business/IApproveRemoteCallBusiness.java
  15. 185 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/business/impl/ApproveRemoteCallBusinessImpl.java
  16. 10 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/constance/ApprovalApiConstance.java
  17. 42 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/IAuthSubTaskTypeBusiness.java
  18. 205 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/impl/AuthSubTaskTypeBusinessImpl.java
  19. 60 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthSubTaskType.java
  20. 57 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/AuthSubTaskTypeFacade.java
  21. 25 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthSubTaskTypeRepository.java
  22. 2 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAddSyncRecordService.java
  23. 64 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthSubTaskTypeService.java
  24. 11 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AddSyncRecordServiceImpl.java
  25. 175 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthSubTaskTypeServiceImpl.java

+ 56 - 0
dcuc-auth-api/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/IAuthSubTaskTypeFacade.java

@@ -0,0 +1,56 @@
+package com.dragoninfo.dcuc.auth.sub.facade;
+
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.AuthSubTaskTypeVo;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.TaskTypeTreeVo;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.base.entity.search.SearchDTO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+/**
+ * @author mazq
+ * @date 2023/2/13
+ */
+@FeignClient(name = "dcuc-auth",path = "/dcuc/auth/subTaskTypeFacade")
+public interface IAuthSubTaskTypeFacade {
+
+    /**
+     * 任务类型分页查询
+     *
+     * @param searchDTO
+     * @return
+     */
+    @PostMapping("pageSearch")
+    Page<AuthSubTaskTypeVo> pageSearch(@RequestBody SearchDTO searchDTO);
+
+    /**
+     * 任务类型导入
+     *
+     * @param fileId
+     * @return
+     */
+    @GetMapping("taskTypeImp")
+    ResponseStatus taskTypeImp(@RequestParam("fileId") String fileId);
+
+
+    /**
+     * 任务类型同步
+     * @return
+     */
+    @GetMapping("taskTypeSync")
+    ResponseStatus taskTypeSync();
+
+    /**
+     * 任务类型树
+     * @return
+     */
+    @GetMapping
+    List<TaskTypeTreeVo> taskTypeTree();
+
+}

+ 1 - 1
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/auth/entity/RoleInfo.java

@@ -90,7 +90,7 @@ public class RoleInfo implements IdEntity<String> {
 	private String faceVerifyFlag;
 
     /**
-     * 角色类型 LOCAL:本地角色 ALL:全局角色 默认本地角色
+     * 角色关键状态 LOCAL:本地角色 ALL:全局角色 默认本地角色
      */
     @Column(name = "ROLE_CATEGORY")
     private String roleCategory = "LOCAL";

+ 1 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/auth/entity/zerotrust/RoleOperateContent.java

@@ -16,6 +16,7 @@ import java.io.Serializable;
  * @author mazq
  * @date 2023/4/21
  */
+@EqualsAndHashCode(callSuper = true)
 @EntityListeners({JpaAuditingEntityListener.class})
 @Data
 @Entity

+ 86 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ApprovalBaseRespDto.java

@@ -0,0 +1,86 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author mazq
+ * 审批返回结果
+ */
+@Data
+public class ApprovalBaseRespDto {
+
+    /**
+     * “0000” 表示令牌有效;
+     * 其他值表示无效或接口调用出错
+     */
+    @JsonProperty("status_code")
+    private String statusCode;
+
+    /**
+     * 状态码对应的详细描述
+     */
+    private String message;
+
+    public ApprovalBaseRespDto success() {
+         this.messageEnumMessage(ApprovalResultEnum.SUCCESS);
+         return this;
+    }
+
+    /**
+     * 设置业务枚举
+     *
+     * @param businessRespEnum 业务枚举
+     */
+    public void setBusinessRespEnum(ApprovalResultEnum businessRespEnum) {
+        setStatusCode(businessRespEnum.getValue());
+        setMessage(businessRespEnum.getLabel());
+    }
+
+
+    /**
+     * 设置业务枚举
+     *
+     * @param businessRespEnum 业务枚举
+     */
+    public ApprovalBaseRespDto messageEnumMessage(ApprovalResultEnum businessRespEnum) {
+        this.setBusinessRespEnum(businessRespEnum);
+        return this;
+    }
+
+
+    /**
+     * 设置请求参数异常
+     *
+     * @param businessRespEnum 枚举
+     * @param message          异常信息
+     */
+    public ApprovalBaseRespDto messageEnumMessage(ApprovalResultEnum businessRespEnum, String message) {
+        ApprovalBaseRespDto respDto = new ApprovalBaseRespDto();
+        respDto.setStatusCode(businessRespEnum.getValue());
+        respDto.setMessage(message);
+        return respDto;
+    }
+
+    /**
+     * 是否成功
+     *
+     * @return 是否成功
+     */
+    @JsonIgnore
+    public boolean isRespSuccess() {
+        return this.statusCode.equalsIgnoreCase(ApprovalResultEnum.SUCCESS.getValue());
+    }
+
+    /**
+     * 是否失败
+     *
+     * @return 是否失败
+     */
+    @JsonIgnore
+    public boolean isRespFail() {
+        return !isRespSuccess();
+    }
+
+}

+ 47 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ApprovalResultEnum.java

@@ -0,0 +1,47 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import com.dragonsoft.duceap.base.enums.ICodeEnum;
+
+/**
+ * 审批中心接口返回状态
+ *
+ * @author mazq
+ * @date 2023/4/6
+ */
+public enum ApprovalResultEnum implements ICodeEnum {
+    /**
+     * 成功
+     */
+    SUCCESS("0000", "成功"),
+    /**
+     * 失败
+     */
+    FAIL("0001", "失败");
+
+    ApprovalResultEnum(String value, String label) {
+        this.label = label;
+        this.value = value;
+    }
+
+    private String label;
+
+    private String value;
+
+    @Override
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+}

+ 25 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/CheckTaskTypeItemResp.java

@@ -0,0 +1,25 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import lombok.Data;
+
+/**
+ * <p>
+ * 检查任务返回
+ * </p>
+ *
+ * @author huangzqa
+ * @date 2023/5/31
+ */
+@Data
+public class CheckTaskTypeItemResp {
+
+    /**
+     * 任务类型
+     */
+    private String taskClass;
+
+    /**
+     * 标题
+     */
+    private String title;
+}

+ 33 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/ExcelImpTaskType.java

@@ -0,0 +1,33 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import lombok.Data;
+
+/**
+ * 导入的任务类型
+ *
+ * @author mazq
+ * @date 2023/2/13
+ */
+@Data
+public class ExcelImpTaskType {
+
+    /**
+     * 在excel中的行数
+     */
+    private Integer rowNum;
+
+    /**
+     * 任务类型名称
+     */
+    private String taskTypeName;
+
+    /**
+     * 任务类型编码
+     */
+    private String taskTypeCode;
+
+    /**
+     * 上级编码
+     */
+    private String parentCode;
+}

+ 75 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/TaskTypeInfoDto.java

@@ -0,0 +1,75 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import lombok.Data;
+
+/**
+ * 任务类型返回内容
+ *
+ * @author mazq
+ * @date 2023/5/29
+ */
+@Data
+public class TaskTypeInfoDto {
+
+    /**
+     * id
+     */
+    private int id;
+
+    /**
+     * 任务类型编码
+     */
+    private String code;
+
+    /**
+     * 任务类型名称
+     */
+    private String name;
+
+    /**
+     * 注释
+     */
+    private String remark;
+
+    /**
+     * 层级
+     */
+    private String level;
+
+    /**
+     * 父任务类型ID
+     */
+    private String parentCode;
+
+    /**
+     * 是否叶子节点
+     */
+    private String isLeaf;
+
+    /**
+     * 警种,多警种用英文逗号分隔
+     */
+    private String policeTag;
+
+    /**
+     * 警种和流程关联关系,警种:流程定义ID
+     * 多数据时,每对数据用应用逗号分隔
+     */
+    private String processIds;
+
+    /**
+     * 来源应用ID
+     */
+    private String appId;
+
+    /**
+     * 来源应用名称
+     */
+    private String appName;
+
+    /**
+     * 是否自动审批
+     */
+    private String isAutoReview;
+
+}

+ 20 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/dto/tasktype/TaskTypeReqDto.java

@@ -0,0 +1,20 @@
+package com.dragoninfo.dcuc.auth.sub.dto.tasktype;
+
+import cn.hutool.crypto.SecureUtil;
+import com.dragonsoft.duceap.commons.util.UUIDUtils;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 任务类型查询dto
+ *
+ * @author mazq
+ * @date 2023/5/29
+ */
+@Data
+public class TaskTypeReqDto {
+
+    private String appTokenId;
+
+}

+ 33 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/vo/tasktype/AuthSubTaskTypeVo.java

@@ -0,0 +1,33 @@
+package com.dragoninfo.dcuc.auth.sub.vo.tasktype;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * @author mazq
+ * @date 2023/2/13
+ */
+@Data
+@ApiModel("任务类型Vo")
+public class AuthSubTaskTypeVo {
+
+    @ApiModelProperty(name = "主键id")
+    private String id;
+
+    @ApiModelProperty(name = "任务类型名称")
+    private String taskTypeName;
+
+    @ApiModelProperty(name = "任务类型编码")
+    private String taskTypeCode;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(name = "任务类型创建时间")
+    private Date createTime;
+
+}

+ 36 - 0
dcuc-auth-model/src/main/java/com/dragoninfo/dcuc/auth/sub/vo/tasktype/TaskTypeTreeVo.java

@@ -0,0 +1,36 @@
+package com.dragoninfo.dcuc.auth.sub.vo.tasktype;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * @author mazq
+ * @date 2023/5/29
+ */
+@ApiModel("任务类型树结构Vo")
+@Data
+public class TaskTypeTreeVo {
+
+    @ApiModelProperty(value = "主键id")
+    private String id;
+
+    @ApiModelProperty(value = "任务类型名称")
+    private String name;
+
+    @ApiModelProperty(value = "任务类型编码")
+    private String code;
+
+    @ApiModelProperty(value = "父节点id")
+    private String pid;
+
+    @ApiModelProperty(value = "是否是父节点")
+    private Boolean isParent;
+
+    @ApiModelProperty(value = "子节点信息")
+    private List<TaskTypeTreeVo> children;
+
+}

+ 1 - 1
dcuc-auth-service/pom.xml

@@ -64,7 +64,7 @@
         <dependency>
             <groupId>com.dragoninfo</groupId>
             <artifactId>dcuc-common</artifactId>
-            <version>2.0.1-SNAPSHOT</version>
+            <version>2.1.0-tjdsj-SNAPSHOT</version>
         </dependency>
 
         <dependency>

+ 0 - 9
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/auth/service/impl/RoleInfoService.java

@@ -510,15 +510,6 @@ public class RoleInfoService implements IRoleInfoService {
         this.delete(id);
     }
 
-//    @Override
-//    public DcucRoleVO getDcucRole() {
-//        DcucRoleVO dcucRoleVO = new DcucRoleVO();
-//        dcucRoleVO.setAppCode(dcucAuthConfig.getAppCode());
-//        dcucRoleVO.setRoleManagerCode(dcucAuthConfig.getRoleManagerCode());
-//        dcucRoleVO.setRoleNormalCode(dcucAuthConfig.getRoleNormalCode());
-//        return dcucRoleVO;
-//    }
-
     @Override
     public RoleInfo getRoleInfoByCode(String roleCode) {
         List<RoleInfo> list = roleInfoBPO.findByPropertyValue("code", roleCode);

+ 34 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/business/IApproveRemoteCallBusiness.java

@@ -0,0 +1,34 @@
+package com.dragoninfo.dcuc.auth.business;
+
+import com.dragoninfo.dcuc.auth.sub.dto.tasktype.CheckTaskTypeItemResp;
+import com.dragonsoft.duceap.base.entity.http.ResponseDTO;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+
+/**
+ * <p>
+ * 任务类型调用业务
+ * </p>
+ *
+ * @author huangzqa
+ * @date 2023/5/31
+ */
+public interface IApproveRemoteCallBusiness {
+
+    /**
+     * 任务类型同步
+     *
+     * @return 状态
+     */
+    ResponseStatus syncTaskClass();
+
+    /**
+     * 校验任务ID
+     *
+     * @param appTokenId 应用令牌ID
+     * @param taskId     任务ID
+     * @return 返回内容
+     */
+    ResponseDTO<CheckTaskTypeItemResp> checkTaskIdRequest(String appTokenId, String taskId);
+
+
+}

+ 185 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/business/impl/ApproveRemoteCallBusinessImpl.java

@@ -0,0 +1,185 @@
+package com.dragoninfo.dcuc.auth.business.impl;
+
+import com.dragoninfo.dcuc.auth.business.IApproveRemoteCallBusiness;
+import com.dragoninfo.dcuc.auth.config.DcucAuthConfig;
+import com.dragoninfo.dcuc.auth.constance.ApprovalApiConstance;
+import com.dragoninfo.dcuc.auth.sub.dto.tasktype.ApprovalResultEnum;
+import com.dragoninfo.dcuc.auth.sub.dto.tasktype.CheckTaskTypeItemResp;
+import com.dragoninfo.dcuc.auth.sub.dto.tasktype.TaskTypeInfoDto;
+import com.dragoninfo.dcuc.auth.sub.entity.AuthSubTaskType;
+import com.dragoninfo.dcuc.auth.sub.service.IAuthSubTaskTypeService;
+import com.dragoninfo.dcuc.common.utils.ResponseUtil;
+import com.dragonsoft.duceap.base.entity.http.ResponseDTO;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.commons.util.json.JsonUtils;
+import com.dragonsoft.duceap.commons.util.string.StringUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author huangzqa
+ * @date 2023/5/31
+ */
+@Slf4j
+@Component
+public class ApproveRemoteCallBusinessImpl implements IApproveRemoteCallBusiness {
+
+    private DcucAuthConfig dcucAuthConfig;
+
+    private RestTemplate restTemplate;
+
+    private IAuthSubTaskTypeService taskTypeService;
+
+    @Autowired
+    public void setDcucAuthConfig(DcucAuthConfig dcucAuthConfig) {
+        this.dcucAuthConfig = dcucAuthConfig;
+    }
+
+    @Autowired
+    public void setTaskTypeService(IAuthSubTaskTypeService taskTypeService) {
+        this.taskTypeService = taskTypeService;
+    }
+
+    @Autowired
+    public void setRestTemplate(RestTemplate restTemplate) {
+        this.restTemplate = restTemplate;
+    }
+
+    @Override
+    public ResponseStatus syncTaskClass() {
+        // 查询审批接口获取任务类型
+        ResponseDTO<List<TaskTypeInfoDto>> listResult = getTaskTypeFromApproval();
+        if (ResponseUtil.isFail(listResult)) {
+            return ResponseStatus.fail(listResult.getMessage());
+        }
+        List<TaskTypeInfoDto> result = ResponseUtil.getResult(listResult);
+        saveOrUpdateByCodes(result);
+
+        return ResponseStatus.success("同步成功");
+    }
+
+
+    /**
+     * 校验任务ID
+     *
+     * @param taskId     任务ID
+     * @param appTokenId 应用令牌ID
+     * @return 返回内容
+     */
+    @Override
+    public ResponseDTO<CheckTaskTypeItemResp> checkTaskIdRequest(String appTokenId, String taskId) {
+        String baseUrl = dcucAuthConfig.getApprovalCenterUrl();
+        String taskIdCheckUrl = baseUrl + ApprovalApiConstance.TASK_ID_CHECK_URL;
+        TypeReference<ResponseDTO<CheckTaskTypeItemResp>> typeReference = new TypeReference<ResponseDTO<CheckTaskTypeItemResp>>() {
+        };
+        log.info("获取审批任务详情地址:{}", taskIdCheckUrl);
+        return baseGet("获取审批任务详情", "获取审批任务详情失败", taskIdCheckUrl, typeReference);
+    }
+
+    /**
+     * 流程详情
+     *
+     * @param url 路径
+     * @param req 请求参数
+     * @return 返回内容
+     */
+    protected <R, S> ResponseDTO<S> basePostReq(String url, R req, String requestName, TypeReference<ResponseDTO<S>> typeReference) {
+        // 打印请求参数
+        log.info(requestName + " 请求路径:{} 请求参数:{}", url, JsonUtils.toJSONString(req));
+        String errorTip = requestName + "失败";
+        HttpEntity<R> entity = new HttpEntity<>(req);
+        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
+
+        return getsResponseDTO(requestName, typeReference, errorTip, exchange);
+    }
+
+    private <S> ResponseDTO<S> getsResponseDTO(String requestName, TypeReference<ResponseDTO<S>> typeReference, String errorTip, ResponseEntity<String> exchange) {
+        if (!exchange.getStatusCode().is2xxSuccessful()) {
+            log.error("{} error. resp: {}", requestName, JsonUtils.toJSONString(exchange));
+            return ResponseUtil.dtoFail(errorTip);
+        }
+        String body = exchange.getBody();
+        if (StringUtils.isBlank(body)) {
+            log.error("{} error. resp: {}", requestName, JsonUtils.toJSONString(exchange));
+            return ResponseUtil.dtoFail(errorTip);
+        }
+
+        log.info("baseReq resp :{}", JsonUtils.toJSONString(exchange));
+
+        ResponseDTO<S> respDto;
+        ObjectMapper mapper = new ObjectMapper();
+        // 忽略不对应的字段
+        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        try {
+            JsonNode jsonNode = mapper.readTree(body);
+            String statusCode = jsonNode.get("statusCode").asText();
+            String message = jsonNode.get("message").asText();
+            if (ApprovalResultEnum.SUCCESS.getValue().equals(statusCode)) {
+                respDto = mapper.readValue(body, typeReference);
+            } else {
+                return ResponseUtil.dtoFail(message);
+            }
+        } catch (JsonProcessingException e) {
+            log.error("parse error.", e);
+            return ResponseUtil.dtoFail("返回值解析失败");
+        }
+        return respDto;
+    }
+
+    /**
+     * 请求获取任务类型
+     *
+     * @return 返回内容
+     */
+    protected ResponseDTO<List<TaskTypeInfoDto>> getTaskTypeFromApproval() {
+        String baseUrl = dcucAuthConfig.getApprovalCenterUrl();
+        String url = baseUrl + ApprovalApiConstance.CLASS_TYPE_URL;
+        TypeReference<ResponseDTO<List<TaskTypeInfoDto>>> typeReference = new TypeReference<ResponseDTO<List<TaskTypeInfoDto>>>() {
+        };
+        log.info("获取审批任务列表地址:{}", url);
+        return baseGet("获取审批任务列表", "获取任务列表失败", url, typeReference);
+    }
+
+    private <S> ResponseDTO<S> baseGet(String reqName, String errorTip, String url, TypeReference<ResponseDTO<S>> typeReference, Object... param) {
+        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class, param);
+        return getsResponseDTO(reqName, typeReference, errorTip, exchange);
+    }
+
+    /**
+     * 更新任务类型信息
+     *
+     * @param listResult 类型类型结果
+     */
+    private void saveOrUpdateByCodes(List<TaskTypeInfoDto> listResult) {
+        if (CollectionUtils.isNotEmpty(listResult)) {
+            List<AuthSubTaskType> collect = listResult.stream()
+                    .map(e -> {
+                        AuthSubTaskType taskType = new AuthSubTaskType();
+                        taskType.setTaskTypeCode(e.getCode());
+                        taskType.setTaskTypeName(e.getName());
+                        taskType.setParentCode(e.getParentCode());
+                        return taskType;
+                    }).collect(Collectors.toList());
+            taskTypeService.saveByCodes(collect);
+        }
+    }
+
+}

+ 10 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/constance/ApprovalApiConstance.java

@@ -51,4 +51,14 @@ public class ApprovalApiConstance {
      * 查询审批流程定义api
      */
     public static final String APPROVAL_DEFINE_API = "/approve-core/api/v1/processes/{businessCode}";
+
+    /**
+     * 任务校验地址
+     */
+    public static final String TASK_ID_CHECK_URL = "/approve-core/api/v1/tasks/{taskCode}";
+
+    /**
+     * 任务列表获取地址
+     */
+    public static final String CLASS_TYPE_URL = "/approve-core/api/v1/task-classes";
 }

+ 42 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/IAuthSubTaskTypeBusiness.java

@@ -0,0 +1,42 @@
+package com.dragoninfo.dcuc.auth.sub.business;
+
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.AuthSubTaskTypeVo;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.TaskTypeTreeVo;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.base.entity.search.SearchDTO;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+/**
+ * 任务类型管理业务类
+ *
+ * @author mazq
+ * @date 2023/2/13
+ */
+public interface IAuthSubTaskTypeBusiness {
+
+    /**
+     * 任务类型导入
+     *
+     * @param fileId 文件ID
+     * @return 状态
+     */
+    ResponseStatus authSubTaskTypeImp(String fileId);
+
+    /**
+     * 任务类型分页查询
+     *
+     * @param searchDTO 搜索
+     * @return 任务类型
+     */
+    Page<AuthSubTaskTypeVo> pageSearch(SearchDTO searchDTO);
+
+    /**
+     * 任务类型树
+     *
+     * @return 树
+     */
+    List<TaskTypeTreeVo> taskTypeTree();
+
+}

+ 205 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/impl/AuthSubTaskTypeBusinessImpl.java

@@ -0,0 +1,205 @@
+package com.dragoninfo.dcuc.auth.sub.business.impl;
+
+import com.dragoninfo.dcuc.auth.constance.Constant;
+import com.dragoninfo.dcuc.auth.sub.business.IAuthSubTaskTypeBusiness;
+import com.dragoninfo.dcuc.auth.sub.dto.tasktype.ExcelImpTaskType;
+import com.dragoninfo.dcuc.auth.sub.entity.AuthSubTaskType;
+import com.dragoninfo.dcuc.auth.sub.service.IAuthSubTaskTypeService;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.AuthSubTaskTypeVo;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.TaskTypeTreeVo;
+import com.dragoninfo.dcuc.auth.util.ImportUtil;
+import com.dragoninfo.dcuc.common.utils.DcucBeanUtil;
+import com.dragoninfo.dcuc.duceap.facade.IDuceapUploadFacade;
+import com.dragoninfo.dcuc.duceap.upload.dto.DocContentDTO;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.base.entity.search.SearchDTO;
+import com.dragonsoft.duceap.commons.util.string.StringUtils;
+import com.dragonsoft.duceap.core.search.Searchable;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author mazq
+ * @date 2023/2/13
+ */
+@Slf4j
+@Service
+public class AuthSubTaskTypeBusinessImpl implements IAuthSubTaskTypeBusiness {
+
+    private final List<String> excelTitle = Arrays.asList("任务类型名称", "任务类型编码", "上级任务类型编码");
+
+    private IAuthSubTaskTypeService taskTypeService;
+
+    private IDuceapUploadFacade uploadFacade;
+
+
+    @Autowired
+    public void setTaskTypeService(IAuthSubTaskTypeService taskTypeService) {
+        this.taskTypeService = taskTypeService;
+    }
+
+    @Autowired
+    public void setUploadFacade(IDuceapUploadFacade uploadFacade) {
+        this.uploadFacade = uploadFacade;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public ResponseStatus authSubTaskTypeImp(String fileId) {
+        DocContentDTO fileContent = uploadFacade.getFileContent(fileId);
+        InputStream inputStream = new ByteArrayInputStream(fileContent.getFileData());
+        try {
+            List<ExcelImpTaskType> list = loadTaskTypeFromExcel(inputStream);
+            //对数据进行校验
+            verifyTaskTypeInfo(list);
+            //保存数据
+            saveImport(list);
+        } catch (IOException e) {
+            return ResponseStatus.fail("文件格式不对");
+        } catch (NumberFormatException e) {
+            return ResponseStatus.fail(e.getMessage());
+        }
+        return ResponseStatus.success("导入成功");
+    }
+
+    private void saveImport(List<ExcelImpTaskType> list) {
+        List<AuthSubTaskType> taskTypes = DcucBeanUtil.createCopyToObjectList(list, AuthSubTaskType.class);
+        taskTypeService.saveByCodes(taskTypes);
+    }
+
+    private void verifyTaskTypeInfo(List<ExcelImpTaskType> list) {
+        // 校验导入的code是否重复
+        Map<String, List<ExcelImpTaskType>> map = list.stream()
+                .collect(Collectors.groupingBy(ExcelImpTaskType::getTaskTypeCode));
+        for (List<ExcelImpTaskType> value : map.values()) {
+            if (value.size() > 1) {
+                ExcelImpTaskType taskType = value.get(0);
+                String taskTypeCode = taskType.getTaskTypeCode();
+                throw new NumberFormatException("导入行中任务类型编码:【" + taskTypeCode + "】存在重复数据");
+            }
+        }
+
+        // 校验数据中code是否存在
+        List<AuthSubTaskType> existCodes = taskTypeService.getByCodes(map.keySet());
+        if (CollectionUtils.isNotEmpty(existCodes)) {
+            String collect = existCodes.stream()
+                    .map(AuthSubTaskType::getTaskTypeCode)
+                    .collect(Collectors.joining(Constant.CHINESE_COMMA));
+            throw new NumberFormatException("任务类型编码:【" + collect + "】已存在数据库");
+        }
+
+    }
+
+    private List<ExcelImpTaskType> loadTaskTypeFromExcel(InputStream inputStream) throws IOException {
+        List<ExcelImpTaskType> list = new ArrayList<>();
+        Workbook wb0 = new HSSFWorkbook(inputStream);
+        Sheet sheet = wb0.getSheetAt(0);
+        for (Row r : sheet) {
+            if (r.getRowNum() == 0) {
+                ImportUtil.checkTitle(r, excelTitle);
+            } else {
+                if (ImportUtil.checkIsEmpty(r, 3)) {
+                    continue;
+                }
+                ExcelImpTaskType orgInfo = getTaskTypeInfoFromRow(r);
+                list.add(orgInfo);
+            }
+        }
+        return list;
+    }
+
+    private ExcelImpTaskType getTaskTypeInfoFromRow(Row r) {
+        ExcelImpTaskType taskType = new ExcelImpTaskType();
+        taskType.setRowNum(r.getRowNum());
+
+        Cell cell;
+        cell = r.getCell(0);
+        // 设置任务类型名称
+        String taskTypeName = ImportUtil.getCellStringValue(cell);
+        taskType.setTaskTypeName(taskTypeName);
+
+        // 设置任务类型编码
+        cell = r.getCell(1);
+        String taskTypeCode = ImportUtil.getCellStringValue(cell);
+        taskType.setTaskTypeCode(taskTypeCode);
+
+        // 设置创建时间
+        cell = r.getCell(2);
+        String parentCode = ImportUtil.getCellStringValue(cell);
+        taskType.setParentCode(parentCode);
+        return taskType;
+    }
+
+    @Override
+    public Page<AuthSubTaskTypeVo> pageSearch(SearchDTO searchDTO) {
+        Searchable searchable = Searchable.toSearchable(searchDTO);
+        Page<AuthSubTaskType> page = taskTypeService.pageSearch(searchable);
+        return DcucBeanUtil.createCopyToObjectPage(page, AuthSubTaskTypeVo.class);
+    }
+
+
+    @Override
+    public List<TaskTypeTreeVo> taskTypeTree() {
+        List<AuthSubTaskType> list = taskTypeService.findAll();
+        List<TaskTypeTreeVo> vos = getVoList(list);
+        return getTreeVos(vos);
+    }
+
+    private List<TaskTypeTreeVo> getTreeVos(List<TaskTypeTreeVo> vos) {
+        Map<Boolean, List<TaskTypeTreeVo>> partMap = vos.stream()
+                .collect(Collectors.partitioningBy(e -> StringUtils.isBlank(e.getPid())));
+        // 最顶级的父节点
+        List<TaskTypeTreeVo> topNodes = partMap.get(Boolean.TRUE);
+        // 子节点
+        List<TaskTypeTreeVo> childNodes = partMap.get(Boolean.FALSE);
+        Map<String, List<TaskTypeTreeVo>> groupMap = childNodes.stream()
+                .collect(Collectors.groupingBy(TaskTypeTreeVo::getPid));
+
+        Deque<TaskTypeTreeVo> queue = new LinkedList<>(topNodes);
+        while (!queue.isEmpty()) {
+            TaskTypeTreeVo firstNode = queue.poll();
+            String id = firstNode.getId();
+            List<TaskTypeTreeVo> childVos = groupMap.get(id);
+            if (CollectionUtils.isNotEmpty(childVos)) {
+                firstNode.setChildren(childVos);
+                firstNode.setIsParent(Boolean.TRUE);
+                queue.addAll(childVos);
+            } else {
+                firstNode.setIsParent(Boolean.FALSE);
+            }
+        }
+
+        return topNodes;
+    }
+
+    private List<TaskTypeTreeVo> getVoList(List<AuthSubTaskType> list) {
+        return list.stream()
+                .map(e -> {
+                    TaskTypeTreeVo treeVo = new TaskTypeTreeVo();
+                    treeVo.setId(e.getId());
+                    treeVo.setPid(e.getParentId());
+                    treeVo.setName(e.getTaskTypeName());
+                    treeVo.setCode(e.getTaskTypeCode());
+                    treeVo.setIsParent(false);
+                    return treeVo;
+                }).collect(Collectors.toList());
+    }
+
+
+
+}

+ 60 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthSubTaskType.java

@@ -0,0 +1,60 @@
+package com.dragoninfo.dcuc.auth.sub.entity;
+
+import com.dragoninfo.dcuc.auth.auth.entity.zerotrust.BaseUpdateEntity;
+import com.dragonsoft.duceap.core.persistent.audit.JpaAuditingEntityListener;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.*;
+
+/**
+ * 主体管理-任务类型
+ *
+ * @author mazq
+ * @date 2023/2/13
+ */
+
+@EqualsAndHashCode(callSuper = true)
+@EntityListeners({JpaAuditingEntityListener.class})
+@Entity
+@Table(name = "T_AUTH_SUB_TASK_TYPE")
+@Data
+@Where(clause = "deleted = '0'")
+public class AuthSubTaskType extends BaseUpdateEntity {
+
+    /**
+     * ID;主键id
+     */
+    @Id
+    @GeneratedValue(generator="idGenerator")
+    @GenericGenerator(name="idGenerator", strategy="uuid")
+    @Column(name = "ID")
+    private String id;
+
+    /**
+     * TASK_TYPE_NAME; 任务类型名称
+     */
+    @Column(name = "TASK_TYPE_NAME")
+    private String taskTypeName;
+
+    /**
+     * TASK_TYPE_CODE; 任务类型编码
+     */
+    @Column(name = "TASK_TYPE_CODE")
+    private String taskTypeCode;
+
+    /**
+     * 父级id
+     */
+    @Column(name = "PARENT_ID")
+    private String parentId;
+
+    /**
+     * 父级编码
+     */
+    @Column(name = "PARENT_CODE")
+    private String parentCode;
+}
+

+ 57 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/AuthSubTaskTypeFacade.java

@@ -0,0 +1,57 @@
+package com.dragoninfo.dcuc.auth.sub.facade;
+
+import com.dragoninfo.dcuc.auth.business.IApproveRemoteCallBusiness;
+import com.dragoninfo.dcuc.auth.sub.business.IAuthSubTaskTypeBusiness;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.AuthSubTaskTypeVo;
+import com.dragoninfo.dcuc.auth.sub.vo.tasktype.TaskTypeTreeVo;
+import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.base.entity.search.SearchDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @author mazq
+ * @date 2023/2/13
+ */
+@RestController
+@RequestMapping("/dcuc/auth/subTaskTypeFacade")
+public class AuthSubTaskTypeFacade implements IAuthSubTaskTypeFacade {
+
+    private IAuthSubTaskTypeBusiness taskTypeBusiness;
+
+    private IApproveRemoteCallBusiness taskTypeRemoteCallBusiness;
+
+    @Autowired
+    public void setTaskTypeRemoteCallBusiness(IApproveRemoteCallBusiness taskTypeRemoteCallBusiness) {
+        this.taskTypeRemoteCallBusiness = taskTypeRemoteCallBusiness;
+    }
+
+    @Autowired
+    public void setTaskTypeBusiness(IAuthSubTaskTypeBusiness taskTypeBusiness) {
+        this.taskTypeBusiness = taskTypeBusiness;
+    }
+
+    @Override
+    public Page<AuthSubTaskTypeVo> pageSearch(SearchDTO searchDTO) {
+        return taskTypeBusiness.pageSearch(searchDTO);
+    }
+
+    @Override
+    public ResponseStatus taskTypeImp(String fileId) {
+        return taskTypeBusiness.authSubTaskTypeImp(fileId);
+    }
+
+    @Override
+    public ResponseStatus taskTypeSync() {
+        return taskTypeRemoteCallBusiness.syncTaskClass();
+    }
+
+    @Override
+    public List<TaskTypeTreeVo> taskTypeTree() {
+        return taskTypeBusiness.taskTypeTree();
+    }
+}

+ 25 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthSubTaskTypeRepository.java

@@ -0,0 +1,25 @@
+package com.dragoninfo.dcuc.auth.sub.repo;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AuthSubTaskType;
+import com.dragonsoft.duceap.core.persistent.repository.BaseRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author mazq
+ * @date 2023/7/12
+ */
+@Repository
+public interface AuthSubTaskTypeRepository extends BaseRepository<AuthSubTaskType, String> {
+
+    /**
+     * 修改上级id
+     * @param id
+     * @param parentId
+     */
+    @Modifying
+    @Query(value = "UPDATE T_AUTH_SUB_TASK_TYPE SET PARENT_ID = :parentId WHERE ID = :id AND DELETED = '0'", nativeQuery = true)
+    void updateParentId(@Param("id") String id, @Param("parentId") String parentId);
+}

+ 2 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAddSyncRecordService.java

@@ -14,4 +14,6 @@ public interface IAddSyncRecordService {
     void update(AddSyncRecord record);
 
     void save(AddSyncRecord record);
+
+    void saveOrUpdate(AddSyncRecord addSyncRecord);
 }

+ 64 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthSubTaskTypeService.java

@@ -0,0 +1,64 @@
+package com.dragoninfo.dcuc.auth.sub.service;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AuthSubTaskType;
+import com.dragonsoft.duceap.core.search.Searchable;
+import org.springframework.data.domain.Page;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 主体管理-任务类型业务类
+ *
+ * @author mazq
+ * @date 2023/2/13
+ */
+public interface IAuthSubTaskTypeService {
+
+    /**
+     * 分页查询
+     *
+     * @param searchable 搜索条件
+     * @return 结果
+     */
+    Page<AuthSubTaskType> pageSearch(Searchable searchable);
+
+
+    /**
+     * 根据任务类型编码批量保存或更新
+     *
+     * @param list 任务类型信息
+     */
+    void saveByCodes(Collection<AuthSubTaskType> list);
+
+    /**
+     * 根据任务类型编码批量获取
+     *
+     * @param taskTypeCodes 任务类型编码集合
+     * @return 任务类型信息
+     */
+    List<AuthSubTaskType> getByCodes(Collection<String> taskTypeCodes);
+
+    /**
+     * 获取所有任务类型
+     *
+     * @return 所以任务类型
+     */
+    List<AuthSubTaskType> findAll();
+
+    /**
+     * 根据code 查询
+     * @param taskCode
+     * @return
+     */
+    AuthSubTaskType getByCode(String taskCode);
+
+    /**
+     * 数量统计
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    Long count(Date startTime, Date endTime);
+}

+ 11 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AddSyncRecordServiceImpl.java

@@ -3,6 +3,7 @@ package com.dragoninfo.dcuc.auth.sub.service.impl;
 import com.dragoninfo.dcuc.auth.sub.entity.AddSyncRecord;
 import com.dragoninfo.dcuc.auth.sub.repo.AddSyncRecordRepo;
 import com.dragoninfo.dcuc.auth.sub.service.IAddSyncRecordService;
+import com.dragonsoft.duceap.commons.util.string.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
 import org.springframework.stereotype.Service;
@@ -34,4 +35,14 @@ public class AddSyncRecordServiceImpl implements IAddSyncRecordService {
     public void save(AddSyncRecord record) {
         recordRepo.save(record);
     }
+
+    @Override
+    public void saveOrUpdate(AddSyncRecord addSyncRecord) {
+        String id = addSyncRecord.getId();
+        if (StringUtils.isNotBlank(id)) {
+            recordRepo.save(addSyncRecord);
+        } else {
+            recordRepo.update(addSyncRecord);
+        }
+    }
 }

+ 175 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthSubTaskTypeServiceImpl.java

@@ -0,0 +1,175 @@
+package com.dragoninfo.dcuc.auth.sub.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import com.dragoninfo.dcuc.auth.sub.entity.AuthSubTaskType;
+import com.dragoninfo.dcuc.auth.sub.repo.AuthSubTaskTypeRepository;
+import com.dragoninfo.dcuc.auth.sub.service.IAuthSubTaskTypeService;
+import com.dragonsoft.duceap.commons.util.string.StringUtils;
+import com.dragonsoft.duceap.core.search.Searchable;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.criteria.Predicate;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author mazq
+ * @date 2023/2/13
+ */
+@Service
+public class AuthSubTaskTypeServiceImpl implements IAuthSubTaskTypeService {
+
+    private AuthSubTaskTypeRepository taskTypeRepository;
+
+    @Autowired
+    public void setTaskTypeRepository(AuthSubTaskTypeRepository taskTypeRepository) {
+        this.taskTypeRepository = taskTypeRepository;
+    }
+
+    @Override
+    public Page<AuthSubTaskType> pageSearch(Searchable searchable) {
+        return taskTypeRepository.paging(searchable);
+    }
+
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void saveByCodes(Collection<AuthSubTaskType> list) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        // 查询已存在的
+        Set<String> taskTypeCodes = list.stream()
+                .map(AuthSubTaskType::getTaskTypeCode)
+                .collect(Collectors.toSet());
+        // 已存在的任务类型列表
+        List<AuthSubTaskType> existTaskTypeList = getByCodes(taskTypeCodes);
+
+        Map<String, AuthSubTaskType> exitCodeTaskTypeMap = existTaskTypeList.stream()
+                .collect(Collectors.toMap(AuthSubTaskType::getTaskTypeCode, e -> e, (old, last) -> last));
+
+        Map<Boolean, List<AuthSubTaskType>> booleanListMap = list.stream()
+                .collect(Collectors.partitioningBy(e -> exitCodeTaskTypeMap.containsKey(e.getTaskTypeCode())));
+        // 保存
+        List<AuthSubTaskType> saveAuthSubTaskTypes = booleanListMap.get(Boolean.FALSE);
+        List<AuthSubTaskType> addList = saveEntities(saveAuthSubTaskTypes);
+        // 更新
+        List<AuthSubTaskType> updateEntity = booleanListMap.get(Boolean.TRUE);
+        List<AuthSubTaskType> updates = updateEntities(exitCodeTaskTypeMap, updateEntity);
+
+        List<AuthSubTaskType> collect = Stream.of(addList, updates)
+                .filter(Objects::nonNull)
+                .filter(CollectionUtils::isNotEmpty)
+                .flatMap(List::stream)
+                .collect(Collectors.toList());
+
+        // 更新上级id
+        updateUpIds(collect);
+    }
+
+    /**
+     * 更新上级ID
+     *
+     * @param collect 集合
+     */
+    private void updateUpIds(List<AuthSubTaskType> collect) {
+        List<String> parentCodes = collect.stream()
+                .map(AuthSubTaskType::getParentCode)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toList());
+        List<AuthSubTaskType> parentTasks = getByCodes(parentCodes);
+        // 设置所有的parentId字段
+        Map<String, String> map = parentTasks.stream()
+                .collect(Collectors.toMap(
+                        AuthSubTaskType::getTaskTypeCode,
+                        AuthSubTaskType::getId));
+        collect.forEach(e -> {
+            e.setParentId(map.get(e.getParentCode()));
+            taskTypeRepository.updateParentId(e.getId(), e.getParentId());
+        });
+
+    }
+
+    /**
+     * 保存
+     *
+     * @param saveEntity 需要保存的
+     * @return 保存后的
+     */
+    private List<AuthSubTaskType> saveEntities(List<AuthSubTaskType> saveEntity) {
+        if (CollectionUtils.isNotEmpty(saveEntity)) {
+            taskTypeRepository.saveAll(saveEntity);
+        }
+        return saveEntity;
+    }
+
+    /**
+     * 更新
+     *
+     * @param exitCodeMap  存在的任务类型代码
+     * @param updateEntity 更新的数据
+     * @return 更新的数据
+     */
+    private List<AuthSubTaskType> updateEntities(Map<String, AuthSubTaskType> exitCodeMap, List<AuthSubTaskType> updateEntity) {
+        if (CollectionUtils.isNotEmpty(updateEntity)) {
+            for (AuthSubTaskType update : updateEntity) {
+                AuthSubTaskType existEntity = exitCodeMap.get(update.getTaskTypeCode());
+                Assert.notNull(existEntity);
+                existEntity.setTaskTypeName(update.getTaskTypeName());
+                existEntity.setTaskTypeCode(update.getTaskTypeCode());
+                existEntity.setParentCode(update.getParentCode());
+                taskTypeRepository.update(existEntity);
+            }
+
+        }
+        return updateEntity;
+    }
+
+    @Override
+    public List<AuthSubTaskType> getByCodes(Collection<String> taskTypeCodes) {
+        if (CollUtil.isEmpty(taskTypeCodes)) {
+            return Collections.emptyList();
+        }
+        Specification<AuthSubTaskType> spec = (root, query, cb) -> root.get("taskTypeCode").in(taskTypeCodes);
+        return taskTypeRepository.findAll(spec);
+    }
+
+    @Override
+    public List<AuthSubTaskType> findAll() {
+        return taskTypeRepository.findAll();
+    }
+
+    @Override
+    public AuthSubTaskType getByCode(String taskCode) {
+        AuthSubTaskType taskType = new AuthSubTaskType();
+        taskType.setTaskTypeCode(taskCode);
+        Example<AuthSubTaskType> example = Example.of(taskType);
+        return taskTypeRepository.findOne(example).orElse(null);
+    }
+
+    @Override
+    public Long count(Date startTime, Date endTime) {
+        Specification<AuthSubTaskType> spec = (root, query, cb) -> {
+            List<Predicate> list = new ArrayList<>();
+            if (null != startTime) {
+                Predicate ge = cb.greaterThanOrEqualTo(root.get("createTime"), startTime);
+                list.add(ge);
+            }
+            if (null != endTime) {
+                Predicate le = cb.lessThanOrEqualTo(root.get("createTime"), endTime);
+                list.add(le);
+            }
+            return cb.and(list.toArray(new Predicate[0]));
+        };
+
+        return taskTypeRepository.count(spec);
+    }
+}