From 0d247afef325a59669adaf4466925b7313b644ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=96=8C=E5=B3=B0?= Date: Sun, 9 Aug 2026 22:15:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(process):=20=E6=B7=BB=E5=8A=A0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E6=B5=81=E7=A8=8B=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3?= =?UTF-8?q?API=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blade-service-api/blade-process-api/pom.xml | 16 + .../process/feign/IBusinessProcessClient.java | 105 +++ .../dto/AdditionOperationParameterDTO.java | 34 + .../process/pojo/dto/ApprovalDTO.java | 119 +++ ...sinessProcessCurrentHandlerRefreshDTO.java | 41 + .../pojo/dto/BusinessProcessDeleteDTO.java | 39 + .../pojo/dto/BusinessProcessQueryDTO.java | 42 + .../pojo/dto/BusinessProcessSubmitDTO.java | 81 ++ .../pojo/dto/BusinessProcessUpdateDTO.java | 39 + .../process/pojo/dto/ProcessExecuteDTO.java | 74 ++ .../process/CommonDeptCodeProcessParam.java | 22 + .../process/pojo/entity/BusinessProcess.java | 164 ++++ .../process/pojo/enums/ApproveStatusEnum.java | 165 ++++ .../process/pojo/enums/TodoStatus.java | 36 + .../process/pojo/vo/ApprovalVO.java | 177 +++++ .../pojo/vo/BusinessProcessListVO.java | 110 +++ .../process/pojo/vo/BusinessProcessVO.java | 43 ++ .../pojo/vo/ProcessApprovedRecordVO.java | 110 +++ .../process/pojo/vo/ProcessAttachmentVO.java | 43 ++ .../process/pojo/vo/ProcessCommentVO.java | 63 ++ .../process/pojo/vo/ProcessTodoVO.java | 79 ++ blade-service-api/pom.xml | 1 + blade-service/blade-system/pom.xml | 4 + .../controller/BusinessProcessController.java | 83 ++ .../process/convert/ApprovalConvert.java | 51 ++ .../convert/BusinessProcessConvert.java | 84 ++ .../process/convert/MKApprovalConvert.java | 149 ++++ .../process/feign/BusinessProcessClient.java | 77 ++ .../process/mapper/BusinessProcessMapper.java | 14 + .../process/mapper/BusinessProcessMapper.xml | 29 + .../service/IBusinessProcessService.java | 115 +++ .../impl/BusinessProcessServiceImpl.java | 725 ++++++++++++++++++ .../springblade/system/SystemApplication.java | 2 + pom.xml | 5 + 34 files changed, 2941 insertions(+) create mode 100644 blade-service-api/blade-process-api/pom.xml create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/feign/IBusinessProcessClient.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/AdditionOperationParameterDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ApprovalDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessCurrentHandlerRefreshDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessDeleteDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessQueryDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessSubmitDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessUpdateDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ProcessExecuteDTO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/process/CommonDeptCodeProcessParam.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/entity/BusinessProcess.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/ApproveStatusEnum.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/TodoStatus.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ApprovalVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessListVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessApprovedRecordVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessAttachmentVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessCommentVO.java create mode 100644 blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessTodoVO.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/controller/BusinessProcessController.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/convert/ApprovalConvert.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/convert/BusinessProcessConvert.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/convert/MKApprovalConvert.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/feign/BusinessProcessClient.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.xml create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/service/IBusinessProcessService.java create mode 100644 blade-service/blade-system/src/main/java/org/springblade/process/service/impl/BusinessProcessServiceImpl.java diff --git a/blade-service-api/blade-process-api/pom.xml b/blade-service-api/blade-process-api/pom.xml new file mode 100644 index 0000000..b4d7371 --- /dev/null +++ b/blade-service-api/blade-process-api/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + org.springblade + blade-service-api + ${revision} + + + blade-process-api + ${project.artifactId} + jar + + diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/feign/IBusinessProcessClient.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/feign/IBusinessProcessClient.java new file mode 100644 index 0000000..9218fe8 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/feign/IBusinessProcessClient.java @@ -0,0 +1,105 @@ +package org.springblade.process.feign; + +import org.springblade.core.launch.constant.AppConstant; +import org.springblade.core.tool.api.FR; +import org.springblade.process.pojo.dto.BusinessProcessCurrentHandlerRefreshDTO; +import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO; +import org.springblade.process.pojo.dto.BusinessProcessSubmitDTO; +import org.springblade.process.pojo.dto.BusinessProcessUpdateDTO; +import org.springblade.process.pojo.vo.BusinessProcessVO; +import org.springblade.process.pojo.vo.ProcessApprovedRecordVO; +import org.springblade.process.pojo.vo.ProcessTodoVO; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +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; + +/** + * 业务流程关联表 Feign接口类 + * + * @author BladeX + * @since 2024-09-19 + */ +@FeignClient( + value = AppConstant.APPLICATION_SYSTEM_NAME +) +public interface IBusinessProcessClient { + + String API_PREFIX = "/feign/client/businessProcess"; + String SUBMIT_BUSINESS_PROCESS = API_PREFIX + "/submitBusinessProcess"; + String UPDATE_BUSINESS_PROCESS_APPROVER = API_PREFIX + "/updateBusinessProcessApprover"; + String REFRESH_BUSINESS_PROCESS_CURRENT_HANDLERS = API_PREFIX + "/refreshBusinessProcessCurrentHandlers"; + String UPDATE_BUSINESS_PROCESS_STATUS = API_PREFIX + "/updateBusinessProcessStatus"; + String DELETE_BUSINESS_PROCESS = API_PREFIX + "/deleteBusinessProcess"; + String QUERY_TODO_LIST = API_PREFIX + "/queryTodoList"; + String QUERY_BUSINESS_PROCESS_SNAPSHOT = API_PREFIX + "/queryBusinessProcessSnapshot"; + String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments"; + + /** + * 提交业务流程 + * @param param + */ + @PostMapping(SUBMIT_BUSINESS_PROCESS) + FR submitBusinessProcess(@Validated @RequestBody BusinessProcessSubmitDTO param); + + /** + * 修改业务流程状态 + * @param param + * @return + */ + @PostMapping(UPDATE_BUSINESS_PROCESS_STATUS) + FR updateBusinessProcessStatus(@Validated @RequestBody BusinessProcessUpdateDTO param); + + /** + * 修改业务流程审批人 + * @param param + * @return + */ + @PostMapping(UPDATE_BUSINESS_PROCESS_APPROVER) + FR updateBusinessProcessApprover(@Validated @RequestBody BusinessProcessUpdateDTO param); + + /** + * 只刷新当前节点和当前处理人 + * @param param + * @return + */ + @PostMapping(REFRESH_BUSINESS_PROCESS_CURRENT_HANDLERS) + FR refreshBusinessProcessCurrentHandlers(@Validated @RequestBody BusinessProcessCurrentHandlerRefreshDTO param); + + /** + * 查询流程当前待办列表 + * @param processInstanceId + * @return + */ + @GetMapping(QUERY_TODO_LIST) + FR> queryTodoList(@RequestParam("processInstanceId") String processInstanceId); + + /** + * 查询业务流程当前快照 + * @param processInstanceId + * @return + */ + @GetMapping(QUERY_BUSINESS_PROCESS_SNAPSHOT) + FR queryBusinessProcessSnapshot(@RequestParam("processInstanceId") String processInstanceId); + + /** + * 删除业务流程 + * @param param + * @return + */ + @PostMapping(DELETE_BUSINESS_PROCESS) + FR deleteBusinessProcess(@Validated @RequestBody BusinessProcessDeleteDTO param); + + /** + * 查询流程审批记录不处理附件 + * @param bizId + * @param processInstanceId + * @return + */ + @GetMapping(QUERY_APPROVED_RECORD_LIST) + FR> queryApprovedRecordsNoAttachments(@RequestParam(name = "bizId", required = false) String bizId, @RequestParam(name = "processInstanceId", required = false) String processInstanceId); +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/AdditionOperationParameterDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/AdditionOperationParameterDTO.java new file mode 100644 index 0000000..211613e --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/AdditionOperationParameterDTO.java @@ -0,0 +1,34 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 附加操作信息 + * + * @author linbb + */ +@Schema(description = "附加操作信息") +@Data +public class AdditionOperationParameterDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 操作类型 + */ + private String operationType; + + /** + * 操作身份 + */ + private String operationIdentity; + + /** + * 操作参数 + */ + private String parameter; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ApprovalDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ApprovalDTO.java new file mode 100644 index 0000000..d2a2055 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ApprovalDTO.java @@ -0,0 +1,119 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * mk审批中心查询参数 + * @author bfhuange + * @since 2025/4/2 + */ +@Data +@Schema(description = "mk审批中心查询参数") +public class ApprovalDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 单据类型 myApproving 我的待审,myApproved 我的已审,myReading 我的待阅,myReaded 我的已阅,myRelated 我参与的,myCreated 我发起的 + */ + @NotBlank(message = "单据类型不能为空") + @Schema(description = "单据类型 myApproving 我的待审,myApproved 我的已审,myReading 我的待阅,myReaded 我的已阅,myRelated 我参与的,myCreated 我发起的") + private String docType; + /** + * 关键字 + */ + @Schema(description = "关键字") + private String keyword; + /** + * 模板名称 + */ + @Schema(description = "模板名称") + private String templateName; + /** + * 申请时间开始 + */ + @Schema(description = "申请时间开始") + private Date applicantTimeStart; + /** + * 申请时间结束 + */ + @Schema(description = "申请时间结束") + private Date applicantTimeEnd; + + //==================================待办参数======================= + + /** + * 接收时间开始 + */ + @Schema(description = "接收时间开始") + private Date receiveTimeStart; + /** + * 接收时间结束 + */ + @Schema(description = "接收时间结束") + private Date receiveTimeEnd; + + //==================================已处理参数======================= + + /** + * 流程状态 00 – 废弃、10 – 草稿、11 – 驳回 20 – 待审、21 – 异常、40 – 挂起 30 – 结束 + */ + @Schema(description = "流程状态 00 – 废弃、10 – 草稿、11 – 驳回 20 – 待审、21 – 异常、40 – 挂起 30 – 结束") + private String status; + + /** + * 结束时间开始 + */ + @Schema(description = "结束时间开始") + private Date finishTimeStart; + /** + * 结束时间结束 + */ + @Schema(description = "结束时间结束") + private Date finishTimeEnd; + + /** + * 最后处理时间开始 + */ + @Schema(description = "最后处理时间开始") + private Date lastHandleStart; + /** + * 最后处理时间结束 + */ + @Schema(description = "最后处理时间结束") + private Date lastHandleEnd; + + //==================================已阅参数======================= + /** + * 阅读时间开始 + */ + @Schema(description = "阅读时间开始") + private Date readTimeStart; + /** + * 阅读时间结束 + */ + @Schema(description = "阅读时间结束") + private Date readTimeEnd; + + //==================================我参与的参数======================= + /** + * 创建时间开始 + */ + @Schema(description = "创建时间开始") + private Date createTimeStart; + /** + * 创建时间结束 + */ + @Schema(description = "创建时间结束") + private Date createTimeEnd; + /** + * 登录名 + */ + @Schema(description = "登录名", hidden = true) + private String loginName; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessCurrentHandlerRefreshDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessCurrentHandlerRefreshDTO.java new file mode 100644 index 0000000..b56c7af --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessCurrentHandlerRefreshDTO.java @@ -0,0 +1,41 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 业务流程当前处理人刷新参数 + * + * @author bfhuange + * @date 2026/4/9 + */ +@Schema(description = "业务流程当前处理人刷新参数") +@Data +public class BusinessProcessCurrentHandlerRefreshDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + @NotBlank(message = "流程实例id不能为空") + @Schema(description = "流程实例id") + private String processInstanceId; + + /** + * 发起人登录名,可为空。 + * 为空时优先从业务流程表回填;仅当业务流程不存在时,才回退使用调用方传入值。 + */ + @Schema(description = "发起人登录名,可为空;为空时优先从业务流程表回填") + private String promoterLoginName; + + /** + * 是否流程已完成 + */ + @Schema(description = "是否流程已完成") + private boolean complete; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessDeleteDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessDeleteDTO.java new file mode 100644 index 0000000..3e78657 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessDeleteDTO.java @@ -0,0 +1,39 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 业务流程删除参数 + * + * @author BladeX + * @since 2024-11-26 + */ +@NoArgsConstructor +@Schema(description = "业务流程删除参数") +@Data +public class BusinessProcessDeleteDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 业务id + */ + @NotNull(message = "业务id不能为空") + @Schema(description = "业务id") + private Long bizId; + /** + * 发起人登录名,即erp手机号或账号 + */ + // @NotBlank(message = "发起人登录名不能为空") + @Schema(description = "发起人登录名,即erp手机号或账号") + private String promoterLoginName; + + public BusinessProcessDeleteDTO(Long bizId) { + this.bizId = bizId; + } +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessQueryDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessQueryDTO.java new file mode 100644 index 0000000..ff5c35b --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessQueryDTO.java @@ -0,0 +1,42 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 业务流程查询参数 + * + * @author BladeX + * @since 2024-09-23 + */ +@Schema(description = "业务流程查询参数") +@Data +public class BusinessProcessQueryDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 流程类型 + */ + @Schema(description = "审批类型") + private String processType; + /** + * 文档编号 + */ + @Schema(description = "审批编号") + private String docCode; + /** + * 类型 todo:待审批,create:我创建的,done:我参与的 + */ + @NotBlank(message = "类型不能为空") + @Schema(defaultValue = "类型 todo:待审批,create:我创建的,done:我参与的") + private String type; + /** + * 当前登录人账号 + */ + @Schema(hidden = true) + private String loginName; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessSubmitDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessSubmitDTO.java new file mode 100644 index 0000000..d6a244d --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessSubmitDTO.java @@ -0,0 +1,81 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 业务流程提交参数 + * + * @author BladeX + * @since 2024-09-19 + */ +@Schema(description = "业务流程提交参数") +@Data +public class BusinessProcessSubmitDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务id + */ + @NotNull(message = "业务id不能为空") + @Schema(description = "业务id") + private Long bizId; + /** + * 流程类型 + */ + @NotBlank(message = "流程类型不能为空") + @Schema(description = "流程类型") + private String processType; + /** + * 文档编号 + */ + @Schema(description = "文档编号") + private String docCode; + /** + * 标题 + */ + @Schema(description = "标题") + private String subject; + /** + * 发起人id,空自动取登录人id + */ + @Schema(description = "发起人id") + private Long promoterId; + /** + * 发起人名称,空自动取登录人名称 + */ + @Schema(description = "发起人名称") + private String promoterName; + /** + * 发起人登录名 + */ + @Schema(description = "发起人登录名") + private String promoterLoginName; + /** + * 提交时间,空自动取当前时间 + */ + @Schema(description = "提交时间") + private Date submitTime; + /** + * 流程参数,如果流程没有用到参数做条件判断或动态部门,可以不传 + */ + @Schema(description = "流程参数") + private T processParam; + /** + * 流程执行参数,透传mk参数 + */ + @Schema(description = "流程执行参数") + private ProcessExecuteDTO executeParam; + /** + * 添加群组编码 + */ + @Schema(description = "添加群组编码") + private boolean addGroupCode; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessUpdateDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessUpdateDTO.java new file mode 100644 index 0000000..865174b --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/BusinessProcessUpdateDTO.java @@ -0,0 +1,39 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; + +/** + * 业务流程修改参数 + * + * @author BladeX + * @since 2024-09-19 + */ +@Schema(description = "业务流程修改参数") +@Data +public class BusinessProcessUpdateDTO extends BusinessProcessCurrentHandlerRefreshDTO { + @Serial + private static final long serialVersionUID = 1L; + /** + * 操作节点id,流程审批结束为空 + */ + @Schema(description = "操作节点id") + private String operationNodeId; + /** + * 操作节点编号,流程审批结束为空 + */ + @Schema(description = "操作节点编号") + private String operationNodeNumber; + /** + * 驳回节点id N2 是起草节点 + */ + @Schema(description = "驳回节点id") + private String rejectNodeId; + /** + * 审批状态 + */ + @Schema(description = "审批状态") + private String approveStatus; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ProcessExecuteDTO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ProcessExecuteDTO.java new file mode 100644 index 0000000..981167c --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/ProcessExecuteDTO.java @@ -0,0 +1,74 @@ +package org.springblade.process.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.system.pojo.dto.AdditionOperationParameterDTO; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * mk 流程执行参数 + * @author bfhuange + * @date 2024/9/26 + */ +@Schema(description = "mk 流程执行参数") +@Data +public class ProcessExecuteDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 表单实例id,业务id + */ + private String formInstanceId; + /** + * 登录账号 登录用户账号/手机号 + */ + private String loginName; + /** + * 流程标题 + */ + private String subject; + /** + * 任务ID + */ + private String taskId; + /** + * 任务类型 + */ + private String activityType; + /** + * 操作详细参数(json) + */ + private String parameter; + /** + * 流程实例ID + */ + private String processId; + /** + * 操作标识(相同操作类型和相同操作身份可能存在多个操作配置) + */ + private String operationId; + /** + * 操作类型 + */ + private String operationType; + /** + * 操作身份 + */ + private String operationIdentity; + /** + * 附加操作参数信息 + */ + private List additionParameters; + /** + * 表单实例Model Name + */ + private String formInstanceModel; + /** + * 业务表单字段值集合 + */ + // private Map formValues; + private Object formValues; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/process/CommonDeptCodeProcessParam.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/process/CommonDeptCodeProcessParam.java new file mode 100644 index 0000000..8044194 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/dto/process/CommonDeptCodeProcessParam.java @@ -0,0 +1,22 @@ +package org.springblade.process.pojo.dto.process; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 公共部门编码流程参数 + * @author bfhuange + * @date 2024/10/9 + */ +@Data +public class CommonDeptCodeProcessParam implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 部门编码 + */ + private String deptCode; + +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/entity/BusinessProcess.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/entity/BusinessProcess.java new file mode 100644 index 0000000..bac2329 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/entity/BusinessProcess.java @@ -0,0 +1,164 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.process.pojo.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.core.tool.utils.DateUtil; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 业务流程关联表 实体类 + * + * @author BladeX + * @since 2024-09-19 + */ +@Data +@TableName("blade_business_process") +@Schema(description = "BusinessProcess对象") +public class BusinessProcess implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @Schema(description = "主键") + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 业务id + */ + @Schema(description = "业务id") + private Long bizId; + /** + * 流程实例id + */ + @Schema(description = "流程实例id") + private String processInstanceId; + /** + * 流程类型 + */ + @Schema(description = "流程类型") + private String processType; + /** + * 文档编号 + */ + @Schema(description = "文档编号") + private String docCode; + /** + * 标题 + */ + @Schema(description = "标题") + private String subject; + /** + * 发起人id + */ + @Schema(description = "发起人id") + private Long promoterId; + /** + * 发起人名称 + */ + @Schema(description = "发起人名称") + private String promoterName; + /** + * 发起人登录名 + */ + @Schema(description = "发起人登录名") + private String promoterLoginName; + /** + * 提交时间 + */ + @Schema(description = "提交时间") + private Date submitTime; + /** + * 完成时间 + */ + @Schema(description = "完成时间") + private Date completeTime; + /** + * 当前节点id,多个用逗号拼接 + */ + @Schema(description = "当前节点id,多个用逗号拼接") + private String currentNodeIds; + /** + * 当前节点名称,多个用逗号拼接 + */ + @Schema(description = "当前节点名称,多个用逗号拼接") + private String currentNodeNames; + /** + * 当前处理人,多个用逗号拼接 + */ + @Schema(description = "当前处理人,多个用逗号拼接") + private String currentHandlers; + /** + * 接收时间 + */ + @Schema(description = "接收时间") + private Date receiveTime; + /** + * 是否已完成(0:未完成, 1:已完成) + */ + @Schema(description = "是否已完成") + private Integer isCompleted; + /** + * 审批状态 + */ + @Schema(description = "审批状态") + private String approveStatus; + /** + * 租户ID + */ + @Schema(description = "租户ID") + private String tenantId; + /** + * 创建时间 + */ + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATE) + @Schema(description = "创建时间", hidden = true) + @TableField(fill = FieldFill.INSERT) + private Date createTime; + /** + * 更新时间 + */ + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATE) + @Schema(description = "更新时间", hidden = true) + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/ApproveStatusEnum.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/ApproveStatusEnum.java new file mode 100644 index 0000000..9b9aafe --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/ApproveStatusEnum.java @@ -0,0 +1,165 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.process.pojo.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.Objects; + +/** + * 审批状态 + * + * @author LiuXinjie + * @apiNote 合同审批状态 + */ +@Getter +@AllArgsConstructor +public enum ApproveStatusEnum { + + /** + * 默认编号 + */ + DRAFT("draft", "草稿"), //可提交 + APPROVING("approval", "审批中"), + APPROVED("pass", "审批通过"), + REJECTED("reject", "审批驳回"), //通用的流程 驳回可编辑 + REVOCATION("revocation", "已撤回"), //可重新提交 + ABANDON("abandon", "废弃"), + ; + + final String value; + final String text; + + public boolean match(String value){ + return this.value.equals(value); + } + + public static String getValueByText(String text) { + if (text == null) { + return null; + } + for (ApproveStatusEnum item : values()) { + if (Objects.equals(item.getText(), text)) { + return item.getValue(); + } + } + return null; + } + + public static String getTextByValue(String value) { + if (value == null) { + return null; + } + for (ApproveStatusEnum item : values()) { + if (Objects.equals(item.getValue(), value)) { + return item.getText(); + } + } + return null; + } + + /** + * 是否可以撤回 + * + * @param value + * @return + */ + public static boolean canRevoke(String value) { + return APPROVING.getValue().equals(value); + } + + /** + * 能不能删除审批流 + * @param value + * @return + */ + public static boolean canDelAuditFlow(String value){ + return REJECTED.getValue().equals(value) || REVOCATION.getValue().equals(value); + } + + /** + * 驳回或撤回 + * @return + */ + public static boolean rejectedOrRevocation(String approveStatus) { + return canDelAuditFlow(approveStatus); + } + + /** + * 能不能删除数据 + * @param value + * @return + */ + public static boolean canDeleteData(String value){ + return ABANDON.getValue().equals(value) || DRAFT.getValue().equals(value) || canDelAuditFlow(value); + } + + public static String getNameStr(String value) { + for (ApproveStatusEnum state : values()) { + if (state.value.equals(value)) { + return state.text; + } + } + return null; + } + + + /** + * 是否可以编辑表单 + * + * @param value + * @return + */ + public static boolean canEdit(String value) { + return DRAFT.getValue().equals(value) || REJECTED.getValue().equals(value) || REVOCATION.getValue().equals(value); + } + + /** + * 获取可驳回状态 + * + * @return + */ + public static List buildPreviousApproveStatusList(String currentStatus) { + if (ApproveStatusEnum.APPROVING.getValue().equals(currentStatus)) { + // 变更成审批中,前置条件为 草稿或者审批中 + return List.of(ApproveStatusEnum.APPROVING.getValue()); + } else if (ApproveStatusEnum.APPROVED.getValue().equals(currentStatus)) { + // 变更成审批通过,前置条件为 审批中 + return List.of(ApproveStatusEnum.APPROVING.getValue()); + } else if (ApproveStatusEnum.REJECTED.getValue().equals(currentStatus)) { + // 变更成审批驳回,前置条件为 审批中 + return List.of(ApproveStatusEnum.APPROVING.getValue()); + } else if (ApproveStatusEnum.REVOCATION.getValue().equals(currentStatus)) { + // 变更成撤回,前置条件为 审批中 + return List.of(ApproveStatusEnum.APPROVING.getValue()); + } else { + // 其他情况,前置条件为 草稿 + return List.of(ApproveStatusEnum.DRAFT.getValue()); + } + } +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/TodoStatus.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/TodoStatus.java new file mode 100644 index 0000000..962399e --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/enums/TodoStatus.java @@ -0,0 +1,36 @@ +package org.springblade.process.pojo.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 待办状态枚举 + * @author bfhuange + * @date 2024/9/20 + */ +@AllArgsConstructor +@Getter +public enum TodoStatus { + /** + * 待办 + */ + TODO("todo", "待办"), + /** + * 已办 + */ + DONE("done", "已办"), + /** + * 身份重复跳过 + */ + SKIP("skip", "身份重复跳过"), + ; + + /** + * 待办状态编码 + */ + private final String code; + /** + * 待办状态名称 + */ + private final String name; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ApprovalVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ApprovalVO.java new file mode 100644 index 0000000..5c05c88 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ApprovalVO.java @@ -0,0 +1,177 @@ +package org.springblade.process.pojo.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.core.tool.utils.DateUtil; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author bfhuange + * @since 2025/4/2 + */ +@Data +@Schema(description = "mk审批中心记录") +public class ApprovalVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @Schema(description = "id") + private String id; + /** + * 流程所属应用 + */ + @Schema(description = "流程所属应用") + private String appName; + /** + * 申请人名称 + */ + @Schema(description = "申请人名称") + private String applicantName; + /** + * 申请人登录名 + */ + @Schema(description = "申请人登录名") + private String applicantLoginName; + /** + * 发起人名称 + */ + @Schema(description = "发起人名称") + private String creator; + /** + * 处理人名称 + */ + @Schema(description = "处理人名称") + private String handlerName; + /** + * 处理人登录名 + */ + @Schema(description = "处理人登录名") + private String handlerLoginName; + /** + * 当前处理人名称 + */ + @Schema(description = "当前处理人名称") + private String currentHandler; + /** + * 节点名称 + */ + @Schema(description = "节点名称") + private String nodeName; + /** + * 流程id + */ + @Schema(description = "流程id") + private String processId; + /** + * 流程发起时间 + */ + @Schema(description = "流程发起时间") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date startTime; + /** + * 创建时间 + */ + @Schema(description = "创建时间") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date createTime; + /** + * 如果是待办:待办接收时间 如果是待阅:传阅接收时间 + */ + @Schema(description = "如果是待办:待办接收时间 如果是待阅:传阅接收时间") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date receiveTime; + /** + * 任务结束时间 + */ + @Schema(description = "任务结束时间") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date finishTime; + /** + * 阅读时间(待阅任务) + */ + @Schema(description = "阅读时间(待阅任务)") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date readTime; + /** + * 最后处理时间(待审任务) + */ + @Schema(description = "最后处理时间(待审任务)") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date lastHandleTime; + /** + * 流程结束时间 + */ + @Schema(description = "流程结束时间") + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME, timezone = "GMT+8") + private Date processFinishTime; + /** + * 流程状态 00 – 废弃、10 – 草稿、11 – 驳回 20 – 待审、21 – 异常、40 – 挂起 30 – 结束 + */ + @Schema(description = "流程状态 00 – 废弃、10 – 草稿、11 – 驳回 20 – 待审、21 – 异常、40 – 挂起 30 – 结束") + private String status; + /** + * 流程状态名称 + */ + @Schema(description = "流程状态名称") + private String statusStr; + /** + * 流程主题 + */ + @Schema(description = "流程主题") + private String subject; + /** + * 模板编码 + */ + @Schema(description = "模板编码") + private String templateCode; + /** + * 任务id + */ + @Schema(description = "任务id") + private String taskId; + /** + * 任务状态 20 - 激活、30 - 结束、40 - 挂起、50 - 自动跳过 + */ + @Schema(description = "任务状态 20 - 激活、30 - 结束、40 - 挂起、50 - 自动跳过") + private String taskStatus; + /** + * 任务标题 + */ + @Schema(description = "任务标题") + private String taskSubject; + /** + * 催办标记 + */ + @Schema(description = "催办标记") + private String urgeTab; + /** + * 任务类型 1待办,2待阅 + */ + @Schema(description = "任务类型 1待办,2待阅") + private Integer taskType; + /** + * 待办优先级 + */ + @Schema(description = "待办优先级") + private Integer level; + /** + * 模板名称中文 + */ + @Schema(description = "模板名称中文") + private String templateNameCn; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessListVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessListVO.java new file mode 100644 index 0000000..0d1d1b6 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessListVO.java @@ -0,0 +1,110 @@ +package org.springblade.process.pojo.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author bfhuange + * @date 2024/9/23 + */ +@Data +@Schema(description = "BusinessProcessListVO") +public class BusinessProcessListVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @Schema(description = "主键") + private Long id; + + /** + * 业务id + */ + @JsonSerialize(using = ToStringSerializer.class) + @Schema(description = "业务id") + private Long bizId; + /** + * 流程实例id + */ + @Schema(description = "流程实例id") + private String processInstanceId; + /** + * 流程类型 + */ + @Schema(description = "审批类型") + private String processType; + /** + * 流程类型名称 + */ + @Schema(description = "审批类型名称") + private String processTypeStr; + /** + * 文档编号 + */ + @Schema(description = "审批单号") + private String docCode; + /** + * 发起人id + */ + @Schema(description = "发起人id") + private Long promoterId; + /** + * 发起人名称 + */ + @Schema(description = "发起人名称") + private String promoterName; + /** + * 提交时间 + */ + @Schema(description = "提交时间") + private Date submitTime; + /** + * 接收时间 + */ + @Schema(description = "接收时间") + private Date receiveTime; + /** + * 完成时间 + */ + @Schema(description = "完成时间") + private Date completeTime; + /** + * 当前节点id,多个用逗号拼接 + */ + @Schema(description = "当前节点id,多个用逗号拼接") + private String currentNodeIds; + /** + * 当前节点名称,多个用逗号拼接 + */ + @Schema(description = "当前节点名称,多个用逗号拼接") + private String currentNodeNames; + /** + * 当前处理人,多个用逗号拼接 + */ + @Schema(description = "当前处理人,多个用逗号拼接") + private String currentHandlers; + /** + * 是否已完成(0:未完成, 1:已完成) + */ + @Schema(description = "是否已完成(0:未完成, 1:已完成)") + private Integer isCompleted; + /** + * 审批状态 + */ + @Schema(description = "审批状态") + private String approveStatus; + /** + * 审批状态名称 + */ + @Schema(description = "审批状态名称") + private String approveStatusStr; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessVO.java new file mode 100644 index 0000000..67b22eb --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/BusinessProcessVO.java @@ -0,0 +1,43 @@ +package org.springblade.process.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author bfhuange + * @date 2024/9/20 + */ +@Data +@Schema(description = "BusinessProcessVO") +public class BusinessProcessVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 流程实例id + */ + private String processInstanceId; + /** + * 当前节点id,多个用逗号拼接 + */ + @Schema(description = "当前节点id,多个用逗号拼接") + private String currentNodeIds; + /** + * 当前节点名称,多个用逗号拼接 + */ + @Schema(description = "当前节点名称,多个用逗号拼接") + private String currentNodeNames; + /** + * 当前处理人,多个用逗号拼接 + */ + @Schema(description = "当前处理人,多个用逗号拼接") + private String currentHandlers; + /** + * 接收时间 + */ + @Schema(description = "接收时间") + private Date receiveTime; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessApprovedRecordVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessApprovedRecordVO.java new file mode 100644 index 0000000..e6a96d6 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessApprovedRecordVO.java @@ -0,0 +1,110 @@ +package org.springblade.process.pojo.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.core.tool.utils.DateUtil; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author bfhuange + * @since 2025/2/24 + */ +@Data +@Schema(description = "流程审批记录") +public class ProcessApprovedRecordVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 记录主键 + */ + @Schema(description = "id") + private String id; + /** + * 处理人 + */ + @Schema(description = "处理人") + private String handler; + /** + * 操作 + */ + @Schema(description = "操作") + private String action; + /** + * 操作编码 + */ + @Schema(description = "操作编码") + private String actionCode; + /** + * 操作描述(系统操作) + */ + @Schema(description = "操作描述(系统操作)") + private String actionDesc; + /** + * 操作名称 + */ + @Schema(description = "操作名称") + private String actionName; + /** + * 处理意见 + */ + @Schema(description = "处理意见") + private String message; + /** + * 创建时间 + */ + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME) + @Schema(description = "创建时间") + private Date createTime; + /** + * 流程实例id + */ + @Schema(description = "流程实例id") + private String processInstanceId; + /** + * 节点实例id + */ + @Schema(description = "节点实例id") + private String nodeInstanceId; + /** + * 节点类型 + */ + @Schema(description = "节点类型") + private String nodeType; + /** + * 节点id + */ + @Schema(description = "节点id") + private String nodeId; + /** + * 节点名称 + */ + @Schema(description = "节点名称") + private String nodeName; + /** + * 节点编号 + */ + @Schema(description = "节点编号") + private String nodeNumber; + /** + * 抄送人列表 + */ + @Schema(description = "抄送人列表") + private List senders; + /** + * 附件参数 + */ + @Schema(description = "附件参数") + private List attachmentParameter; + /** + * 流程附言 + */ + @Schema(description = "流程附言") + private List processComments; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessAttachmentVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessAttachmentVO.java new file mode 100644 index 0000000..4e0548e --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessAttachmentVO.java @@ -0,0 +1,43 @@ +package org.springblade.process.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author bfhuange + * @since 2025/2/24 + */ +@Data +@Schema(description = "流程附件") +public class ProcessAttachmentVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * id + */ + @Schema(description = "id") + private String id; + /** + * 附件名称 + */ + @Schema(description = "附件名称") + private String name; + /** + * 附件类型 electronicSign 电子签名,attachment 附件 + */ + @Schema(description = "附件类型 electronicSign 电子签名,attachment 附件") + private String type; + /** + * 附件ID + */ + @Schema(description = "附件ID") + private String fileId; + /** + * base64 + */ + @Schema(description = "base64") + private String base64; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessCommentVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessCommentVO.java new file mode 100644 index 0000000..b95f96d --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessCommentVO.java @@ -0,0 +1,63 @@ +package org.springblade.process.pojo.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springblade.core.tool.utils.DateUtil; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 流程附言 + * @author bfhuange + * @since 2025/2/24 + */ +@Data +@Schema(description = "流程附言") +public class ProcessCommentVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * id + */ + @Schema(description = "id") + private String id; + /** + * 附言内容 + */ + @Schema(description = "附言内容") + private String content; + /** + * 创建时间 + */ + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME) + @Schema(description = "创建时间") + private Date createTime; + /** + * 更新时间 + */ + @DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME) + @JsonFormat(pattern = DateUtil.PATTERN_DATETIME) + @Schema(description = "更新时间") + private Date updateTime; + /** + * 用户id + */ + @Schema(description = "用户id") + private String userId; + /** + * 用户名称 + */ + @Schema(description = "用户名称") + private String userName; + /** + * 附言附件 + */ + @Schema(description = "附言附件") + private List attachments; +} diff --git a/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessTodoVO.java b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessTodoVO.java new file mode 100644 index 0000000..8b4b615 --- /dev/null +++ b/blade-service-api/blade-process-api/src/main/java/org/springblade/process/pojo/vo/ProcessTodoVO.java @@ -0,0 +1,79 @@ +package org.springblade.process.pojo.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * @author bfhuange + * @since 2025/3/10 + */ +@Data +@Schema(description = "流程待办") +public class ProcessTodoVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @Schema(description = "主键") + private Long id; + + /** + * 流程实例id + */ + @Schema(description = "流程实例id") + private String processInstanceId; + /** + * 节点id + */ + @Schema(description = "节点id") + private String nodeId; + /** + * 节点编号 + */ + @Schema(description = "节点编号") + private String nodeNumber; + /** + * 节点名称 + */ + @Schema(description = "节点名称") + private String nodeName; + /** + * mk登录名 + */ + @Schema(description = "mk登录名") + private String loginName; + /** + * 用户姓名 + */ + @Schema(description = "用户姓名") + private String userName; + /** + * 状态(todo:待办,done:已办,skip:身份重复跳过) + */ + @Schema(description = "状态(todo:待办,done:已办,skip:身份重复跳过)") + private String status; + /** + * 接收时间 + */ + @Schema(description = "接收时间") + private Date receiveTime; + /** + * 操作时间 + */ + @Schema(description = "操作时间") + private Date operationTime; + /** + * 操作名称 + */ + @Schema(description = "操作名称") + private String operationName; +} diff --git a/blade-service-api/pom.xml b/blade-service-api/pom.xml index 0cca155..538df59 100644 --- a/blade-service-api/pom.xml +++ b/blade-service-api/pom.xml @@ -25,6 +25,7 @@ blade-record-api blade-file-api blade-open-api + blade-process-api diff --git a/blade-service/blade-system/pom.xml b/blade-service/blade-system/pom.xml index 4ab8af9..d3bde19 100644 --- a/blade-service/blade-system/pom.xml +++ b/blade-service/blade-system/pom.xml @@ -45,6 +45,10 @@ org.springblade blade-user-api + + org.springblade + blade-process-api + org.springblade diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/controller/BusinessProcessController.java b/blade-service/blade-system/src/main/java/org/springblade/process/controller/BusinessProcessController.java new file mode 100644 index 0000000..c976569 --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/controller/BusinessProcessController.java @@ -0,0 +1,83 @@ +package org.springblade.process.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import org.springblade.core.boot.ctrl.BladeController; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tool.api.R; +import org.springblade.process.pojo.dto.ApprovalDTO; +import org.springblade.process.pojo.vo.ApprovalVO; +import org.springblade.process.pojo.vo.ProcessApprovedRecordVO; +import org.springblade.process.service.IBusinessProcessService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 业务流程关联表 控制器 + * + * @author BladeX + * @since 2024-09-19 + */ +@Valid +@RestController +@AllArgsConstructor +@RequestMapping("businessProcess") +@Tag(name = "业务流程关联表", description = "业务流程关联表接口") +public class BusinessProcessController extends BladeController { + + private final IBusinessProcessService businessProcessService; + + /** + * 业务流程关联表 分页 + */ + @PostMapping("/mkList") + @ApiOperationSupport(order = 1) + @Operation(summary = "分页", description = "传入businessProcess") + public R> mkList(@Validated @RequestBody(required = false) ApprovalDTO param, Query query) { + if (param == null) { + param = new ApprovalDTO(); + } + param.setLoginName(AuthUtil.getUserAccount()); + IPage pages = businessProcessService.queryMkApprovalList(Condition.getPage(query), param); + return R.data(pages); + } + + @GetMapping("/isEditView") + @ApiOperationSupport(order = 2) + @Operation(summary = "是否编辑页", description = "传入业务id") + public R isEditView(@Valid @NotBlank(message = "业务id不能为空") String bizId) { + return R.data(businessProcessService.isEditView(bizId)); + } + + @GetMapping("/getMKApprovalUrl") + @ApiOperationSupport(order = 3) + @Operation(summary = "获取mk审批页链接", description = "传入业务id或流程实例id") + public R getMKApprovalUrl(String bizId, String processInstanceId) { + return R.data(businessProcessService.getMKApprovalUrl(bizId, processInstanceId)); + } + + @GetMapping("/getApprovedRecords") + @ApiOperationSupport(order = 4) + @Operation(summary = "查询审批记录", description = "传入业务id或流程实例id") + public R> getApprovedRecords(String bizId, String processInstanceId) { + return R.data(businessProcessService.queryApprovedRecords(bizId, processInstanceId)); + } + + @GetMapping("/downloadFile") + @ApiOperationSupport(order = 5) + @Operation(summary = "下载附件", description = "传入附件id") + public void downloadFile(HttpServletResponse response, @Valid @NotBlank(message = "附件id不能为空") String fileId) { + businessProcessService.downloadFile(response, fileId); + } + +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/convert/ApprovalConvert.java b/blade-service/blade-system/src/main/java/org/springblade/process/convert/ApprovalConvert.java new file mode 100644 index 0000000..dcc4b18 --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/convert/ApprovalConvert.java @@ -0,0 +1,51 @@ +package org.springblade.process.convert; + +import org.mapstruct.*; +import org.springblade.common.constant.DictTypeEnum; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.process.pojo.dto.ApprovalDTO; +import org.springblade.process.pojo.vo.ApprovalVO; +import org.springblade.system.cache.DictCache; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO; +import org.springblade.thirdparty.mk.pojo.vo.MKApprovalVO; +import org.springblade.thirdparty.mk.pojo.vo.MKProcessVO; + +import java.util.Date; +import java.util.List; + +/** + * @author bfhuange + * @since 2025/4/3 + */ +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ApprovalConvert { + + @Mapping(source = "dynamicProps.templateNameCn", target = "templateNameCn") + @Mapping(source = "status", target = "statusStr", qualifiedByName = "statusStr") + ApprovalVO mk2vo(MKApprovalVO vo); + + List mk2vos(List vos); + + @Mapping(source = "creator", target = "applicantName") + @Mapping(source = "currentNode", target = "nodeName") + @Mapping(source = "templateName", target = "templateNameCn") + @Mapping(source = "createTime", target = "startTime") + ApprovalVO mk2vo(MKProcessVO vo); + + List mkProcess2vos(List vos); + + @Mapping(source = "docType", target = "mydoc") + @Mapping(source = "applicantTimeStart", target = "createBeginTime", qualifiedByName = "date2long") + @Mapping(source = "applicantTimeEnd", target = "createEndTime", qualifiedByName = "date2long") + MKProcessDTO dto2mk(ApprovalDTO dto); + + @Named("statusStr") + default String statusStr(String status) { + return StringUtil.isBlank(status) ? "" : DictCache.getValue(DictTypeEnum.MK_STATUS.getType(), status); + } + + @Named("date2long") + default Long date2long(Date date) { + return date == null ? null : date.getTime(); + } +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/convert/BusinessProcessConvert.java b/blade-service/blade-system/src/main/java/org/springblade/process/convert/BusinessProcessConvert.java new file mode 100644 index 0000000..d8bd781 --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/convert/BusinessProcessConvert.java @@ -0,0 +1,84 @@ +package org.springblade.process.convert; + +import org.mapstruct.*; +import org.springblade.common.constant.DictTypeEnum; +import org.springblade.core.tool.utils.CollectionUtil; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.process.pojo.dto.AdditionOperationParameterDTO; +import org.springblade.process.pojo.dto.BusinessProcessSubmitDTO; +import org.springblade.process.pojo.dto.ProcessExecuteDTO; +import org.springblade.process.pojo.entity.BusinessProcess; +import org.springblade.process.pojo.vo.BusinessProcessListVO; +import org.springblade.process.pojo.vo.ProcessApprovedRecordVO; +import org.springblade.process.pojo.vo.ProcessAttachmentVO; +import org.springblade.process.pojo.vo.ProcessCommentVO; +import org.springblade.system.cache.DictCache; +import org.springblade.thirdparty.mk.constant.MKConstant; +import org.springblade.thirdparty.mk.pojo.dto.MKAdditionOperationParameterDTO; +import org.springblade.thirdparty.mk.pojo.dto.MKProcessExecuteDTO; +import org.springblade.thirdparty.mk.pojo.vo.MKAttachmentVO; +import org.springblade.thirdparty.mk.pojo.vo.MKAuditNoteVO; +import org.springblade.thirdparty.mk.pojo.vo.MKProcessCommentVO; +import org.springblade.thirdparty.mk.pojo.vo.MKUserOrgVO; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +/** + * @author bfhuange + * @date 2024/9/19 + */ +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface BusinessProcessConvert { + + BusinessProcess dto2entity(BusinessProcessSubmitDTO dto); + + MKProcessExecuteDTO dto2mk(ProcessExecuteDTO dto); + + MKAdditionOperationParameterDTO dto2mk(AdditionOperationParameterDTO dto); + + ProcessApprovedRecordVO mk2vo(MKAuditNoteVO vo); + + ProcessAttachmentVO mk2vo(MKAttachmentVO vo); + + List attachments2vos(List vos); + + @Mapping(source = "userOrgInfo", target = "userName", qualifiedByName = "userName") + ProcessCommentVO mk2vo(MKProcessCommentVO vo); + + List comments2vos(List vos); + + default List auditNotes2vos(List vos, Function> senderFunction) { + if (CollectionUtil.isEmpty(vos)) { + return Collections.emptyList(); + } + return vos.stream() + .map(auditNote -> { + ProcessApprovedRecordVO record = this.mk2vo(auditNote); + if (record != null && MKConstant.NODE_TYPE_SEND.equals(record.getNodeType())) { + // 抄送节点,查询抄送人员 + record.setSenders(senderFunction.apply(record)); + } + return record; + }).toList(); + } + + default void handleDict(BusinessProcessListVO vo) { + if (vo == null) { + return; + } + String processTypeStr = StringUtil.isBlank(vo.getProcessType()) ? "" : DictCache.getValue(DictTypeEnum.PROCESS_TYPE.getType(), vo.getProcessType()); + vo.setProcessTypeStr(processTypeStr); + String approveStatusStr = StringUtil.isBlank(vo.getApproveStatus()) ? "" : DictCache.getValue(DictTypeEnum.APPROVE_STATUS.getType(), vo.getApproveStatus()); + vo.setApproveStatusStr(approveStatusStr); + } + + @Named("userName") + default String userName(MKUserOrgVO userOrgInfo) { + return Optional.ofNullable(userOrgInfo) + .map(MKUserOrgVO::getName) + .orElse(null); + } +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/convert/MKApprovalConvert.java b/blade-service/blade-system/src/main/java/org/springblade/process/convert/MKApprovalConvert.java new file mode 100644 index 0000000..8d680a3 --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/convert/MKApprovalConvert.java @@ -0,0 +1,149 @@ +package org.springblade.process.convert; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springblade.process.pojo.dto.ApprovalDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalConditionDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKConditionDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKConditionDTO.MKConditionDTOBuilder; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * @author bfhuange + * @since 2025/4/3 + */ +@Getter +public enum MKApprovalConvert { + /** + * 单据类型 + */ + DOC_TYPE(MKApprovalConditionDTO::setMydoc, compose(MKConditionDTOBuilder::eq, ApprovalDTO::getDocType)), + /** + * 关键字 + */ + KEYWORD((condition, keyword) -> { + if (condition.getKeyword() == null) { + condition.setKeyword(new ArrayList<>()); + } + condition.getKeyword().add(keyword); + }, compose(MKConditionDTOBuilder::eq, ApprovalDTO::getKeyword)), + /** + * 模板名称 + */ + TEMPLATE_NAME(MKApprovalConditionDTO::setTemplateName, compose(MKConditionDTOBuilder::contains, ApprovalDTO::getTemplateName)), + /** + * 发起时间 + */ + START_TIME(MKApprovalConditionDTO::setStartTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getApplicantTimeStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getApplicantTimeEnd)) + ), + /** + * 接收时间 + */ + RECEIVE_TIME(MKApprovalConditionDTO::setReceiveTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getReceiveTimeStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getReceiveTimeEnd)) + ), + /** + * 流程状态 + */ + STATUS(MKApprovalConditionDTO::setStatus, compose(MKConditionDTOBuilder::eq, ApprovalDTO::getStatus)), + /** + * 结束时间 + */ + FINISH_TIME(MKApprovalConditionDTO::setFinishTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getFinishTimeStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getFinishTimeEnd)) + ), + /** + * 最后处理时间 + */ + LAST_HANDLE_TIME(MKApprovalConditionDTO::setLastHandleTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getLastHandleStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getLastHandleEnd)) + ), + /** + * 阅读时间 + */ + READ_TIME(MKApprovalConditionDTO::setReadTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getReadTimeStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getReadTimeEnd)) + ), + /** + * 创建时间 + */ + CREATE_TIME(MKApprovalConditionDTO::setCreateTime, + compose(MKConditionDTOBuilder::gte, getGetter(ApprovalDTO::getCreateTimeStart)), + compose(MKConditionDTOBuilder::lte, getGetter(ApprovalDTO::getCreateTimeEnd)) + ), + ; + /** + * 最终设置条件方法 + */ + private final BiConsumer setter; + /** + * 组合参数 + */ + private final List composes; + + MKApprovalConvert(BiConsumer setter, Compose... compose) { + this.setter = setter; + this.composes = List.of(compose); + } + + /** + * 获取时间戳 + * @param date + * @return + */ + private static String getTimestamp(Date date) { + return Optional.ofNullable(date) + .map(e -> String.valueOf(e.getTime())) + .orElse(null); + } + + /** + * date 转 string + * @param dateGetter + * @return + */ + private static Function getGetter(Function dateGetter) { + return approvalDTO -> getTimestamp(dateGetter.apply(approvalDTO)); + } + + /** + * 工厂方法 + * @param builderSetter + * @param getter + * @return + */ + private static Compose compose(BiConsumer builderSetter, Function getter) { + return new Compose(builderSetter, getter); + } + + /** + * 组合参数,条件和取值 + */ + @AllArgsConstructor + @NoArgsConstructor + @Data + public static class Compose { + /** + * 条件builder的setter + */ + private BiConsumer builderSetter; + /** + * 从参数取值 + */ + private Function getter; + } +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/feign/BusinessProcessClient.java b/blade-service/blade-system/src/main/java/org/springblade/process/feign/BusinessProcessClient.java new file mode 100644 index 0000000..e8ca2df --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/feign/BusinessProcessClient.java @@ -0,0 +1,77 @@ +package org.springblade.process.feign; + +import io.swagger.v3.oas.annotations.Hidden; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import org.springblade.core.tool.api.FR; +import org.springblade.process.pojo.dto.BusinessProcessCurrentHandlerRefreshDTO; +import org.springblade.process.pojo.dto.BusinessProcessDeleteDTO; +import org.springblade.process.pojo.dto.BusinessProcessSubmitDTO; +import org.springblade.process.pojo.dto.BusinessProcessUpdateDTO; +import org.springblade.process.pojo.vo.BusinessProcessVO; +import org.springblade.process.pojo.vo.ProcessApprovedRecordVO; +import org.springblade.process.pojo.vo.ProcessTodoVO; +import org.springblade.process.service.IBusinessProcessService; +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.RestController; + +import java.util.List; + +/** + * 业务流程关联表 Feign实现类 + * + * @author BladeX + * @since 2024-09-19 + */ +@Valid +@Hidden +@RestController +@AllArgsConstructor +public class BusinessProcessClient implements IBusinessProcessClient { + + private final IBusinessProcessService businessProcessService; + + @PostMapping(SUBMIT_BUSINESS_PROCESS) + @Override + public FR submitBusinessProcess(@Validated @RequestBody BusinessProcessSubmitDTO param) { + return FR.data(businessProcessService.submitBusinessProcess(param)); + } + + @Override + public FR updateBusinessProcessStatus(@Validated @RequestBody BusinessProcessUpdateDTO param) { + return FR.data(businessProcessService.updateBusinessProcessStatus(param)); + } + + @Override + public FR updateBusinessProcessApprover(@Validated @RequestBody BusinessProcessUpdateDTO param) { + return FR.data(businessProcessService.updateBusinessProcessApprover(param)); + } + + @Override + public FR refreshBusinessProcessCurrentHandlers(@Validated @RequestBody BusinessProcessCurrentHandlerRefreshDTO param) { + return FR.data(businessProcessService.refreshBusinessProcessCurrentHandlers(param)); + } + + @Override + public FR> queryTodoList(String processInstanceId) { + return FR.data(businessProcessService.queryTodoList(processInstanceId)); + } + + @Override + public FR queryBusinessProcessSnapshot(String processInstanceId) { + return FR.data(businessProcessService.queryBusinessProcessSnapshot(processInstanceId)); + } + + @PostMapping(DELETE_BUSINESS_PROCESS) + @Override + public FR deleteBusinessProcess(@Validated @RequestBody BusinessProcessDeleteDTO param) { + return FR.data(businessProcessService.deleteBusinessProcess(param)); + } + + @Override + public FR> queryApprovedRecordsNoAttachments(String bizId, String processInstanceId) { + return FR.data(businessProcessService.queryApprovedRecordsNoAttachments(bizId, processInstanceId)); + } +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.java b/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.java new file mode 100644 index 0000000..3ef7fdf --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.java @@ -0,0 +1,14 @@ +package org.springblade.process.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springblade.process.pojo.entity.BusinessProcess; + +/** + * 业务流程关联表 Mapper 接口 + * + * @author BladeX + * @since 2024-09-19 + */ +public interface BusinessProcessMapper extends BaseMapper { + +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.xml b/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.xml new file mode 100644 index 0000000..47b45b7 --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/mapper/BusinessProcessMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/service/IBusinessProcessService.java b/blade-service/blade-system/src/main/java/org/springblade/process/service/IBusinessProcessService.java new file mode 100644 index 0000000..9dd744d --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/service/IBusinessProcessService.java @@ -0,0 +1,115 @@ +package org.springblade.process.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.springblade.process.pojo.dto.*; +import org.springblade.process.pojo.entity.BusinessProcess; +import org.springblade.process.pojo.vo.*; + +import java.util.List; + +/** + * 业务流程关联表 服务类 + * + * @author BladeX + * @since 2024-09-19 + */ +public interface IBusinessProcessService extends IService { + + /** + * 提交业务流程 + * + * @param param + * @return + */ + BusinessProcessVO submitBusinessProcess(BusinessProcessSubmitDTO param); + + /** + * 修改业务流程状态 + * @param param + * @return + */ + boolean updateBusinessProcessStatus(BusinessProcessUpdateDTO param); + + /** + * 修改业务流程审批人 + * @param param + * @return + */ + BusinessProcessVO updateBusinessProcessApprover(BusinessProcessUpdateDTO param); + + /** + * 只刷新当前节点和当前处理人 + * @param param + * @return + */ + BusinessProcessVO refreshBusinessProcessCurrentHandlers(BusinessProcessCurrentHandlerRefreshDTO param); + + /** + * 查询业务流程当前快照 + * @param processInstanceId + * @return + */ + BusinessProcessVO queryBusinessProcessSnapshot(String processInstanceId); + + /** + * 是否编辑页 + * @param bizId + * @return + */ + boolean isEditView(String bizId); + + /** + * 获取mk审批页面链接,业务id和流程实例id任意一个即可 + * @param bizId 业务id + * @param processInstanceId 流程实例id + * @return + */ + String getMKApprovalUrl(String bizId, String processInstanceId); + + /** + * 删除业务流程 + * @param param + * @return + */ + boolean deleteBusinessProcess(BusinessProcessDeleteDTO param); + + /** + * 查询流程审批记录 + * @param bizId + * @param processInstanceId + * @return + */ + List queryApprovedRecords(String bizId, String processInstanceId); + + /** + * 查询流程审批记录不处理附件 + * @param bizId + * @param processInstanceId + * @return + */ + List queryApprovedRecordsNoAttachments(String bizId, String processInstanceId); + + /** + * 下载文件 + * @param response + * @param fileId + */ + void downloadFile(HttpServletResponse response, String fileId); + + /** + * 查询业务流程当前处理人 + * @param processInstanceId + * @return + */ + List queryTodoList(String processInstanceId); + + /** + * 查询mk审批记录 + * @param page + * @param param + * @return + */ + IPage queryMkApprovalList(IPage page, ApprovalDTO param); +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/process/service/impl/BusinessProcessServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/process/service/impl/BusinessProcessServiceImpl.java new file mode 100644 index 0000000..105651e --- /dev/null +++ b/blade-service/blade-system/src/main/java/org/springblade/process/service/impl/BusinessProcessServiceImpl.java @@ -0,0 +1,725 @@ +package org.springblade.process.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springblade.process.pojo.dto.*; +import org.springblade.process.pojo.enums.ApproveStatusEnum; +import org.springblade.core.log.exception.ServiceException; +import org.springblade.core.log.utils.AssertUtils; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.process.convert.ApprovalConvert; +import org.springblade.process.convert.BusinessProcessConvert; +import org.springblade.process.convert.MKApprovalConvert; +import org.springblade.process.mapper.BusinessProcessMapper; +import org.springblade.process.pojo.entity.BusinessProcess; +import org.springblade.process.pojo.enums.TodoStatus; +import org.springblade.process.pojo.vo.*; +import org.springblade.process.service.IBusinessProcessService; +import org.springblade.thirdparty.mk.config.MKProperties; +import org.springblade.thirdparty.mk.constant.MKConstant; +import org.springblade.thirdparty.mk.constant.MKDoc; +import org.springblade.thirdparty.mk.exception.MKException; +import org.springblade.thirdparty.mk.pojo.dto.MKAuditNoteDTO; +import org.springblade.thirdparty.mk.pojo.dto.MKProcessCreateDTO; +import org.springblade.thirdparty.mk.pojo.dto.MKProcessExecuteDTO; +import org.springblade.thirdparty.mk.pojo.dto.MKSenderDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalConditionDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKApprovalDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKConditionDTO; +import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO; +import org.springblade.thirdparty.mk.pojo.dto.sort.*; +import org.springblade.thirdparty.mk.pojo.vo.*; +import org.springblade.thirdparty.mk.service.IMKService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +/** + * 业务流程关联表 服务实现类 + * + * @author BladeX + * @since 2024-09-19 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class BusinessProcessServiceImpl extends ServiceImpl implements IBusinessProcessService { + + private final BusinessProcessConvert convert; + private final IMKService mkService; + private final MKProperties mkProperties; + private final ApprovalConvert approvalConvert; + + @Transactional(rollbackFor = Exception.class) + @Override + public BusinessProcessVO submitBusinessProcess(BusinessProcessSubmitDTO param) { + if (param == null) { + log.warn("提交业务流程参数为空"); + return null; + } + Long bizId = param.getBizId(); + if (bizId == null) { + log.warn("提交业务流程业务id为空"); + return null; + } + log.info("提交业务流程参数:{}", JSON.toJSONString(param)); + BusinessProcess businessProcess = this.getOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getBizId, bizId) + ); + if (businessProcess == null) { + businessProcess = convert.dto2entity(param); + } + // 设置发起人 + if (businessProcess.getPromoterId() == null) { + businessProcess.setPromoterId(AuthUtil.getUserId()); + } + if (businessProcess.getPromoterName() == null) { + businessProcess.setPromoterName(AuthUtil.getNickName()); + } + if (businessProcess.getPromoterLoginName() == null) { + businessProcess.setPromoterLoginName(AuthUtil.getUserName()); + param.setPromoterLoginName(AuthUtil.getUserName()); + } + // 设置提交时间 + if (businessProcess.getSubmitTime() == null) { + businessProcess.setSubmitTime(new Date()); + } + // 1.提交流程 + long start = System.currentTimeMillis(); + log.info("提交流程开始"); + String processInstanceId = submitMKProcess(param); + long end = System.currentTimeMillis(); + log.info("提交流程结束 耗时:{}", end - start); + businessProcess.setProcessInstanceId(processInstanceId); + // 提交是审批中状态 + businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue()); + // 2.保存业务流程 + this.saveOrUpdate(businessProcess); + + // 3.查询当前节点 + BusinessProcessVO businessProcessVO = new BusinessProcessVO(); + businessProcessVO.setProcessInstanceId(processInstanceId); + return businessProcessVO; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public boolean updateBusinessProcessStatus(BusinessProcessUpdateDTO param) { + AssertUtils.notNull(param, "参数不能为空"); + BusinessProcess businessProcess = this.getOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getProcessInstanceId, param.getProcessInstanceId()) + ); + AssertUtils.notNull(businessProcess, "流程实例不存在"); + // if (StringUtils.isNotBlank(approveStatus) && !rejectAfterPass(approveStatus, operationNodeNumber)) { + if (StringUtils.isNotBlank(param.getApproveStatus()) && updateApproveStatus(param.getApproveStatus(), param.getRejectNodeId())) { + // 审批状态不为空且需要修改审批状态 + BusinessProcess updateParam = new BusinessProcess(); + updateParam.setId(businessProcess.getId()); + updateParam.setApproveStatus(param.getApproveStatus()); + return this.updateById(updateParam); + } + return true; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public BusinessProcessVO updateBusinessProcessApprover(BusinessProcessUpdateDTO param) { + BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(param.getProcessInstanceId()); + String promoterLoginName = resolvePromoterLoginName(businessProcess, param.getPromoterLoginName()); + if (StringUtils.isBlank(promoterLoginName)) { + log.warn("修改业务流程审批人失败,发起人登录名为空,流程实例id:{}", param.getProcessInstanceId()); + return null; + } + BusinessProcessVO businessProcessVO = this.refreshBusinessProcessCurrentHandlers(param); + if (businessProcessVO == null) { + return null; + } + // 再补历史已办逻辑,兼容旧代码 + if (param.getOperationNodeId() != null && !MKConstant.DAFTER_NODE_ID.equals(param.getOperationNodeId())) { + MKAllHandlerVO nodeHandlers = mkService.getNodeHandlers(param.getProcessInstanceId(), promoterLoginName, param.getOperationNodeId()); + this.handleNodeHandlers(param.getProcessInstanceId(), nodeHandlers, param); + } + return businessProcessVO; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public BusinessProcessVO refreshBusinessProcessCurrentHandlers(BusinessProcessCurrentHandlerRefreshDTO param) { + if (param == null) { + log.warn("刷新业务流程当前处理人参数为空"); + return null; + } + BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(param.getProcessInstanceId()); + String promoterLoginName = resolvePromoterLoginName(businessProcess, param.getPromoterLoginName()); + if (StringUtils.isBlank(promoterLoginName)) { + log.warn("刷新业务流程当前处理人失败,发起人登录名为空,流程实例id:{}", param.getProcessInstanceId()); + return null; + } + Long businessProcessId = Optional.ofNullable(businessProcess).map(BusinessProcess::getId).orElse(null); + // 1. 查询当前节点 + BusinessProcessVO businessProcessVO = new BusinessProcessVO(); + businessProcessVO.setProcessInstanceId(param.getProcessInstanceId()); + List currentNodes = mkService.getCurrentNodes(param.getProcessInstanceId(), promoterLoginName); + // 处理当前节点信息 + BusinessProcess updateBusinessProcess = this.handleCurrentNodes(businessProcessId, param.getProcessInstanceId(), param.isComplete(), currentNodes, businessProcessVO); + if (updateBusinessProcess != null) { + // 设置当前处理人、当前节点、接收时间 + businessProcessVO.setCurrentHandlers(updateBusinessProcess.getCurrentHandlers()); + businessProcessVO.setCurrentNodeIds(updateBusinessProcess.getCurrentNodeIds()); + businessProcessVO.setCurrentNodeNames(updateBusinessProcess.getCurrentNodeNames()); + businessProcessVO.setReceiveTime(updateBusinessProcess.getReceiveTime()); + } + return businessProcessVO; + } + + @Override + public BusinessProcessVO queryBusinessProcessSnapshot(String processInstanceId) { + AssertUtils.notBlank(processInstanceId, "流程实例id不能为空"); + BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId); + AssertUtils.notNull(businessProcess, "业务流程不存在"); + return this.buildBusinessProcessVO(businessProcess); + } + + @Override + public boolean isEditView(String bizId) { + if (StringUtils.isBlank(bizId)) { + log.warn("查询是否编辑页,业务id为空"); + return false; + } + BusinessProcess businessProcess = this.baseMapper.selectOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getBizId, bizId) + .last("limit 1") + ); + if (businessProcess == null) { + log.warn("查询是否编辑页,业务流程不存在 业务id:{}", bizId); + return false; + } + String approveStatus = businessProcess.getApproveStatus(); + String userAccount = AuthUtil.getUserAccount(); + String promoterLoginName = businessProcess.getPromoterLoginName(); + // (驳回或撤销或草稿)且当前登录人是流程提交人 + boolean result = ApproveStatusEnum.canEdit(approveStatus) && userAccount.equals(promoterLoginName); + log.info("是否编辑页 审批状态:{} 当前登录人:{} 提交人:{} 结果:{}", approveStatus, userAccount, promoterLoginName, result); + return result; + } + + @Override + public String getMKApprovalUrl(String bizId, String processInstanceId) { + boolean bizIdBlank = StringUtil.isBlank(bizId); + boolean processInstanceIdBlank = StringUtil.isBlank(processInstanceId); + AssertUtils.isFalse(bizIdBlank && processInstanceIdBlank, "参数不能为空"); + if (processInstanceIdBlank) { + BusinessProcess businessProcess = this.getOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getBizId, bizId) + .last("limit 1") + ); + AssertUtils.notNull(businessProcess, "业务流程不存在"); + processInstanceId = businessProcess.getProcessInstanceId(); + } + try { + String mkApprovalUrl = mkService.getMKApprovalUrl(processInstanceId, AuthUtil.getUserAccount()); + AssertUtils.notBlank(mkApprovalUrl, "获取mk审批页面链接异常"); + return mkApprovalUrl; + } catch (MKException e) { + throw new ServiceException("获取mk审批页面链接异常 " + e.getMessage()); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public boolean deleteBusinessProcess(BusinessProcessDeleteDTO param) { + log.info("删除业务流程 参数:{}", JSON.toJSONString(param)); + Long bizId = param.getBizId(); + String promoterLoginName = param.getPromoterLoginName(); + if (bizId == null) { + return false; + } + BusinessProcess businessProcess = this.getOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getBizId, bizId) + ); + if (businessProcess == null) { + log.warn("业务流程不存在 业务id:{}", bizId); + return false; + } + if (promoterLoginName == null) { + promoterLoginName = businessProcess.getPromoterLoginName(); + } + // 1. 删除业务流程 + this.removeById(businessProcess.getId()); + // 2. 删除待办 + if (StringUtils.isEmpty(businessProcess.getProcessInstanceId())) { + log.warn("流程id为空 id:{} 业务id:{}", businessProcess.getId(), bizId); + return true; + } + // 3. 删除流程 + return mkService.processDelete(businessProcess.getProcessInstanceId(), promoterLoginName); + } + + @Override + public List queryApprovedRecords(String bizId, String processInstanceId) { + List records = this.queryApprovedRecordsNoAttachments(bizId, processInstanceId); + if (CollectionUtil.isEmpty(records)) { + return records; + } + Map fileMap = new HashMap<>(); + for (ProcessApprovedRecordVO record : records) { + List attachmentParameter = record.getAttachmentParameter(); + // 处理电子签名base64并排序附件 + attachmentParameter = handleAttachmentBase64(attachmentParameter, fileMap); + record.setAttachmentParameter(attachmentParameter); + if (CollectionUtil.isNotEmpty(record.getProcessComments())) { + for (ProcessCommentVO processComment : record.getProcessComments()) { + // 处理电子签名base64并排序附件 + List attachments = handleAttachmentBase64(processComment.getAttachments(), fileMap); + processComment.setAttachments(attachments); + } + } + } + return records; + } + + @Override + public List queryApprovedRecordsNoAttachments(String bizId, String processInstanceId) { + boolean bizIdBlank = StringUtil.isBlank(bizId); + boolean processInstanceIdBlank = StringUtil.isBlank(processInstanceId); + AssertUtils.isFalse(bizIdBlank && processInstanceIdBlank, "参数不能为空"); + + BusinessProcess businessProcess = this.getOne(Wrappers.lambdaQuery() + .eq(!bizIdBlank, BusinessProcess::getBizId, bizId) + .eq(!processInstanceIdBlank, BusinessProcess::getProcessInstanceId, processInstanceId) + .last("limit 1") + ); + AssertUtils.notNull(businessProcess, "业务流程不存在"); + if (processInstanceIdBlank) { + processInstanceId = businessProcess.getProcessInstanceId(); + } + // 查询审批记录 + List mkAuditNotes = mkService.queryAuditNotes(new MKAuditNoteDTO(businessProcess.getPromoterLoginName(), processInstanceId)); + // 转换参数 + return convert.auditNotes2vos(mkAuditNotes, record -> { + List mkSenders = mkService.querySenderList(new MKSenderDTO(record.getProcessInstanceId(), record.getNodeInstanceId())); + return mkSenders.stream() + .map(MKSenderVO::getName) + .toList(); + }); + } + + /** + * 处理附件base64并排序附件 + * @param attachmentParameter + * @param fileMap + */ + private List handleAttachmentBase64(List attachmentParameter, Map fileMap) { + if (CollectionUtil.isEmpty(attachmentParameter)) { + return attachmentParameter; + } + // 电子签名的附件 + List signAttachments = attachmentParameter.stream() + .filter(attachment -> MKConstant.FILE_TYPE_SIGN.equals(attachment.getType())) + .peek(attachment -> { + // 电子签名,查询图片base64 + if (fileMap.containsKey(attachment.getFileId())) { + attachment.setBase64(fileMap.get(attachment.getFileId())); + } else { + String fileBase64 = mkService.getFileBase64(attachment.getFileId()); + fileMap.put(attachment.getFileId(), fileBase64); + attachment.setBase64(fileBase64); + } + }).toList(); + if (CollectionUtil.isEmpty(signAttachments)) { + // 没有电子签名的附件,无需处理 + return attachmentParameter; + } + List result = new ArrayList<>(); + // 纯附件,非电子签名附件 + List attachments = attachmentParameter.stream() + .filter(attachment -> !MKConstant.FILE_TYPE_SIGN.equals(attachment.getType())) + .toList(); + if (CollectionUtil.isNotEmpty(attachments)) { + result.addAll(attachments); + } + // 把电子签名附件放到最后 + result.addAll(signAttachments); + return result; + } + + @Override + public void downloadFile(HttpServletResponse response, String fileId) { + mkService.downloadFile(response,fileId); + } + + @Override + public List queryTodoList(String processInstanceId) { + AssertUtils.notNull(processInstanceId, "流程实例id不能为空"); + BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId); + if (businessProcess == null) { + return null; + } + // 1. 查询当前节点处理人 + List currentNodes = mkService.getCurrentNodes(processInstanceId, businessProcess.getPromoterLoginName()); + if (CollectionUtil.isEmpty(currentNodes)) { + return Collections.emptyList(); + } + return getProcessTodoList(currentNodes); + } + + /** + * 通过流程实例id查询业务流程 + * @param processInstanceId 流程实例id + * @return 业务流程 + */ + private BusinessProcess getBusinessProcessByProcessInstanceId(String processInstanceId) { + return this.getOne(Wrappers.lambdaQuery() + .eq(BusinessProcess::getProcessInstanceId, processInstanceId) + ); + } + + /** + * 解析最终使用的发起人登录名 + * @param businessProcess 业务流程 + * @param fallbackPromoterLoginName 调用方传入的发起人登录名 + * @return 发起人登录名 + */ + private String resolvePromoterLoginName(BusinessProcess businessProcess, String fallbackPromoterLoginName) { + return Optional.ofNullable(businessProcess) + .map(BusinessProcess::getPromoterLoginName) + .filter(StringUtils::isNotBlank) + .orElse(fallbackPromoterLoginName); + } + + /** + * 构造业务流程快照 + * @param businessProcess 业务流程 + * @return 快照 + */ + private BusinessProcessVO buildBusinessProcessVO(BusinessProcess businessProcess) { + BusinessProcessVO businessProcessVO = new BusinessProcessVO(); + businessProcessVO.setProcessInstanceId(businessProcess.getProcessInstanceId()); + businessProcessVO.setCurrentNodeIds(businessProcess.getCurrentNodeIds()); + businessProcessVO.setCurrentNodeNames(businessProcess.getCurrentNodeNames()); + businessProcessVO.setCurrentHandlers(businessProcess.getCurrentHandlers()); + businessProcessVO.setReceiveTime(businessProcess.getReceiveTime()); + return businessProcessVO; + } + + /** + * 获取流程待办列表 + * @param currentNodes + * @return + */ + private List getProcessTodoList(List currentNodes) { + if (CollectionUtil.isEmpty(currentNodes)) { + return Collections.emptyList(); + } + return currentNodes.stream() + .filter(node -> CollectionUtil.isNotEmpty(node.getNodeHandlers())) + .flatMap(node -> node.getNodeHandlers().stream() + // 过滤掉登录名为空的脏数据 + .filter(handler -> handler.getFdHandlerOrgInfo() != null && StringUtil.isNotBlank(handler.getFdHandlerOrgInfo().getLoginName())) + .map(handler -> { + ProcessTodoVO addParam = new ProcessTodoVO(); + addParam.setProcessInstanceId(node.getProcessInstanceId()); + addParam.setNodeId(node.getNodeId()); + addParam.setNodeNumber(node.getNodeNumber()); + addParam.setNodeName(node.getNodeName()); + addParam.setLoginName(handler.getFdHandlerOrgInfo().getLoginName()); + addParam.setUserName(handler.getHandlerName()); + addParam.setStatus(TodoStatus.TODO.getCode()); + addParam.setReceiveTime(handler.getReceiveTime()); + return addParam; + }) + ).toList(); + } + + @Override + public IPage queryMkApprovalList(IPage page, ApprovalDTO param) { + if (MKDoc.RELATED.getCode().equals(param.getDocType())) { + // 我参与的,调用流程列表接口 + MKProcessDTO processParam = approvalConvert.dto2mk(param); + processParam.setPage((int) page.getCurrent(), (int) page.getSize()); + MKPageVO mkPage = mkService.queryProcessList(processParam); + page.setTotal(mkPage.getTotalSize()); + page.setRecords(approvalConvert.mkProcess2vos(mkPage.getContent())); + return page; + } + // 非我参与的,调用审批中心接口 + MKApprovalDTO approvalParam = getMkApprovalParam(param); + approvalParam.setPage((int) page.getCurrent(), (int) page.getSize()); + MKPageVO mkPage = mkService.queryApprovalList(approvalParam); + page.setTotal(mkPage.getTotalSize()); + page.setRecords(approvalConvert.mk2vos(mkPage.getContent())); + return page; + } + + /** + * 获取mk查询参数 + * + * @param param + * @return + */ + private MKApprovalDTO getMkApprovalParam(ApprovalDTO param) { + String docType = param.getDocType(); + // 我的待审 + // mk页面接口参数 {"offset":0,"pageNo":1,"pageSize":10,"conditions":{"fdStartTime":{"$gte":1711900800000,"$lte":1746374399999},"fdReceiveTime":{"$gte":1712160000000,"$lte":1746115199999},"fdTemplateName":{"$contains":"测试"},"keyword":{"$eq":"提交"},"mydoc":{"$eq":"myApproving"}},"sorts":{"fdLevel":"asc","fdReceiveTime":"desc"}} + MKApprovalDTO approvalParam = new MKApprovalDTO(); + approvalParam.setLoginName(param.getLoginName()); + ISort sort = getSort(docType, approvalParam); + approvalParam.setSorts(sort); + // 获取查询条件的参数 + MKApprovalConditionDTO condition = getCondition(param); + approvalParam.setConditions(condition); + return approvalParam; + } + + /** + * 获取排序 + * @param docType + * @param approvalParam + * @return + */ + private ISort getSort(String docType, MKApprovalDTO approvalParam) { + if (MKDoc.APPROVING.getCode().equals(docType) || MKDoc.READING.getCode().equals(docType)) { + // 待办、待阅排序是相同的 + return new MKApprovingSortDTO(); + } + if (MKDoc.APPROVED.getCode().equals(docType)) { + // 已办 + return new MKApprovedSortDTO(); + } + if (MKDoc.READ.getCode().equals(docType)) { + // 已阅 + return new MKReadSortDTO(); + } + if (MKDoc.CREATE.getCode().equals(docType) || MKDoc.RELATED.getCode().equals(docType)) { + // 我发起的/我关联的 + return new MKCreateSortDTO(); + } + throw new ServiceException("不支持的单据类型"); + } + + /** + * 获取查询条件 + * @param param + * @return + */ + private MKApprovalConditionDTO getCondition(ApprovalDTO param) { + MKApprovalConditionDTO condition = null; + for (MKApprovalConvert convert : MKApprovalConvert.values()) { + MKConditionDTO.MKConditionDTOBuilder builder = null; + BiConsumer setter = convert.getSetter(); + List composes = convert.getComposes(); + // 是否多个 Compose + boolean multi = composes.size() > 1; + if (multi) { + // 不是多个setter + for (MKApprovalConvert.Compose compose : composes) { + // 遍历获取参数值 + String value = compose.getGetter().apply(param); + if (StringUtils.isNotBlank(value)) { + // 参数值不为空,设置到builder + if (builder == null) { + builder = MKConditionDTO.builder(); + } + compose.getBuilderSetter().accept(builder, value); + } + } + if (builder != null) { + // builder不为空,设置到最终的条件 + if (condition == null) { + condition = new MKApprovalConditionDTO(); + } + setter.accept(condition, builder.build()); + convert.getSetter().accept(condition, builder.build()); + } + } else { + // 只有1个compose + MKApprovalConvert.Compose compose = composes.get(0); + String value = compose.getGetter().apply(param); + if (StringUtils.isNotBlank(value)) { + // 替换中文逗号为英文逗号 + value = value.replace(",", ","); + // 按英文逗号拆分值 + String[] values = value.split(","); + for (String singleValue: values) { + if (StringUtils.isNotBlank(value)) { + // 参数值不为空,设置到builder + if (builder == null) { + builder = MKConditionDTO.builder(); + } + compose.getBuilderSetter().accept(builder, singleValue); + if (builder != null) { + // builder不为空,设置到最终的条件 + if (condition == null) { + condition = new MKApprovalConditionDTO(); + } + // 索引不超过setters长度,设置条件 + setter.accept(condition, builder.build()); + } + } + } + } + } + } + return condition; + } + + /** + * 处理已审批的人 + * + * @param processInstanceId + * @param nodeHandlers + * @param param + */ + private void handleNodeHandlers(String processInstanceId, MKAllHandlerVO nodeHandlers, BusinessProcessUpdateDTO param) { + if (nodeHandlers == null) { + log.warn("修改业务流程 查询操作节点历史处理信息为空 流程实例id:{} 操作节点id:{}", param.getProcessInstanceId(), param.getOperationNodeId()); + return; + } + List approvedHandlers = nodeHandlers.getApprovedHandlers(); + if (CollectionUtil.isEmpty(approvedHandlers)) { + // 已审批为空 + log.warn("修改业务流程 查询操作节点已处理信息为空 流程实例id:{} 操作节点id:{}", param.getProcessInstanceId(), param.getOperationNodeId()); + return; + } + + } + + /** + * 处理当前节点信息 + * + * @param businessProcessId + * @param processInstanceId + * @param complete + * @param currentNodes + * @param businessProcessVO + */ + private BusinessProcess handleCurrentNodes(Long businessProcessId, String processInstanceId, boolean complete, List currentNodes, BusinessProcessVO businessProcessVO) { + if (CollectionUtil.isEmpty(currentNodes)) { + log.info("修改业务流程 当前节点处理人为空"); + if (businessProcessId != null) { + // 清空当前节点,当前处理人,接收时间 + log.info("修改业务流程 流程结束清空当前节点,当前处理人,接收时间 业务流程id:{} 流程实例id:{}", businessProcessId, processInstanceId); + this.lambdaUpdate() + .eq(BusinessProcess::getId, businessProcessId) + .set(BusinessProcess::getCurrentNodeIds, null) + .set(BusinessProcess::getCurrentNodeNames, null) + .set(BusinessProcess::getCurrentHandlers, null) + .set(complete, BusinessProcess::getIsCompleted, true) + .set(complete, BusinessProcess::getCompleteTime, new Date()) + .set(BusinessProcess::getUpdateTime, new Date()) + .update(); + } else { + log.warn("修改业务流程 流程结束 业务流程id为空"); + } + return null; + } + // 处理待办 + List processTodoList = getProcessTodoList(currentNodes); + + // 更新业务流程 + return updateBusinessProcess(businessProcessId, processTodoList); + } + + /** + * 更新业务流程 + * + * @param businessProcessId + * @param addToDos + */ + private BusinessProcess updateBusinessProcess(Long businessProcessId, List addToDos) { + if (CollectionUtil.isEmpty(addToDos)) { + log.warn("新增待办为空"); + return null; + } + String nodeIds = addToDos.stream() + .map(ProcessTodoVO::getNodeId) + .distinct() + .collect(Collectors.joining(",")); + String nodeNames = addToDos.stream() + .map(ProcessTodoVO::getNodeName) + .distinct() + .collect(Collectors.joining(",")); + String usernames = addToDos.stream() + .map(ProcessTodoVO::getUserName) + .distinct() + .collect(Collectors.joining(",")); + Date receiveTime = addToDos.get(0).getReceiveTime(); + // 更新当前节点id,当前节点名称,当前处理人,接收时间 + BusinessProcess updateParam = new BusinessProcess(); + updateParam.setId(businessProcessId); + updateParam.setCurrentNodeIds(nodeIds); + updateParam.setCurrentNodeNames(nodeNames); + updateParam.setCurrentHandlers(usernames); + updateParam.setReceiveTime(receiveTime); + if (businessProcessId != null) { + this.updateById(updateParam); + } else { + log.warn("新增待办,业务流程id为空"); + } + return updateParam; + } + + /** + * 是否修改审批状态,驳回状态只修改驳回节点是起草节点的 + * @param approveStatus + * @param rejectNodeId + * @return + */ + private boolean updateApproveStatus(String approveStatus, String rejectNodeId) { + if (!ApproveStatusEnum.REJECTED.getValue().equals(approveStatus)) { + // 不是驳回状态,直接修改 + return true; + } + if (StringUtils.isBlank(rejectNodeId)) { + // 驳回节点id为空说明是老流程,没有配置参数,可以修改 + return true; + } + // 是驳回状态,只修改驳回节点id是起草节点id的 + return MKConstant.DAFTER_NODE_ID.equals(rejectNodeId); + } + + /** + * 提交mk流程 + * @param param + * @return + */ + private String submitMKProcess(BusinessProcessSubmitDTO param) { + if (param.getExecuteParam() == null || StringUtil.isBlank(param.getExecuteParam().getProcessId())) { + // 执行参数为空,是提交 + MKProcessCreateDTO processParam = new MKProcessCreateDTO(); + processParam.setFormInstanceId(String.valueOf(param.getBizId())); + processParam.setLoginName(param.getPromoterLoginName()); + processParam.setSubmitIdentity(param.getPromoterLoginName()); + processParam.setSubject(param.getSubject()); + processParam.setTemplateCode(mkProperties.getTemplateCodePrefix() + param.getProcessType()); + processParam.setFormValues(param.getProcessParam()); + // 临时变量设置为业务表单对象,以便不用修改mk流程表单字段,直接使用流程模板临时变量 + processParam.setTempVarData(ObjectUtil.cloneByStream(param.getProcessParam())); + return mkService.processSubmit(processParam); + } + // 执行参数不为空,是驳回/撤销后提交/废弃 + ProcessExecuteDTO executeParam = param.getExecuteParam(); + MKProcessExecuteDTO processExecuteDTO = convert.dto2mk(executeParam); + processExecuteDTO.setLoginName(param.getPromoterLoginName()); + processExecuteDTO.setFormValues(param.getProcessParam()); + // 临时变量设置为业务表单对象,以便不用修改mk流程表单字段,直接使用流程模板临时变量 + processExecuteDTO.setTempVarData(ObjectUtil.cloneByStream(param.getProcessParam())); + // 重新设置标题,防止标题变了 + processExecuteDTO.setSubject(param.getSubject()); + mkService.processExecute(processExecuteDTO); + return executeParam.getProcessId(); + } + +} diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/SystemApplication.java b/blade-service/blade-system/src/main/java/org/springblade/system/SystemApplication.java index 278ef63..b82811e 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/SystemApplication.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/SystemApplication.java @@ -28,11 +28,13 @@ package org.springblade.system; import org.springblade.core.cloud.client.BladeCloudApplication; import org.springblade.core.launch.BladeApplication; import org.springblade.core.launch.constant.AppConstant; +import org.springframework.context.annotation.ComponentScan; /** * 系统模块启动器 * @author Chill */ +@ComponentScan(basePackages = {"org.springblade.system", "org.springblade.process"}) @BladeCloudApplication public class SystemApplication { diff --git a/pom.xml b/pom.xml index 41c2daa..29b91ad 100644 --- a/pom.xml +++ b/pom.xml @@ -110,6 +110,11 @@ blade-system-api ${revision} + + org.springblade + blade-process-api + ${revision} + org.springblade