From fbf6e2d0a4152d79125e3b0ca2417cc769bfdddd Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 30 Aug 2024 10:59:02 +0800 Subject: [PATCH 001/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E4=B8=BA=201.4.2-SNAPSHOT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../cn/axzo/workflow/common/enums/ProcessTaskEventEnum.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 130212e4f..f8f3df719 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ workflow-engine - 1.4.1-SNAPSHOT + 1.4.2-SNAPSHOT 2.0.0-SNAPSHOT 2.0.0-SNAPSHOT 11.8 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ProcessTaskEventEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ProcessTaskEventEnum.java index 124af9a6e..cfe9b8531 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ProcessTaskEventEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ProcessTaskEventEnum.java @@ -10,8 +10,8 @@ import cn.axzo.framework.rocketmq.Event; */ public enum ProcessTaskEventEnum { - PROCESS_TASK_CREATED("process-task", "process-task-created", "流程任务已创建"), PROCESS_TASK_ASSIGNED("process-task", "process-task-assigned", "流程任务已分配"), + PROCESS_TASK_CREATED("process-task", "process-task-created", "流程任务已创建"), PROCESS_TASK_COMPLETED("process-task", "process-task-completed", "流程任务已结束"), PROCESS_TASK_DELETED("process-task", "process-task-deleted", "流程任务已删除"), ; From a8204cbeb615d6cc981cb0098873fd593504752d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 30 Aug 2024 14:45:04 +0800 Subject: [PATCH 002/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97=E7=9A=84=20DDL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/sql/upgrade_to_1.4.2.sql | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql new file mode 100644 index 000000000..fd73d58e1 --- /dev/null +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -0,0 +1,26 @@ +create table `workflow-engine`.ext_ax_process_log +( + id bigint auto_increment comment '主键' + primary key, + process_instance_id varchar(64) default '' not null comment '流程实例 ID', + activity_id varchar(64) default '' not null comment '节点 ID', + activity_name varchar(255) default '' not null comment '节点名称', + approval_method varchar(32) default '' not null comment '审批方式:配置审批人/业务指定/业务触发(不含人)', + node_type varchar(32) default '' not null comment '节点类型:审批节点/业务节点/评论节点/抄送节点', + node_mode varchar(32) default '' not null comment '节点模式:会签/或签', + task_id varchar(64) default '' not null comment '任务 ID', + advice varchar(4000) default '' not null comment '操作建议', + operation_desc varchar(4000) default '' not null comment '操作描述', + assignee varchar(1024) default '' not null comment '审批人', + start_time datetime(3) default CURRENT_TIMESTAMP not null comment '任务开始时间', + end_time datetime(3) null comment '任务结束时间', + returned tinyint(1) default 0 not null comment '已回退', + status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', + create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', + update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete bigint default 0 not null comment '是否删除' +) + comment '审批日志持久化'; + + + From 4fc3993cdf4b255bf18959e0cb439859a6a6ebb4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 30 Aug 2024 14:57:30 +0800 Subject: [PATCH 003/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97=E7=9A=84=20DDL=20=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/sql/upgrade_to_1.4.2.sql | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index fd73d58e1..19f94326e 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -12,8 +12,8 @@ create table `workflow-engine`.ext_ax_process_log advice varchar(4000) default '' not null comment '操作建议', operation_desc varchar(4000) default '' not null comment '操作描述', assignee varchar(1024) default '' not null comment '审批人', - start_time datetime(3) default CURRENT_TIMESTAMP not null comment '任务开始时间', - end_time datetime(3) null comment '任务结束时间', + start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', + end_time datetime(3) null comment '任务结束时间', returned tinyint(1) default 0 not null comment '已回退', status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', @@ -21,6 +21,3 @@ create table `workflow-engine`.ext_ax_process_log is_delete bigint default 0 not null comment '是否删除' ) comment '审批日志持久化'; - - - From a4df310e5499baeff783aedd6864c95359736dc2 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 30 Aug 2024 19:00:39 +0800 Subject: [PATCH 004/139] =?UTF-8?q?REQ-2924-=E6=B5=81=E7=A8=8B=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=80=80=E5=9B=9E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessTaskApi.java | 6 + .../bpmn/task/BpmnTaskBackAuditDTO.java | 30 ++++ .../core/engine/cmd/CustomBackTaskCmd.java | 147 ++++++++++++++++++ .../core/service/BpmnProcessTaskService.java | 7 +- .../impl/BpmnProcessTaskServiceImpl.java | 13 ++ .../web/bpmn/BpmnProcessTaskController.java | 13 ++ 6 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 80d57d980..d173f1856 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; @@ -71,6 +72,11 @@ public interface ProcessTaskApi { @PostMapping("/api/process/task/batch/approve") CommonResponse batchApproveTask(@Validated @RequestBody List dtos); + + @Operation(summary = "回退") + @PostMapping("/api/process/task/back") + CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); + /** * 驳回 * diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java new file mode 100644 index 000000000..a7a9611f9 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java @@ -0,0 +1,30 @@ +package cn.axzo.workflow.common.model.request.bpmn.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; + +@EqualsAndHashCode(callSuper = true) +@ApiModel("回退到指定节点入参模型") +@Data +@Validated +@AllArgsConstructor +@NoArgsConstructor +public class BpmnTaskBackAuditDTO extends BpmnTaskAuditDTO { + + @ApiModelProperty(value = "当前流程节点id", required = true) + @NotBlank(message = "当前流程节点id不能为空") + private String currentActivityId; + + @ApiModelProperty(value = "目标流程节点id", required = true) + @NotEmpty(message = "目标流程节点id不能为空") + private String toActivityId; +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java new file mode 100644 index 000000000..78b4198c9 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -0,0 +1,147 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import com.alibaba.fastjson.JSON; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; + +/** + * 回退命令 + */ +public class CustomBackTaskCmd extends AbstractCommand implements Serializable { + private static final Logger log = LoggerFactory.getLogger(CustomBackTaskCmd.class); + private final String taskId; + /** + * advice 统一均为审批节点的审批意见,一般为用户在同意、驳回时填写的内容 + * 有值时,在日志中一般出现在 operationDesc 的下方 + */ + private final String advice; + /** + * operationDesc 统一为审批节点的动作描述,例如:某某转交、加签某某等 + * 在日志中一般出现在节点名称的下方 + * 不传,默认"已通过" + */ + private String operationDesc; + /** + * 附件, 可为空 + */ + private final List attachmentList; + private final BpmnTaskDelegateAssigner approver; + /** + * 下级节点的审批,可为空 + */ + private final BpmnTaskDelegateAssigner nextApprover; + + /** + * 指定节点类型 + */ + private List nodeTypes; + + private String currentActivityId; + + private String toActivityId; + + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("taskId", taskId); + params.put("advice", advice); + params.put("operationDesc", operationDesc); + params.put("attachmentList", JSON.toJSONString(attachmentList)); + params.put("approver", JSON.toJSONString(approver)); + params.put("nextApprover", JSON.toJSONString(nextApprover)); + params.put("nodeTypes", JSON.toJSONString(nodeTypes)); + return JSON.toJSONString(params); + } + + public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto) { + this(dto, null); + if (Objects.nonNull(dto.getOperationDesc())) { + this.operationDesc = dto.getOperationDesc(); + } + } + + public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto, String operationDesc) { + this.taskId = dto.getTaskId(); + this.advice = dto.getAdvice(); + this.attachmentList = dto.getAttachmentList(); + this.approver = dto.getApprover(); + this.nextApprover = dto.getNextApprover(); + this.nodeTypes = dto.getNodeTypes(); + // 这里的不能直接使用字符串的比较,因为外部可能传入空字符串,比如发起人的通过时,就是传入的空字符串 + if (Objects.nonNull(operationDesc)) { + this.operationDesc = operationDesc; + } else { + this.operationDesc = "已回退"; + } + this.currentActivityId = dto.getCurrentActivityId(); + this.toActivityId = dto.getToActivityId(); + } + + @Override + public Void execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + HistoricTaskInstanceQuery taskQuery = + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + TaskService taskService = processEngineConfiguration.getTaskService(); + + HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); + + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + validTask(historicTaskInstance, (TaskEntity) task, approver, nodeTypes); + if (StringUtils.hasLength(advice)) { + Authentication.setAuthenticatedUserId(approver.buildAssigneeId()); + addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice); + Authentication.setAuthenticatedUserId(null); + } + + batchAddAttachment(commandContext, task.getProcessInstanceId(), taskId, attachmentList, approver); + + Authentication.setAuthenticatedUserId(Objects.nonNull(approver) ? approver.buildAssigneeId() : null); + addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc); + Authentication.setAuthenticatedUserId(null); + + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + if (Objects.nonNull(nextApprover)) { + // 主动设置下级审批人 + runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER, + nextApprover); + } + ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + + runtimeService.createChangeActivityStateBuilder().moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId),toActivityId); + return null; + } + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java index cdcd624df..28482b76c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java @@ -1,10 +1,10 @@ package cn.axzo.workflow.core.service; -import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; @@ -41,6 +41,11 @@ public interface BpmnProcessTaskService { */ void approveTask(BpmnTaskAuditDTO taskAuditDTO); + /** + * 回退 + */ + void backTask(BpmnTaskBackAuditDTO taskAuditDTO); + /** * 批量同意 * diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 86f7d06f8..99b5b0c50 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; @@ -25,6 +26,7 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskAsyncCmd; import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd; +import cn.axzo.workflow.core.engine.cmd.CustomBackTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomCommentTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomCompleteDummyTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomCountersignUserTaskAsyncCmd; @@ -310,6 +312,17 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } } + @Override + @Transactional(rollbackFor = Exception.class) + public void backTask(BpmnTaskBackAuditDTO dto) { + CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); + if (dto.getAsync()) { + commandExecutor.execute(new CustomApproveTaskAsyncCmd(dto)); + } else { + commandExecutor.execute(new CustomBackTaskCmd(dto)); + } + } + @Override public BatchOperationResultVO batchApproveTask(List dtos) { return batchOperation(dtos, bpmnProcessTaskService::approveTask); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 14076241c..e539cf42a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; @@ -118,6 +119,18 @@ public class BpmnProcessTaskController implements ProcessTaskApi { return success(bpmnProcessTaskService.batchApproveTask(dtos)); } + /** + * 回退 + */ + @Operation(summary = "回退任务") + @PostMapping("/back") + @RepeatSubmit + @Override + public CommonResponse backTask(BpmnTaskBackAuditDTO dto) { + bpmnProcessTaskService.backTask(dto); + return success(); + } + /** * 驳回 */ From 82be0200311f6488501ddd2aa6faf2dcd19d62de Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 2 Sep 2024 10:59:57 +0800 Subject: [PATCH 005/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97=E7=9A=84=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/InternalExtAxTaskInstEvent_lo_Listener.java | 6 ++++++ .../core/repository/entity/ExtAxProcessLog.java | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java index e34dd85fc..24052586e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java @@ -44,6 +44,12 @@ public class InternalExtAxTaskInstEvent_lo_Listener extends AbstractBpmnEventLis return Integer.MIN_VALUE; } + @Override + public void onAssigned(DelegateTask delegateTask) { + // 用于创建该流程实例发起人的日志 + BpmnTaskEventListener.super.onAssigned(delegateTask); + } + @Override public void onCreated(DelegateTask delegateTask) { String assignee; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java new file mode 100644 index 000000000..01b7db77d --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java @@ -0,0 +1,12 @@ +package cn.axzo.workflow.core.repository.entity; + +import cn.axzo.framework.data.mybatisplus.model.BaseEntity; + +/** + * TODO + * + * @author wangli + * @since 2024-08-30 15:29 + */ +public class ExtAxProcessLog extends BaseEntity { +} From d6aa18dea0f681ec3f046c09a8d83813609d029b Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Mon, 2 Sep 2024 11:14:39 +0800 Subject: [PATCH 006/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=88=B0=E6=8C=87=E5=AE=9A=E8=8A=82=E7=82=B9=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java | 4 +++- .../server/controller/web/bpmn/BpmnProcessTaskController.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 78b4198c9..b3db09fcd 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -140,7 +140,9 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ } ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); - runtimeService.createChangeActivityStateBuilder().moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId),toActivityId); + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId),toActivityId).changeState(); return null; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index e539cf42a..85b71c29a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -126,7 +126,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @PostMapping("/back") @RepeatSubmit @Override - public CommonResponse backTask(BpmnTaskBackAuditDTO dto) { + public CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto) { bpmnProcessTaskService.backTask(dto); return success(); } From 700dd1941227bfb1ef07c0fdde6feb065585d7f5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 3 Sep 2024 15:12:23 +0800 Subject: [PATCH 007/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97=E7=9A=84=E5=AE=9E=E4=BD=93?= =?UTF-8?q?,=E4=BB=A5=E5=8F=8A=E5=AE=8C=E5=96=84=E7=9B=B8=E5=85=B3=20mappe?= =?UTF-8?q?r/service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/enums/BpmnButtonEnum.java | 2 +- .../CustomReceiveTaskActivityBehavior.java | 5 +- .../listener/EngineEntityEventListener.java | 206 ++++++++++++++++++ ...ernalExtAxTaskInstEvent_lo_1_Listener.java | 93 ++++++++ ...nternalExtAxTaskInstEvent_lo_Listener.java | 6 - .../repository/entity/ExtAxProcessLog.java | 99 ++++++++- .../mapper/ExtAxProcessLogMapper.java | 8 + .../core/service/ExtAxProcessLogService.java | 37 ++++ .../impl/ExtAxProcessLogServiceImpl.java | 76 +++++++ .../main/resources/sql/upgrade_to_1.4.2.sql | 40 ++-- 10 files changed, 546 insertions(+), 26 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxProcessLogMapper.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java index 2daf65036..d9cc769c1 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java @@ -35,7 +35,7 @@ public enum BpmnButtonEnum { /** * 回退按钮 */ - BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "回退"), + BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "退回"), /** * 抄送按钮 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java index 3004da535..7661176b9 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java @@ -7,6 +7,7 @@ import org.flowable.bpmn.model.ReceiveTask; import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.TaskListener; import org.flowable.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.persistence.entity.ExecutionEntity; @@ -48,7 +49,9 @@ public class CustomReceiveTaskActivityBehavior extends ReceiveTaskActivityBehavi task.setTaskDefinitionKey(receiveTask.getId()); task.setPropagatedStageInstanceId(execution.getPropagatedStageInstanceId()); task.setName(receiveTask.getName()); - TaskHelper.insertTask(task, (ExecutionEntity) execution, false, false); + TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false); + + processEngineConfiguration.getListenerNotificationHelper().executeTaskListeners(task, TaskListener.EVENTNAME_CREATE); // 添加 taskInst 扩展表数据 FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java new file mode 100644 index 000000000..8326140b1 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java @@ -0,0 +1,206 @@ +package cn.axzo.workflow.core.engine.listener; + +import cn.axzo.framework.jackson.utility.JSON; +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; +import com.google.common.collect.ImmutableSet; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.ListUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListener; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEvent; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.bizSpecify; +import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_ACTIVATED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_CREATED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_DELETED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_INITIALIZED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_SUSPENDED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_UPDATED; + +/** + * TODO + * + * @author wangli + * @since 2024-09-02 15:34 + */ +@Component +@Slf4j +@AllArgsConstructor +public class EngineEntityEventListener extends AbstractFlowableEventListener { + + private final ExtAxProcessLogService processLogService; + + public static final Set SUPPORTED = + ImmutableSet.builder() + .add(ENTITY_CREATED) + .add(ENTITY_INITIALIZED) + .add(ENTITY_UPDATED) + .add(ENTITY_DELETED) + .add(ENTITY_SUSPENDED) + .add(ENTITY_ACTIVATED) + .build(); + + @Override + public void onEvent(FlowableEvent event) { + if (event instanceof FlowableEntityEvent) { + FlowableEntityEvent entityEvent = (FlowableEntityEvent) event; +// log.warn("entity event type: {}, class: {}",entityEvent.getType(), entityEvent.getEntity().getClass()); + if (entityEvent.getEntity() instanceof TaskEntity) { + TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity(); + log.error("event taskId :{}, taskDefKey: {}", taskEntity.getId(), taskEntity.getTaskDefinitionKey()); + if (Objects.equals(event.getType(), ENTITY_CREATED)) { + onCreate(taskEntity); + } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) { + onInitialized(taskEntity); + } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) { + onUpdated(taskEntity); + } else if (Objects.equals(event.getType(), ENTITY_DELETED)) { + onDeleted(taskEntity); + } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) { + onSuspended(taskEntity); + } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) { + onActivated(taskEntity); + } + } + } + } + + private void onActivated(TaskEntity taskEntity) { + log.error("onActivated"); + } + + private void onSuspended(TaskEntity taskEntity) { + log.error("onSuspended"); + } + + private void onDeleted(TaskEntity taskEntity) { + log.error("onDeleted"); + } + + private void onUpdated(TaskEntity taskEntity) { + log.error("onUpdated"); + if (Objects.equals(HIDDEN_ASSIGNEE_ID, taskEntity.getAssignee())) { + ExtAxProcessLog queryLog = new ExtAxProcessLog(); + queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); + queryLog.setTaskId(taskEntity.getId()); + processLogService.delete(queryLog); + } else { + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + List assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(), "[_ACTIVITY_INFO_SNAPSHOT_]" + taskEntity.getTaskDefinitionKey(), List.class); + ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny() + .ifPresent(assignee -> { + log.error("审批人: {}", JSON.toJSONString(assignee)); + ExtAxProcessLog queryLog = new ExtAxProcessLog(); + queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); + queryLog.setTaskId(taskEntity.getId()); + processLogService.updateAssignee(queryLog, assignee); + }); + } + } + + private void onInitialized(TaskEntity taskEntity) { + log.error("onInitialized"); + } + + private void onCreate(TaskEntity taskEntity) { + log.error("onCreate"); + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + BpmnTaskDelegateAssigner assignee; + + // 记录发起人 + boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType()); + if (isNodeStarter) { + assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), + INTERNAL_INITIATOR)); + if (Objects.isNull(assignee)) { + // 兼容历史数据 + assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), OLD_INTERNAL_INITIATOR)); + } + } else { + assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); + } + + RepositoryService repositoryService = processEngineConfiguration.getRepositoryService(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(taskEntity.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(taskEntity.getTaskDefinitionKey()); + + ExtAxProcessLog log = new ExtAxProcessLog(); + log.setProcessInstanceId(taskEntity.getProcessInstanceId()); + log.setTenantId(taskEntity.getTenantId()); + log.setActivityId(taskEntity.getTaskDefinitionKey()); + log.setActivityName(taskEntity.getName()); + log.setApprovalMethod((isNodeStarter ? nobody : getApprovalMethod(flowElement).orElse(nobody)).getType()); + if (Objects.equals(log.getApprovalMethod(), nobody.getType()) || Objects.equals(log.getApprovalMethod(), bizSpecify.getType())) { + log.setOperationDesc("待处理"); + } + log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType()); + log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType()); + log.setTaskId(taskEntity.getId()); + if (Objects.nonNull(assignee)) { + // FIXME 应该还有逻辑来拼接 + log.setOperationDesc(isNodeStarter ? assignee.getAssignerName() : null); + + log.setAssigneeFull(assignee); + log.setAssigneeId(Long.valueOf(assignee.getPersonId())); + log.setAssigneeTenantId(assignee.getTenantId()); + log.setAssigneeName(assignee.getAssignerName()); + log.setAssigneeOuId(assignee.getOuId()); + } + log.setStartTime(taskEntity.getCreateTime()); + log.setStatus(PROCESSING.getStatus()); + processLogService.insert(log); + } + + private BpmnFlowNodeMode getNodeMode(FlowElement flowElement) { + BpmnFlowNodeMode node = GENERAL; + if (flowElement instanceof UserTask) { + UserTask userTask = (UserTask) flowElement; + if (userTask.getBehavior() instanceof MultiInstanceActivityBehavior) { + MultiInstanceActivityBehavior behavior = + (MultiInstanceActivityBehavior) userTask.getBehavior(); + node = Objects.equals(AND_SIGN_EXPRESSION, behavior.getCompletionCondition()) ? AND : OR; + } + } + return node; + } + + @Override + public boolean isFailOnException() { + return true; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java new file mode 100644 index 000000000..602ba4841 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java @@ -0,0 +1,93 @@ +package cn.axzo.workflow.core.listener.impl; + +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.common.context.TaskOperationContext; +import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; +import cn.axzo.workflow.core.listener.BpmnTaskEventListener; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; +import org.flowable.task.service.delegate.DelegateTask; + +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; + +/** + * Core 包内置的,可共用与 Jar 包集成和微服务集成 + *

+ * 该类主要处理新版的日志表 + * + * @author wangli + * @since 2023/12/9 22:56 + */ +@Slf4j +//@Component +//@Scope("prototype") +@AllArgsConstructor +public class InternalExtAxTaskInstEvent_lo_1_Listener extends AbstractBpmnEventListener implements BpmnTaskEventListener { + private final RuntimeService runtimeService; + private final RepositoryService repositoryService; + private final ExtAxProcessLogService processLogService; + + @Override + public int getOrder() { + return Integer.MIN_VALUE + 1; + } + + /** + * Assigned 事件先于 Create 事件,所以在此事件中, 只要任务逻辑上应该有人,那么这里的数据就有人, 仅创建日志的初始状态 + * + * @param delegateTask + */ + @Override + public void onCreated(DelegateTask delegateTask) { + BpmnTaskDelegateAssigner assignee; + // 记录发起人 + boolean isNodeStarter = Objects.equals(delegateTask.getTaskDefinitionKey(), NODE_STARTER.getType()); + if (isNodeStarter) { + assignee = getContext().getInitiator(() -> + BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), + INTERNAL_INITIATOR))); + if (Objects.isNull(assignee)) { + // 兼容历史数据 + assignee = getContext().getInitiator(() -> + BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), OLD_INTERNAL_INITIATOR))); + } + } else { + assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId())); + } + + BpmnModel bpmnModel = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(delegateTask.getTaskDefinitionKey()); + + } + + + private BpmnFlowNodeMode getNodeMode(FlowElement flowElement) { + BpmnFlowNodeMode node = GENERAL; + if (flowElement instanceof UserTask) { + UserTask userTask = (UserTask) flowElement; + if (userTask.getBehavior() instanceof MultiInstanceActivityBehavior) { + MultiInstanceActivityBehavior behavior = + (MultiInstanceActivityBehavior) userTask.getBehavior(); + node = Objects.equals(AND_SIGN_EXPRESSION, behavior.getCompletionCondition()) ? AND : OR; + } + } + return node; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java index 24052586e..e34dd85fc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_Listener.java @@ -44,12 +44,6 @@ public class InternalExtAxTaskInstEvent_lo_Listener extends AbstractBpmnEventLis return Integer.MIN_VALUE; } - @Override - public void onAssigned(DelegateTask delegateTask) { - // 用于创建该流程实例发起人的日志 - BpmnTaskEventListener.super.onAssigned(delegateTask); - } - @Override public void onCreated(DelegateTask delegateTask) { String assignee; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java index 01b7db77d..179b8d732 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java @@ -1,12 +1,109 @@ package cn.axzo.workflow.core.repository.entity; import cn.axzo.framework.data.mybatisplus.model.BaseEntity; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; /** - * TODO + * 审批日志 * * @author wangli * @since 2024-08-30 15:29 */ +@EqualsAndHashCode(callSuper = true) +@TableName(value = "ext_ax_process_log", autoResultMap = true) +@Data +@ToString(callSuper = true) public class ExtAxProcessLog extends BaseEntity { + + /** + * 流程实例 ID + */ + private String processInstanceId; + /** + * 实例归属租户 + */ + private String tenantId; + /** + * 活动节点 ID + */ + private String activityId; + /** + * 活动节点名称 + */ + private String activityName; + /** + * 审批方式:配置审批人/业务指定/业务触发(不含人) + */ + private String approvalMethod; + /** + * 节点类型:审批节点/业务节点/评论节点/抄送节点 + */ + private String nodeType; + /** + * 节点模式:会签/或签 + */ + private String nodeMode; + /** + * 任务 ID + */ + private String taskId; + /** + * 操作建议 + */ + private String advice; + /** + * 操作描述 + */ + private String operationDesc; + /** + * 审批人对象信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private BpmnTaskDelegateAssigner assigneeFull; + /** + * 审批人标识 + */ + private Long assigneeId; + /** + * 审批人归属租户 + */ + private String assigneeTenantId; + /** + * 审批人姓名 + */ + private String assigneeName; + /** + * 审批人归属单位 + */ + private String assigneeOuId; + /** + * 任务开始时间 + */ + private Date startTime; + /** + * 任务结束时间 + */ + private Date endTime; + /** + * 已回退标志 + */ + private Boolean returned; + /** + * 任务状态:审批中/通过/驳回/转交/加签/退回 + */ + private String status; + /** + * 扩展字段 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private JSONObject extra; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxProcessLogMapper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxProcessLogMapper.java new file mode 100644 index 000000000..cf9ebd84f --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxProcessLogMapper.java @@ -0,0 +1,8 @@ +package cn.axzo.workflow.core.repository.mapper; + +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ExtAxProcessLogMapper extends BaseMapperX { +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java new file mode 100644 index 000000000..7cee90d03 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java @@ -0,0 +1,37 @@ +package cn.axzo.workflow.core.service; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; + +/** + * Api Log 表操作服务 + * + * @author wangli + * @since 2024/4/3 10:40 + */ +public interface ExtAxProcessLogService { + /** + * 新增审批流程日志 + * + * @param log + * @return + */ + Long insert(ExtAxProcessLog log); + + /** + * 根据参数删除指定任务 + * + * @param deleteLog + */ + void delete(ExtAxProcessLog deleteLog); + + /** + * 更新指定任务的审批人 + * + * @param updateLog + * @param assignee + */ + void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee); + + void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, String operationDesc); +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java new file mode 100644 index 000000000..5f491349a --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java @@ -0,0 +1,76 @@ +package cn.axzo.workflow.core.service.impl; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; +import cn.axzo.workflow.core.repository.mapper.ExtAxProcessLogMapper; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; +import static cn.axzo.workflow.common.constant.BpmnConstants.ROBOT_ASSIGNEE_ID; + +/** + * Api Log 表操服务实现 + * + * @author wangli + * @since 2024/4/3 10:41 + */ +@Service +@Slf4j +public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService { + @Resource + private ExtAxProcessLogMapper extAxProcessLogMapper; + + @Override + public Long insert(ExtAxProcessLog log) { + extAxProcessLogMapper.insert(log); + return log.getId(); + } + + @Override + public void delete(ExtAxProcessLog deleteLog) { + extAxProcessLogMapper.delete(buildQueryWrapper(deleteLog)); + } + + @Override + public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee) { + updateAssignee(queryLog, assignee, assignee.getAssignerName()); + } + + @Override + public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, String operationDesc) { + List filterAssignee = Lists.newArrayList(NO_ASSIGNEE, HIDDEN_ASSIGNEE_ID, ROBOT_ASSIGNEE_ID, + DUMMY_ASSIGNEE_ID); + if (Objects.isNull(assignee) || filterAssignee.contains(assignee.buildAssigneeId())) { + return; + } + ExtAxProcessLog update = new ExtAxProcessLog(); + update.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : assignee.getAssignerName()); + update.setAssigneeFull(assignee); + update.setAssigneeId(Long.valueOf(assignee.getPersonId())); + update.setAssigneeTenantId(assignee.getTenantId()); + update.setAssigneeOuId(assignee.getOuId()); + update.setAssigneeName(assignee.getAssignerName()); + extAxProcessLogMapper.update(update, buildQueryWrapper(queryLog)); + } + + LambdaQueryWrapper buildQueryWrapper(ExtAxProcessLog log) { + return new LambdaQueryWrapper() + .eq(Objects.nonNull(log.getId()), ExtAxProcessLog::getId, log.getId()) + .eq(StringUtils.hasText(log.getProcessInstanceId()), ExtAxProcessLog::getProcessInstanceId, log.getProcessInstanceId()) + .eq(StringUtils.hasText(log.getActivityId()), ExtAxProcessLog::getActivityId, log.getActivityId()) + .eq(StringUtils.hasText(log.getActivityName()), ExtAxProcessLog::getActivityName, log.getActivityName()) + .eq(StringUtils.hasText(log.getTaskId()), ExtAxProcessLog::getTaskId, log.getTaskId()) + .eq(StringUtils.hasText(log.getTenantId()), ExtAxProcessLog::getTenantId, log.getTenantId()); + } +} diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index 19f94326e..28639e798 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -2,22 +2,28 @@ create table `workflow-engine`.ext_ax_process_log ( id bigint auto_increment comment '主键' primary key, - process_instance_id varchar(64) default '' not null comment '流程实例 ID', - activity_id varchar(64) default '' not null comment '节点 ID', - activity_name varchar(255) default '' not null comment '节点名称', - approval_method varchar(32) default '' not null comment '审批方式:配置审批人/业务指定/业务触发(不含人)', - node_type varchar(32) default '' not null comment '节点类型:审批节点/业务节点/评论节点/抄送节点', - node_mode varchar(32) default '' not null comment '节点模式:会签/或签', - task_id varchar(64) default '' not null comment '任务 ID', - advice varchar(4000) default '' not null comment '操作建议', - operation_desc varchar(4000) default '' not null comment '操作描述', - assignee varchar(1024) default '' not null comment '审批人', - start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', - end_time datetime(3) null comment '任务结束时间', - returned tinyint(1) default 0 not null comment '已回退', - status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', - create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', - update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete bigint default 0 not null comment '是否删除' + process_instance_id varchar(64) default '' not null comment '流程实例 ID', + tenant_id bigint not null comment '实例归属租户', + activity_id varchar(64) default '' not null comment '节点 ID', + activity_name varchar(255) default '' not null comment '节点名称', + approval_method varchar(32) default '' not null comment '审批方式:配置审批人/业务指定/业务触发(不含人)', + node_type varchar(32) default '' not null comment '节点类型:审批节点/业务节点/评论节点/抄送节点', + node_mode varchar(32) default '' not null comment '节点模式:会签/或签', + task_id varchar(64) default '' not null comment '任务 ID', + advice varchar(4000) default '' not null comment '操作建议', + operation_desc varchar(4000) default '' not null comment '操作描述', + assignee_full json null comment '审批人(JSON)', + assignee_id bigint default 0 not null comment '审批人标识(axzo=personId)', + assignee_tenant_id varchar(255) default '' not null comment '审批人归属租户', + assignee_name varchar(255) default '' not null comment '审批人姓名', + assignee_ou_id bigint default 0 not null comment '审批人归属单位', + start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', + end_time datetime(3) null comment '任务结束时间', + returned tinyint(1) default 0 not null comment '已回退标志', + status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', + extra json null comment '扩展字段', + create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', + update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete bigint default 0 not null comment '是否删除' ) comment '审批日志持久化'; From ae173d789bf609db95c6e82dc1de219c9b88ea43 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 3 Sep 2024 16:47:30 +0800 Subject: [PATCH 008/139] =?UTF-8?q?REQ-2924-=E5=A2=9E=E5=8A=A0=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=88=B0=E6=8C=87=E5=AE=9A=E8=8A=82=E7=82=B9=EF=BC=8C?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E8=8A=82=E7=82=B9=E9=80=89=E9=A1=B9=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessTaskApi.java | 17 +++- .../bpmn/task/BpmnOptionalNodeDTO.java | 31 +++++++ .../bpmn/task/BpmnUserTaskNodeDTO.java | 36 ++++++++ .../service/BpmnProcessDefinitionService.java | 11 +++ .../core/service/BpmnProcessTaskService.java | 8 ++ .../BpmnProcessDefinitionServiceImpl.java | 50 +++++++++++ .../impl/BpmnProcessTaskServiceImpl.java | 88 ++++++++++++++++++- .../web/bpmn/BpmnProcessTaskController.java | 24 ++++- 8 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index d173f1856..204a66d8e 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -1,8 +1,8 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; @@ -13,6 +13,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; @@ -22,7 +23,6 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; -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; @@ -72,7 +72,20 @@ public interface ProcessTaskApi { @PostMapping("/api/process/task/batch/approve") CommonResponse batchApproveTask(@Validated @RequestBody List dtos); + /** + * 获取当前节点可退回节点选项列表 + * @param bpmnUserTaskNodeDTO 参数 + * @return + */ + @Operation(summary = "获取当前节点可退回节点选项列表") + @PostMapping("/api/process/task/back/optional/nodes") + CommonResponse> getApproveOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); + /** + * 回退到指定节点 + * @param dto + * @return + */ @Operation(summary = "回退") @PostMapping("/api/process/task/back") CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java new file mode 100644 index 000000000..665a5b19f --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java @@ -0,0 +1,31 @@ +package cn.axzo.workflow.common.model.request.bpmn.task; + +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 退回到指定节点,可选节点模型 + */ +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class BpmnOptionalNodeDTO { + + private String processInstanceId; + + private String processDefinitionId; + + private String processNodeId; + + private String processNodeName; + + private String processNodeDesc; + + private BpmnFlowNodeType nodeType; + + private Integer ordinal; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java new file mode 100644 index 000000000..9a1e89517 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.common.model.request.bpmn.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; + +@ApiModel("节点信息模型") +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BpmnUserTaskNodeDTO { + + @ApiModelProperty(value = "租户id") + @NotBlank(message = "租户id不能为空") + private String tenantId; + + @ApiModelProperty(value = "流程实例id") + @NotBlank(message = "流程实例id不能为空") + private String processInstanceId; + + @ApiModelProperty(value = "审批任务id") + @NotBlank(message = "审批任务id不能为空") + private String taskId; + + private String processNodeId; + + private String processNodeName; +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessDefinitionService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessDefinitionService.java index 88e3a7648..e67398dcc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessDefinitionService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessDefinitionService.java @@ -4,6 +4,9 @@ import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefiniti import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowNode; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; @@ -82,4 +85,12 @@ public interface BpmnProcessDefinitionService { List getProcessDefinitionListByDeploymentIds(Set deploymentIds); void delete(String deploymentId, Boolean cascade); + + List findEndFlowElement(String processDefinitionId); + + List findFlowNodes(String processDefinitionId); + + List findFlowElements(String processDefinitionId); + + List findFlowElementsByIds(String processDefinitionId, List flowElementIds); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java index 28482b76c..f78bff7bc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.service; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; @@ -53,6 +54,13 @@ public interface BpmnProcessTaskService { */ BatchOperationResultVO batchApproveTask(List taskAuditDTOS); + /** + * 退回到指定节点,可以退回节点选项 + * @param processInstanceId 流程实例id + * @param taskId 任务id + */ + List getApproveOptionalNodes(String processInstanceId, String taskId, String tenantId); + /** * 驳回 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessDefinitionServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessDefinitionServiceImpl.java index 55956d45c..e2df82aa3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessDefinitionServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessDefinitionServiceImpl.java @@ -14,6 +14,9 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowNode; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; @@ -27,6 +30,7 @@ import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; @@ -282,4 +286,50 @@ public class BpmnProcessDefinitionServiceImpl implements BpmnProcessDefinitionSe } return repositoryService.createDeploymentQuery().deploymentId(id).singleResult(); } + + @Override + public List findEndFlowElement(String processDefinitionId) { + return getNodesByType(processDefinitionId, EndEvent.class); + } + + @Override + public List findFlowNodes(String processDefinitionId) { + return getNodesByType(processDefinitionId, FlowNode.class); + } + + @Override + public List findFlowElements(String processDefinitionId) { + return getNodesByType(processDefinitionId, FlowElement.class); + } + + @Override + public List findFlowElementsByIds(String processDefinitionId, List flowElementIds) { + if (CollectionUtils.isEmpty(flowElementIds)) { + return emptyList(); + } + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(processDefinitionId) + .singleResult(); + if (processDefinition == null) { + return emptyList(); + } + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + return flowElementIds.stream().map(bpmnModel::getFlowElement).collect(Collectors.toList()); + } + + private List getNodesByType(String processDefinitionId, Class clazz) { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(processDefinitionId) + .singleResult(); + if (processDefinition == null) { + return emptyList(); + } + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + Collection flowNodes = bpmnModel.getMainProcess().findFlowElementsOfType(clazz); + if (CollectionUtils.isEmpty(flowNodes)) { + return emptyList(); + } + return new ArrayList<>(flowNodes); + } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 99b5b0c50..2e52fb165 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.core.service.impl; import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; @@ -40,6 +42,7 @@ import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder; import cn.axzo.workflow.core.engine.event.MessagePushEventImpl; import cn.axzo.workflow.core.engine.event.MessagePushEventType; import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; +import cn.axzo.workflow.core.service.BpmnProcessDefinitionService; import cn.axzo.workflow.core.service.BpmnProcessTaskService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter; @@ -50,7 +53,13 @@ import cn.axzo.workflow.core.service.converter.BpmnTaskTodoPageItemConverter; import cn.hutool.core.collection.CollUtil; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.flowable.bpmn.model.BaseElement; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.ServiceTask; +import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandExecutor; @@ -59,6 +68,7 @@ import org.flowable.engine.ManagementService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; @@ -82,7 +92,6 @@ import org.flowable.variable.service.impl.persistence.entity.HistoricVariableIns import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import javax.annotation.Resource; @@ -96,6 +105,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -108,7 +118,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELAT import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CARBON_COPY; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; @@ -153,6 +167,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Resource @Lazy private BpmnProcessTaskService bpmnProcessTaskService; + @Resource + private BpmnProcessDefinitionService bpmnProcessModelService; @Override public BpmPageResult getTodoTaskPage(BpmnTaskPageSearchDTO dto) { @@ -323,6 +339,76 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } } + @Override + public List getApproveOptionalNodes(String processInstanceId, String taskId, String tenantId) { + Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + //1.获取当前的流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + if (processInstance == null) { + //流程为空,已经结束,返回空 + return Collections.emptyList(); + } + List hisList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + List activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId); + if (CollectionUtils.isEmpty(activeActivityIds)) { + return Collections.emptyList(); + } + List flowElements = bpmnProcessModelService.findFlowElements(task.getProcessDefinitionId()); + if (CollectionUtils.isEmpty(flowElements)) { + return Collections.emptyList(); + } + //考虑会签 + Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); + List executePath = new ArrayList<>(); + for (HistoricActivityInstance his : hisList) { + FlowElement flowElement = flowElementMap.get(his.getActivityId()); + if (flowElement != null) { + FlowElement previousNode = CollectionUtils.isEmpty(executePath) ? null : executePath.get(executePath.size() - 1); + //上一级直接连接,不是同一个节点,表示跳转过去的, + if (previousNode != null && !his.getActivityId().equals(previousNode.getId()) && (previousNode instanceof UserTask || previousNode instanceof ServiceTask) && !(flowElement instanceof SequenceFlow)) { + int i = executePath.size() - 1; + for (; i >= 0; i--) { + if (executePath.get(i).getId().equals(flowElement.getId())) { + break; + } + } + //去掉跳过的路径 + executePath = executePath.subList(0, i); + } + if (previousNode == null || !previousNode.getId().equals(his.getActivityId())) { + executePath.add(flowElement); + } + } + } + AtomicInteger index = new AtomicInteger(0); + List resultList = executePath.stream() + .filter(flowElement -> !activeActivityIds.contains(flowElement.getId())) //排除当前节点 + .filter(flowElement -> { + BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); + return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; + }) + .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) + .map(flowElement -> BpmnOptionalNodeDTO + .builder() + .processInstanceId(task.getProcessInstanceId()) + .processDefinitionId(task.getProcessDefinitionId()) + .processNodeId(flowElement.getId()) + .processNodeName(flowElement.getName()) + .processNodeDesc(flowElement.getName()) + .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) + .ordinal(index.incrementAndGet()) + .build()) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultList)) { + BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); + bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessNodeId() + "(上一级)"); + } + return resultList; + } + return Collections.emptyList(); + } + @Override public BatchOperationResultVO batchApproveTask(List dtos) { return batchOperation(dtos, bpmnProcessTaskService::approveTask); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 85b71c29a..f9468e6e1 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.server.controller.web.bpmn; import cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi; import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; @@ -13,6 +14,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; @@ -119,6 +121,20 @@ public class BpmnProcessTaskController implements ProcessTaskApi { return success(bpmnProcessTaskService.batchApproveTask(dtos)); } + /** + * 获取当前节点可退回节点选项列表 + * @param dto 参数 + * @return + */ + @Operation(summary = "获取当前节点可退回节点选项列表") + @PostMapping("/api/process/task/back/optional/nodes") + @Override + @RepeatSubmit + public CommonResponse> getApproveOptionalNodes(@RequestBody @Validated BpmnUserTaskNodeDTO dto) { + List approveOptionalNodes = bpmnProcessTaskService.getApproveOptionalNodes(dto.getProcessInstanceId(), dto.getTaskId(), dto.getTenantId()); + return success(approveOptionalNodes); + } + /** * 回退 */ @@ -132,10 +148,12 @@ public class BpmnProcessTaskController implements ProcessTaskApi { } /** - * 驳回 + * 回退到指定节点 + * @param dto + * @return */ - @Operation(summary = "驳回任务") - @PostMapping("/reject") + @Operation(summary = "回退") + @PostMapping("/api/process/task/back") @Override @RepeatSubmit public CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto) { From 19e75f3a65ff1cfa470a0edd29f0a33440d5191b Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 3 Sep 2024 17:17:20 +0800 Subject: [PATCH 009/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpmn/task/BpmnUserTaskNodeDTO.java | 4 - .../common/code/BpmnInstanceRespCode.java | 1 + .../impl/BpmnProcessTaskServiceImpl.java | 122 +++++++++--------- .../web/bpmn/BpmnProcessTaskController.java | 4 +- 4 files changed, 65 insertions(+), 66 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java index 9a1e89517..c1a228742 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java @@ -29,8 +29,4 @@ public class BpmnUserTaskNodeDTO { @ApiModelProperty(value = "审批任务id") @NotBlank(message = "审批任务id不能为空") private String taskId; - - private String processNodeId; - - private String processNodeName; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnInstanceRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnInstanceRespCode.java index 281569769..e1e8d2bbe 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnInstanceRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnInstanceRespCode.java @@ -27,6 +27,7 @@ public enum BpmnInstanceRespCode implements IModuleRespCode { TASK_CANT_COMMENT_INSTANCE_NOT_EXISTS("012", "流程实例【{}】不存在, 不能评论"), RUNNING_INSTANCE_ONLY_FORECAST("013", "仅运行中的实例可以推测"), ENGINE_EXEC_EXCEPTION("014", "引擎内部异常"), + PROCESS_TASK_NOT_EXISTS("015", "流程任务不存在或已处理"), ; private final String code; private final String message; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 2e52fb165..425f04fb8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -128,6 +128,8 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; +import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; +import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_TASK_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.FIND_TASK_BY_PERSON_ID_ERROR; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS; import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet; @@ -342,71 +344,71 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Override public List getApproveOptionalNodes(String processInstanceId, String taskId, String tenantId) { Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(taskId).singleResult(); - if (task != null) { - //1.获取当前的流程实例 - ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); - if (processInstance == null) { - //流程为空,已经结束,返回空 - return Collections.emptyList(); - } - List hisList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); - List activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId); - if (CollectionUtils.isEmpty(activeActivityIds)) { - return Collections.emptyList(); - } - List flowElements = bpmnProcessModelService.findFlowElements(task.getProcessDefinitionId()); - if (CollectionUtils.isEmpty(flowElements)) { - return Collections.emptyList(); - } - //考虑会签 - Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); - List executePath = new ArrayList<>(); - for (HistoricActivityInstance his : hisList) { - FlowElement flowElement = flowElementMap.get(his.getActivityId()); - if (flowElement != null) { - FlowElement previousNode = CollectionUtils.isEmpty(executePath) ? null : executePath.get(executePath.size() - 1); - //上一级直接连接,不是同一个节点,表示跳转过去的, - if (previousNode != null && !his.getActivityId().equals(previousNode.getId()) && (previousNode instanceof UserTask || previousNode instanceof ServiceTask) && !(flowElement instanceof SequenceFlow)) { - int i = executePath.size() - 1; - for (; i >= 0; i--) { - if (executePath.get(i).getId().equals(flowElement.getId())) { - break; - } + if (task == null) { + throw new WorkflowEngineException(PROCESS_TASK_NOT_EXISTS); + } + //1.获取当前的流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + if (processInstance == null) { + //流程为空,已经结束,返回空 + throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); + } + List hisList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + List activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId); + if (CollectionUtils.isEmpty(activeActivityIds)) { + return Collections.emptyList(); + } + List flowElements = bpmnProcessModelService.findFlowElements(task.getProcessDefinitionId()); + if (CollectionUtils.isEmpty(flowElements)) { + return Collections.emptyList(); + } + //考虑会签 + Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); + List executePath = new ArrayList<>(); + for (HistoricActivityInstance his : hisList) { + FlowElement flowElement = flowElementMap.get(his.getActivityId()); + if (flowElement != null) { + FlowElement previousNode = CollectionUtils.isEmpty(executePath) ? null : executePath.get(executePath.size() - 1); + //上一级直接连接,不是同一个节点,表示跳转过去的, + if (previousNode != null && !his.getActivityId().equals(previousNode.getId()) && (previousNode instanceof UserTask || previousNode instanceof ServiceTask) && !(flowElement instanceof SequenceFlow)) { + int i = executePath.size() - 1; + for (; i >= 0; i--) { + if (executePath.get(i).getId().equals(flowElement.getId())) { + break; } - //去掉跳过的路径 - executePath = executePath.subList(0, i); - } - if (previousNode == null || !previousNode.getId().equals(his.getActivityId())) { - executePath.add(flowElement); } + //去掉跳过的路径 + executePath = executePath.subList(0, i); + } + if (previousNode == null || !previousNode.getId().equals(his.getActivityId())) { + executePath.add(flowElement); } } - AtomicInteger index = new AtomicInteger(0); - List resultList = executePath.stream() - .filter(flowElement -> !activeActivityIds.contains(flowElement.getId())) //排除当前节点 - .filter(flowElement -> { - BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); - return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; - }) - .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) - .map(flowElement -> BpmnOptionalNodeDTO - .builder() - .processInstanceId(task.getProcessInstanceId()) - .processDefinitionId(task.getProcessDefinitionId()) - .processNodeId(flowElement.getId()) - .processNodeName(flowElement.getName()) - .processNodeDesc(flowElement.getName()) - .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) - .ordinal(index.incrementAndGet()) - .build()) - .collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(resultList)) { - BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); - bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessNodeId() + "(上一级)"); - } - return resultList; } - return Collections.emptyList(); + AtomicInteger index = new AtomicInteger(0); + List resultList = executePath.stream() + .filter(flowElement -> !activeActivityIds.contains(flowElement.getId())) //排除当前节点 + .filter(flowElement -> { + BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); + return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; + }) + .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) + .map(flowElement -> BpmnOptionalNodeDTO + .builder() + .processInstanceId(task.getProcessInstanceId()) + .processDefinitionId(task.getProcessDefinitionId()) + .processNodeId(flowElement.getId()) + .processNodeName(flowElement.getName()) + .processNodeDesc(flowElement.getName()) + .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) + .ordinal(index.incrementAndGet()) + .build()) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(resultList)) { + BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); + bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessNodeId() + "(上一级)"); + } + return resultList; } @Override diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index f9468e6e1..6c68abdae 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -124,10 +124,10 @@ public class BpmnProcessTaskController implements ProcessTaskApi { /** * 获取当前节点可退回节点选项列表 * @param dto 参数 - * @return + * @return 可选退回节点列表 */ @Operation(summary = "获取当前节点可退回节点选项列表") - @PostMapping("/api/process/task/back/optional/nodes") + @PostMapping("/back/optional/nodes") @Override @RepeatSubmit public CommonResponse> getApproveOptionalNodes(@RequestBody @Validated BpmnUserTaskNodeDTO dto) { From 4a48c9a5e22f314ef23480466b0121d7c6caa589 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 3 Sep 2024 18:53:26 +0800 Subject: [PATCH 010/139] =?UTF-8?q?REQ-2924-=E5=9B=9E=E9=80=80=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=94=AF=E6=8C=81=E5=BC=82=E6=AD=A5=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/BpmnProcessInstanceResultEnum.java | 1 + .../bpmn/task/BpmnTaskBackAuditDTO.java | 6 +- .../engine/cmd/CustomApproveTaskAsyncCmd.java | 2 + .../engine/cmd/CustomBackTaskAsyncCmd.java | 83 +++++++++++++++++++ .../core/engine/cmd/CustomBackTaskCmd.java | 28 +++---- .../engine/job/AsyncBackTaskJobHandler.java | 50 +++++++++++ .../impl/BpmnProcessTaskServiceImpl.java | 7 +- 7 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java index 81ba92e01..150ecbc35 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java @@ -6,6 +6,7 @@ public enum BpmnProcessInstanceResultEnum { PROCESSING("PROCESSING", "审批中"), APPROVED("APPROVED", "已通过"), REJECTED("REJECTED", "已驳回"), + BACKED("BACKED", "已回退"), CANCELLED("CANCELLED", "已撤回"), ABORTED("ABORTED", "已中止"), TRANSFER("TRANSFER", "已转交"), diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java index a7a9611f9..f618fcd4f 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java @@ -3,7 +3,6 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -11,6 +10,7 @@ import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; +import java.io.Serializable; @EqualsAndHashCode(callSuper = true) @ApiModel("回退到指定节点入参模型") @@ -18,7 +18,9 @@ import javax.validation.constraints.NotEmpty; @Validated @AllArgsConstructor @NoArgsConstructor -public class BpmnTaskBackAuditDTO extends BpmnTaskAuditDTO { +public class BpmnTaskBackAuditDTO extends BpmnTaskAuditDTO implements Serializable { + + private static final long serialVersionUID = 2226704888158991717L; @ApiModelProperty(value = "当前流程节点id", required = true) @NotBlank(message = "当前流程节点id不能为空") diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java index f7bccb3ab..c89d20c74 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskAsyncCmd.java @@ -29,8 +29,10 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * @since 2024/1/4 15:50 */ public class CustomApproveTaskAsyncCmd extends AbstractCommand implements Serializable { + private static final long serialVersionUID = -4706627700694867170L; private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskAsyncCmd.class); + private final BpmnTaskAuditDTO dto; public CustomApproveTaskAsyncCmd(BpmnTaskAuditDTO dto) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java new file mode 100644 index 000000000..0dbfda785 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java @@ -0,0 +1,83 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncBackTaskJobHandler; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.TaskService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobService; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.Objects; + +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; + +public class CustomBackTaskAsyncCmd extends AbstractCommand implements Serializable { + + private static final long serialVersionUID = 1773108485033787095L; + + private static final Logger log = LoggerFactory.getLogger(CustomBackTaskAsyncCmd.class); + + private final BpmnTaskBackAuditDTO dto; + + public CustomBackTaskAsyncCmd(BpmnTaskBackAuditDTO dto) { + this.dto = dto; + } + + @Override + public String executeInternal(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + HistoricTaskInstanceQuery taskQuery = + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + TaskService taskService = processEngineConfiguration.getTaskService(); + + HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); + + Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); + if (Objects.isNull(task)) { + log.info("任务不存在: {}", dto.getTaskId()); + } + validTask(historicTaskInstance, (TaskEntity) task, dto.getApprover(), null); + + return startAsync(processEngineConfiguration, task); + } + + private String startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) { + JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService(); + + JobEntity job = jobService.createJob(); + // 这里的 executionId 可为 null + job.setExecutionId(task.getExecutionId()); + job.setProcessInstanceId(task.getProcessInstanceId()); + job.setProcessDefinitionId(task.getProcessDefinitionId()); + job.setElementId(task.getTaskDefinitionKey()); + job.setElementName(task.getName()); + job.setJobHandlerType(AsyncBackTaskJobHandler.TYPE); + job.setTenantId(task.getTenantId()); + + // 携带自定义的数据 + job.setCustomValues(JSONUtil.toJsonStr(dto)); + + // 创建异步任务并调度 + jobService.createAsyncJob(job, false); + jobService.scheduleAsyncJob(job); + return job.getId(); + } + + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index b3db09fcd..4613b9177 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -28,9 +28,8 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; -import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; -import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; @@ -39,7 +38,10 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask * 回退命令 */ public class CustomBackTaskCmd extends AbstractCommand implements Serializable { + private static final long serialVersionUID = -1241290344311892346L; + private static final Logger log = LoggerFactory.getLogger(CustomBackTaskCmd.class); + private final String taskId; /** * advice 统一均为审批节点的审批意见,一般为用户在同意、驳回时填写的内容 @@ -57,19 +59,15 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ */ private final List attachmentList; private final BpmnTaskDelegateAssigner approver; - /** - * 下级节点的审批,可为空 - */ - private final BpmnTaskDelegateAssigner nextApprover; /** * 指定节点类型 */ - private List nodeTypes; + private final List nodeTypes; - private String currentActivityId; + private final String currentActivityId; - private String toActivityId; + private final String toActivityId; @Override public String paramToJsonString() { @@ -79,7 +77,6 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ params.put("operationDesc", operationDesc); params.put("attachmentList", JSON.toJSONString(attachmentList)); params.put("approver", JSON.toJSONString(approver)); - params.put("nextApprover", JSON.toJSONString(nextApprover)); params.put("nodeTypes", JSON.toJSONString(nodeTypes)); return JSON.toJSONString(params); } @@ -96,7 +93,6 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ this.advice = dto.getAdvice(); this.attachmentList = dto.getAttachmentList(); this.approver = dto.getApprover(); - this.nextApprover = dto.getNextApprover(); this.nodeTypes = dto.getNodeTypes(); // 这里的不能直接使用字符串的比较,因为外部可能传入空字符串,比如发起人的通过时,就是传入的空字符串 if (Objects.nonNull(operationDesc)) { @@ -133,16 +129,12 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ Authentication.setAuthenticatedUserId(null); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - if (Objects.nonNull(nextApprover)) { - // 主动设置下级审批人 - runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER, - nextApprover); - } - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, BACKED.getStatus()); runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId),toActivityId).changeState(); + .moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId), toActivityId) + .changeState(); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java new file mode 100644 index 000000000..bfec5ab1a --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java @@ -0,0 +1,50 @@ +package cn.axzo.workflow.core.engine.job; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.core.engine.cmd.CustomBackTaskCmd; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobHandler; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; +import org.flowable.variable.api.delegate.VariableScope; + +import java.util.Objects; + +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; + +@Slf4j +public class AsyncBackTaskJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { + + public static final String TYPE = "async-back-task"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + log.info("AsyncBackTaskJobHandler executing..."); + log(job); + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + BpmnTaskBackAuditDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnTaskBackAuditDTO.class); + Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(dto.getTaskId()).singleResult(); + if (Objects.isNull(task)) { + return; + } + CustomBackTaskCmd command; + if (Objects.equals(task.getTaskDefinitionKey(), NODE_STARTER.getType())) { + // 这里的 operationDesc 设置为“” 是为了在日志中不显示(已通过) + command = new CustomBackTaskCmd(dto, ""); + } else { + command = new CustomBackTaskCmd(dto); + } + processEngineConfiguration.getCommandExecutor().execute(command); + } + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 425f04fb8..283cdce74 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -28,6 +28,7 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskAsyncCmd; import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd; +import cn.axzo.workflow.core.engine.cmd.CustomBackTaskAsyncCmd; import cn.axzo.workflow.core.engine.cmd.CustomBackTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomCommentTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomCompleteDummyTaskCmd; @@ -323,7 +324,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Transactional(rollbackFor = Exception.class) public void approveTask(BpmnTaskAuditDTO dto) { CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); - if (dto.getAsync()) { + if (Boolean.TRUE.equals(dto.getAsync())) { commandExecutor.execute(new CustomApproveTaskAsyncCmd(dto)); } else { commandExecutor.execute(new CustomApproveTaskCmd(dto)); @@ -334,8 +335,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Transactional(rollbackFor = Exception.class) public void backTask(BpmnTaskBackAuditDTO dto) { CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); - if (dto.getAsync()) { - commandExecutor.execute(new CustomApproveTaskAsyncCmd(dto)); + if (Boolean.TRUE.equals(dto.getAsync())) { + commandExecutor.execute(new CustomBackTaskAsyncCmd(dto)); } else { commandExecutor.execute(new CustomBackTaskCmd(dto)); } From 10701800b53e548165260b0fc1455e6b836ea516 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 4 Sep 2024 12:52:03 +0800 Subject: [PATCH 011/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=BC=95=E6=93=8E=E8=BF=87=E6=97=B6=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ernalExtAxTaskInstEvent_lo_1_Listener.java | 93 ------------------- 1 file changed, 93 deletions(-) delete mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java deleted file mode 100644 index 602ba4841..000000000 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalExtAxTaskInstEvent_lo_1_Listener.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.axzo.workflow.core.listener.impl; - -import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; -import cn.axzo.workflow.core.common.context.TaskOperationContext; -import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; -import cn.axzo.workflow.core.listener.BpmnTaskEventListener; -import cn.axzo.workflow.core.service.ExtAxProcessLogService; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.RuntimeService; -import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; -import org.flowable.task.service.delegate.DelegateTask; - -import java.util.Objects; - -import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; -import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; -import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; -import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; - -/** - * Core 包内置的,可共用与 Jar 包集成和微服务集成 - *

- * 该类主要处理新版的日志表 - * - * @author wangli - * @since 2023/12/9 22:56 - */ -@Slf4j -//@Component -//@Scope("prototype") -@AllArgsConstructor -public class InternalExtAxTaskInstEvent_lo_1_Listener extends AbstractBpmnEventListener implements BpmnTaskEventListener { - private final RuntimeService runtimeService; - private final RepositoryService repositoryService; - private final ExtAxProcessLogService processLogService; - - @Override - public int getOrder() { - return Integer.MIN_VALUE + 1; - } - - /** - * Assigned 事件先于 Create 事件,所以在此事件中, 只要任务逻辑上应该有人,那么这里的数据就有人, 仅创建日志的初始状态 - * - * @param delegateTask - */ - @Override - public void onCreated(DelegateTask delegateTask) { - BpmnTaskDelegateAssigner assignee; - // 记录发起人 - boolean isNodeStarter = Objects.equals(delegateTask.getTaskDefinitionKey(), NODE_STARTER.getType()); - if (isNodeStarter) { - assignee = getContext().getInitiator(() -> - BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), - INTERNAL_INITIATOR))); - if (Objects.isNull(assignee)) { - // 兼容历史数据 - assignee = getContext().getInitiator(() -> - BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), OLD_INTERNAL_INITIATOR))); - } - } else { - assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(delegateTask.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId())); - } - - BpmnModel bpmnModel = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()); - FlowElement flowElement = bpmnModel.getFlowElement(delegateTask.getTaskDefinitionKey()); - - } - - - private BpmnFlowNodeMode getNodeMode(FlowElement flowElement) { - BpmnFlowNodeMode node = GENERAL; - if (flowElement instanceof UserTask) { - UserTask userTask = (UserTask) flowElement; - if (userTask.getBehavior() instanceof MultiInstanceActivityBehavior) { - MultiInstanceActivityBehavior behavior = - (MultiInstanceActivityBehavior) userTask.getBehavior(); - node = Objects.equals(AND_SIGN_EXPRESSION, behavior.getCompletionCondition()) ? AND : OR; - } - } - return node; - } -} From 8ec054f6be58a930c07e75a5d5248545bd94380c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 4 Sep 2024 16:02:39 +0800 Subject: [PATCH 012/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=96=B0=E7=9A=84=E6=97=A5=E5=BF=97=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/EngineEntityEventListener.java | 28 +++++++++++++------ .../core/service/ExtAxProcessLogService.java | 15 ++++++++++ .../impl/ExtAxProcessLogServiceImpl.java | 9 ++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java index 8326140b1..f76131e69 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java @@ -17,6 +17,7 @@ import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListen import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEvent; +import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; @@ -31,15 +32,16 @@ import java.util.Set; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; -import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.bizSpecify; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; @@ -108,6 +110,18 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { private void onDeleted(TaskEntity taskEntity) { log.error("onDeleted"); + ExtAxProcessLog queryLog = new ExtAxProcessLog(); + queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); + queryLog.setTaskId(taskEntity.getId()); + ExtAxProcessLog update = new ExtAxProcessLog(); + if (Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType())) { + update.setStatus(APPROVED.getStatus()); + } else { + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + HistoryService historyService = processEngineConfiguration.getHistoryService(); + + } + processLogService.update(queryLog, update); } private void onUpdated(TaskEntity taskEntity) { @@ -120,7 +134,8 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { } else { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - List assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(), "[_ACTIVITY_INFO_SNAPSHOT_]" + taskEntity.getTaskDefinitionKey(), List.class); + List assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(), + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class); ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny() .ifPresent(assignee -> { log.error("审批人: {}", JSON.toJSONString(assignee)); @@ -165,16 +180,11 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { log.setActivityId(taskEntity.getTaskDefinitionKey()); log.setActivityName(taskEntity.getName()); log.setApprovalMethod((isNodeStarter ? nobody : getApprovalMethod(flowElement).orElse(nobody)).getType()); - if (Objects.equals(log.getApprovalMethod(), nobody.getType()) || Objects.equals(log.getApprovalMethod(), bizSpecify.getType())) { - log.setOperationDesc("待处理"); - } log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType()); log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType()); log.setTaskId(taskEntity.getId()); + log.setOperationDesc("待处理"); if (Objects.nonNull(assignee)) { - // FIXME 应该还有逻辑来拼接 - log.setOperationDesc(isNodeStarter ? assignee.getAssignerName() : null); - log.setAssigneeFull(assignee); log.setAssigneeId(Long.valueOf(assignee.getPersonId())); log.setAssigneeTenantId(assignee.getTenantId()); @@ -183,6 +193,7 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { } log.setStartTime(taskEntity.getCreateTime()); log.setStatus(PROCESSING.getStatus()); + processLogService.insert(log); } @@ -199,6 +210,7 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { return node; } + @Override public boolean isFailOnException() { return true; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java index 7cee90d03..99b9ef4e8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java @@ -25,6 +25,21 @@ public interface ExtAxProcessLogService { */ void delete(ExtAxProcessLog deleteLog); + /** + * 根据有 ID 的实体直接更新 + * + * @param updateLog + */ + void updateById(ExtAxProcessLog updateLog); + + /** + * 根据条件更新指定对象的列 + * + * @param query + * @param update + */ + void update(ExtAxProcessLog query, ExtAxProcessLog update); + /** * 更新指定任务的审批人 * diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java index 5f491349a..67c30f0e7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java @@ -42,9 +42,18 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService { extAxProcessLogMapper.delete(buildQueryWrapper(deleteLog)); } + public void updateById(ExtAxProcessLog updateLog) { + extAxProcessLogMapper.updateById(updateLog); + } + + public void update(ExtAxProcessLog query, ExtAxProcessLog update) { + extAxProcessLogMapper.update(update, buildQueryWrapper(query)); + } + @Override public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee) { updateAssignee(queryLog, assignee, assignee.getAssignerName()); + } @Override From ebc6bf0441cba5ec5693d45ce748b547a3b0dbbe Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 4 Sep 2024 20:25:06 +0800 Subject: [PATCH 013/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E8=8A=82=E7=82=B9=E6=97=A0=E4=BA=BA=E7=9A=84?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E9=80=BB=E8=BE=91=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/BpmnProcessInstanceResultEnum.java | 2 +- .../enums/BpmnProcessTaskResultEnum.java | 6 +++--- .../CustomReceiveTaskActivityBehavior.java | 12 ++++++++---- .../listener/EngineEntityEventListener.java | 19 ++++++++++++++++--- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java index 150ecbc35..a69939c39 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java @@ -6,7 +6,7 @@ public enum BpmnProcessInstanceResultEnum { PROCESSING("PROCESSING", "审批中"), APPROVED("APPROVED", "已通过"), REJECTED("REJECTED", "已驳回"), - BACKED("BACKED", "已回退"), + BACKED("BACKED", "已退回"), CANCELLED("CANCELLED", "已撤回"), ABORTED("ABORTED", "已中止"), TRANSFER("TRANSFER", "已转交"), diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/enums/BpmnProcessTaskResultEnum.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/enums/BpmnProcessTaskResultEnum.java index 3b6532d74..23eadcd0f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/enums/BpmnProcessTaskResultEnum.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/enums/BpmnProcessTaskResultEnum.java @@ -9,7 +9,8 @@ import java.util.Arrays; * @since 2023/9/18 17:11 */ public enum BpmnProcessTaskResultEnum { - + PENDING("PENDING", "待处理"), + PROCESSED("PROCESSED", "已处理"), AUTO_SKIP("AUTO_SKIP", "任务自动跳过"), // 引擎默认的标识,不允许修改 MI_END("MI_END", "多实例任务运行结束"), @@ -17,8 +18,7 @@ public enum BpmnProcessTaskResultEnum { DELETE_MI_EXECUTION("Delete MI execution", "多实例任务被删除"), INITIATOR_REVOCATION("INITIATOR_REVOCATION", "发起者主动撤回"), REJECTION_AUTO_COMPLETED("REJECTION_AUTO_COMPLETED", "审批驳回自动结束"), - BACKED("BACKED", "退回"); - + ; private final String status; /** * 描述 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java index 7661176b9..5c0db9d78 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java @@ -7,18 +7,17 @@ import org.flowable.bpmn.model.ReceiveTask; import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.delegate.DelegateExecution; -import org.flowable.engine.delegate.TaskListener; import org.flowable.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.persistence.entity.ExecutionEntity; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.TaskHelper; -import org.flowable.task.api.Task; import org.flowable.task.service.TaskService; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; @@ -51,7 +50,6 @@ public class CustomReceiveTaskActivityBehavior extends ReceiveTaskActivityBehavi task.setName(receiveTask.getName()); TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false); - processEngineConfiguration.getListenerNotificationHelper().executeTaskListeners(task, TaskListener.EVENTNAME_CREATE); // 添加 taskInst 扩展表数据 FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); @@ -68,12 +66,18 @@ public class CustomReceiveTaskActivityBehavior extends ReceiveTaskActivityBehavi FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); org.flowable.engine.TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = taskService.createTaskQuery().executionId(execution.getId()) + TaskEntity task = (TaskEntity) taskService.createTaskQuery().executionId(execution.getId()) .taskDefinitionKey(execution.getCurrentActivityId()).singleResult(); if (Objects.nonNull(task)) { + // 用于新版日志 + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), APPROVED.getStatus()); + eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), receiveTask.getId(), task.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); +// // 新版日志使用 +// eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_DELETED, task), +// processEngineConfiguration.getEngineCfgKey()); } else { log.warn("task is null, executionId: {}, activityId: {}", execution.getId(), execution.getCurrentActivityId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java index f76131e69..44673e646 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.listener; import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.ExtAxProcessLogService; @@ -17,25 +18,29 @@ import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListen import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEvent; -import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.cmd.GetTaskCommentsByTypeCmd; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.task.Comment; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Component; +import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Set; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; @@ -43,6 +48,7 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; +import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.PENDING; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_ACTIVATED; @@ -118,8 +124,15 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { update.setStatus(APPROVED.getStatus()); } else { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); - HistoryService historyService = processEngineConfiguration.getHistoryService(); + List comments = processEngineConfiguration.getCommandExecutor() + .execute(new GetTaskCommentsByTypeCmd(taskEntity.getId(), COMMENT_TYPE_OPERATION_DESC)); + comments.stream().max(Comparator.comparing(Comment::getTime)).ifPresent(e -> update.setOperationDesc(e.getFullMessage())); + String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); + log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); + update.setStatus(completionType); + queryLog.setOperationDesc(PENDING.getDesc()); + update.setOperationDesc(BpmnProcessInstanceResultEnum.valueOfStatus(completionType).getDesc()); } processLogService.update(queryLog, update); } @@ -183,7 +196,7 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType()); log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType()); log.setTaskId(taskEntity.getId()); - log.setOperationDesc("待处理"); + log.setOperationDesc(PENDING.getDesc()); if (Objects.nonNull(assignee)) { log.setAssigneeFull(assignee); log.setAssigneeId(Long.valueOf(assignee.getPersonId())); From 1dfa3642826c89a296c26e2ed8c21317c77e066d Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 5 Sep 2024 11:53:59 +0800 Subject: [PATCH 014/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=88=B0=E6=8C=87=E5=AE=9A=E8=8A=82=E7=82=B9=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessTaskApi.java | 2 +- .../bpmn/task/BpmnTaskBackAuditDTO.java | 9 +- .../core/engine/cmd/CustomBackTaskCmd.java | 78 +++++------------ .../web/bpmn/BpmnProcessTaskController.java | 4 +- .../starter/api/WorkflowCoreService.java | 86 +++++++++---------- 5 files changed, 68 insertions(+), 111 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 204a66d8e..214ab75a8 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -79,7 +79,7 @@ public interface ProcessTaskApi { */ @Operation(summary = "获取当前节点可退回节点选项列表") @PostMapping("/api/process/task/back/optional/nodes") - CommonResponse> getApproveOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); + CommonResponse> getBackOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); /** * 回退到指定节点 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java index f618fcd4f..b4a2aed67 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskBackAuditDTO.java @@ -9,7 +9,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; import java.io.Serializable; @EqualsAndHashCode(callSuper = true) @@ -20,13 +19,9 @@ import java.io.Serializable; @NoArgsConstructor public class BpmnTaskBackAuditDTO extends BpmnTaskAuditDTO implements Serializable { - private static final long serialVersionUID = 2226704888158991717L; - - @ApiModelProperty(value = "当前流程节点id", required = true) - @NotBlank(message = "当前流程节点id不能为空") - private String currentActivityId; + private static final long serialVersionUID = -4160538355403179298L; @ApiModelProperty(value = "目标流程节点id", required = true) - @NotEmpty(message = "目标流程节点id不能为空") + @NotBlank(message = "目标流程节点id不能为空") private String toActivityId; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 4613b9177..83e9f806d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -1,10 +1,8 @@ package cn.axzo.workflow.core.engine.cmd; -import cn.axzo.workflow.common.enums.BpmnFlowNodeType; -import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; @@ -15,14 +13,11 @@ import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; @@ -37,71 +32,38 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask /** * 回退命令 */ +@Slf4j public class CustomBackTaskCmd extends AbstractCommand implements Serializable { private static final long serialVersionUID = -1241290344311892346L; - private static final Logger log = LoggerFactory.getLogger(CustomBackTaskCmd.class); + private final BpmnTaskBackAuditDTO dto; - private final String taskId; - /** - * advice 统一均为审批节点的审批意见,一般为用户在同意、驳回时填写的内容 - * 有值时,在日志中一般出现在 operationDesc 的下方 - */ - private final String advice; - /** - * operationDesc 统一为审批节点的动作描述,例如:某某转交、加签某某等 - * 在日志中一般出现在节点名称的下方 - * 不传,默认"已通过" - */ - private String operationDesc; - /** - * 附件, 可为空 - */ - private final List attachmentList; - private final BpmnTaskDelegateAssigner approver; - - /** - * 指定节点类型 - */ - private final List nodeTypes; - - private final String currentActivityId; - - private final String toActivityId; + private final String operationDesc; @Override public String paramToJsonString() { Map params = new HashMap<>(); - params.put("taskId", taskId); - params.put("advice", advice); + params.put("taskId", dto.getTaskId()); + params.put("advice", dto.getAdvice()); params.put("operationDesc", operationDesc); - params.put("attachmentList", JSON.toJSONString(attachmentList)); - params.put("approver", JSON.toJSONString(approver)); - params.put("nodeTypes", JSON.toJSONString(nodeTypes)); + params.put("attachmentList", JSON.toJSONString(dto.getAttachmentList())); + params.put("approver", JSON.toJSONString(dto.getApprover())); + params.put("nodeTypes", JSON.toJSONString(dto.getNodeTypes())); return JSON.toJSONString(params); } public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto) { this(dto, null); - if (Objects.nonNull(dto.getOperationDesc())) { - this.operationDesc = dto.getOperationDesc(); - } } public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto, String operationDesc) { - this.taskId = dto.getTaskId(); - this.advice = dto.getAdvice(); - this.attachmentList = dto.getAttachmentList(); - this.approver = dto.getApprover(); - this.nodeTypes = dto.getNodeTypes(); + this.dto = dto; // 这里的不能直接使用字符串的比较,因为外部可能传入空字符串,比如发起人的通过时,就是传入的空字符串 if (Objects.nonNull(operationDesc)) { this.operationDesc = operationDesc; } else { this.operationDesc = "已回退"; } - this.currentActivityId = dto.getCurrentActivityId(); - this.toActivityId = dto.getToActivityId(); } @Override @@ -112,28 +74,28 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); TaskService taskService = processEngineConfiguration.getTaskService(); - HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); + HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); - Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, approver, nodeTypes); - if (StringUtils.hasLength(advice)) { - Authentication.setAuthenticatedUserId(approver.buildAssigneeId()); - addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice); + Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); + validTask(historicTaskInstance, (TaskEntity) task, dto.getApprover(), dto.getNodeTypes()); + if (StringUtils.hasLength(dto.getAdvice())) { + Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); + addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); Authentication.setAuthenticatedUserId(null); } - batchAddAttachment(commandContext, task.getProcessInstanceId(), taskId, attachmentList, approver); + batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); - Authentication.setAuthenticatedUserId(Objects.nonNull(approver) ? approver.buildAssigneeId() : null); + Authentication.setAuthenticatedUserId(Objects.nonNull(dto.getApprover()) ? dto.getApprover().buildAssigneeId() : null); addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc); Authentication.setAuthenticatedUserId(null); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, BACKED.getStatus()); + ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId), toActivityId) + .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) .changeState(); return null; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 6c68abdae..bcf08eaaf 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -130,7 +130,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @PostMapping("/back/optional/nodes") @Override @RepeatSubmit - public CommonResponse> getApproveOptionalNodes(@RequestBody @Validated BpmnUserTaskNodeDTO dto) { + public CommonResponse> getBackOptionalNodes(@RequestBody @Validated BpmnUserTaskNodeDTO dto) { List approveOptionalNodes = bpmnProcessTaskService.getApproveOptionalNodes(dto.getProcessInstanceId(), dto.getTaskId(), dto.getTenantId()); return success(approveOptionalNodes); } @@ -144,7 +144,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @Override public CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto) { bpmnProcessTaskService.backTask(dto); - return success(); + return success(true); } /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index f7d7aefdf..fd86467fc 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,59 +1,41 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.axzo.workflow.common.util.ThreadUtil; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.azxo.framework.common.model.CommonResponse; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.util.ThreadUtil; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; 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 javax.validation.constraints.NotBlank; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PutMapping; + import javax.annotation.Nullable; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.NotBlank; import java.util.List; import java.util.Map; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import javax.validation.constraints.NotEmpty; + +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; /** * Workflow Engine Starter Core Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 @@ -194,6 +176,24 @@ public interface WorkflowCoreService { @PostMapping("/api/process/task/batch/approve") BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); + /** + * 获取当前节点可退回节点选项列表 + * @param bpmnUserTaskNodeDTO 参数 + * @return + */ + @Operation(summary = "获取当前节点可退回节点选项列表") + @PostMapping("/api/process/task/back/optional/nodes") + List getBackOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); + + /** + * 回退到指定节点 + * @param dto + * @return + */ + @Operation(summary = "回退") + @PostMapping("/api/process/task/back") + Boolean backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); + /** * 驳回 * From 465cbd2791f3513ea8d7b8c8074d2fbce8ab2c80 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 5 Sep 2024 18:47:03 +0800 Subject: [PATCH 015/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E6=B7=BB=E5=8A=A0=20comment=20?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=B8=8D=E8=BF=94=E5=9B=9E=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/helper/CustomTaskHelper.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index b9a134431..d6c8fcd09 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -27,7 +27,6 @@ import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.engine.runtime.Execution; import org.flowable.engine.task.Attachment; -import org.flowable.engine.task.Comment; import org.flowable.engine.task.Event; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; @@ -239,15 +238,18 @@ public class CustomTaskHelper { Authentication.setAuthenticatedUserId(null); } - public static Comment addComment(CommandContext commandContext, String taskId, String processInstanceId, + public static void addComment(CommandContext commandContext, String taskId, String processInstanceId, String type, String message) { TaskEntity task = new TaskEntityImpl(); task.setId(taskId); task.setProcessInstanceId(processInstanceId); - return addComment(commandContext, task, type, message); + addComment(commandContext, task, type, message); } - public static Comment addComment(CommandContext commandContext, Task task, String type, String message) { + public static void addComment(CommandContext commandContext, Task task, String type, String message) { + if (!StringUtils.hasText(message)) { + return; + } ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); @@ -270,7 +272,6 @@ public class CustomTaskHelper { processEngineConfiguration.getCommentEntityManager().insert(comment); - return comment; } public static Attachment addAttachment(CommandContext commandContext, Task task, AttachmentDTO attachmentDto) { From 53a17ed10019c3c00d4e6e4860cdbeb2ee2c9c94 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 6 Sep 2024 00:36:47 +0800 Subject: [PATCH 016/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=BD=AC=E4=BA=A4=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomAbortProcessInstanceCmd.java | 9 +- .../cmd/CustomCancelProcessInstanceCmd.java | 8 +- .../cmd/CustomCountersignUserTaskCmd.java | 8 +- .../engine/cmd/CustomRejectionTaskCmd.java | 11 +- .../engine/cmd/helper/CustomTaskHelper.java | 22 ++- .../entity/EngineEntityEventListener.java | 115 +++++++++++++++ .../listener/entity/EntityEventHandle.java | 27 ++++ .../entity/type/CommentEntityEventHandle.java | 82 +++++++++++ .../type/TaskEntityEventHandle.java} | 138 +++++++----------- .../core/engine/model/AddComment.java | 40 +++++ ...ProcessInstanceAdminPageItemConverter.java | 14 +- .../starter/api/WorkflowManageService.java | 88 +++++------ 12 files changed, 398 insertions(+), 164 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EngineEntityEventListener.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EntityEventHandle.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java rename workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/{EngineEntityEventListener.java => entity/type/TaskEntityEventHandle.java} (63%) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/model/AddComment.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java index cb5836728..69faa460c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import com.alibaba.fastjson.JSON; @@ -20,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID; @@ -35,7 +35,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCEL import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_ABORT; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; -import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask; /** @@ -106,9 +106,10 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand impleme // 添加自定义的节点,用于展示最后的操作 Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId, "系统中止", NODE_ABORT.getType(), null, BpmnTaskDelegateAssigner.buildDummyAssigner("system", - TASK_ASSIGNEE_SKIP_FLAT, "系统"), ABORTED.getStatus()); - addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, reason); + TASK_ASSIGNEE_SKIP_FLAT, "系统"), ABORTED.getStatus(), new AddComment(reason)); runtimeService.setVariable(task.getProcessInstanceId(), TASK_COMPLETE_OPERATION_TYPE + task.getId(), ABORTED); + + completeVirtualTask(commandContext, task); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java index e235d8fdd..cb1996e3a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import com.alibaba.fastjson.JSON; @@ -18,7 +19,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID; @@ -32,7 +32,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_CANCEL; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; -import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask; /** @@ -108,8 +108,8 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand implem // 添加自定义的节点,用于展示最后的操作 Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId, - "发起人撤回", NODE_CANCEL.getType(), reason, initiator, CANCELLED.getStatus()); - addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已撤回"); + "发起人撤回", NODE_CANCEL.getType(), reason, initiator, CANCELLED.getStatus(), new AddComment(CANCELLED.getDesc())); + completeVirtualTask(commandContext, task); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java index 7d5f7c2bb..7f190bc6b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; +import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; @@ -23,12 +24,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; -import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount; @@ -155,9 +155,9 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen } message.append("等").append(targetTaskAssigneeList.size()).append("人进行审批"); Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), - task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus()); - addComment(commandContext, virtualTask, COMMENT_TYPE_OPERATION_DESC, message.toString()); + task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString())); batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, originTaskAssignee); + completeVirtualTask(commandContext, virtualTask); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 259d69036..02fc23b46 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import com.alibaba.fastjson.JSON; @@ -23,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID; @@ -32,8 +32,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_DE import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; -import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; @@ -103,11 +103,12 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), REJECTED.getStatus()); Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), - task.getTaskDefinitionKey(), advice, Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus()); - - addComment(commandContext, virtualTask, COMMENT_TYPE_OPERATION_DESC, operationDesc); + task.getTaskDefinitionKey(), advice, + Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus(), + new AddComment(operationDesc)); batchAddAttachment(commandContext, task.getProcessInstanceId(), virtualTask.getId(), attachmentList, approver); + completeVirtualTask(commandContext, virtualTask); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); finishProcessInstance(commandContext, runtimeService, task, advice); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index d6c8fcd09..2c607957c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter; @@ -246,8 +247,11 @@ public class CustomTaskHelper { addComment(commandContext, task, type, message); } + public static void addComment(CommandContext commandContext, Task task, AddComment addComment) { + addComment(commandContext, task, addComment.getCommentType(), addComment.getContent()); + } public static void addComment(CommandContext commandContext, Task task, String type, String message) { - if (!StringUtils.hasText(message)) { + if (!StringUtils.hasText(type) || !StringUtils.hasText(message)) { return; } ProcessEngineConfigurationImpl processEngineConfiguration = @@ -317,7 +321,7 @@ public class CustomTaskHelper { public static Task createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, BpmnTaskDelegateAssigner assigner, - String extTaskInstStatus) { + String extTaskInstStatus, AddComment addComment) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); @@ -352,6 +356,8 @@ public class CustomTaskHelper { // 添加审批意见 addAdvice(commandContext, task, advice, Objects.nonNull(assigner) ? assigner.buildAssigneeId() : null); + // 添加操作描述 + addComment(commandContext, task, addComment); CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, task.getProcessInstanceId(), task.getId(), task.getTaskDefinitionKey(), assigner, extTaskInstStatus); @@ -362,12 +368,20 @@ public class CustomTaskHelper { task.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), assigner.toJson()); } - // 完成临时节点 - taskService.complete(task.getId()); + // 完成临时节点, 1.4.2虚拟节点创建方法不再默认完成,需主动调用 completeVirtualTask 完成 + // taskService.complete(task.getId()); return task; } + public static Task completeVirtualTask(CommandContext commandContext, Task task) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskService taskService = processEngineConfiguration.getTaskService(); + taskService.complete(task.getId()); + return task; + } + private static void addAdvice(CommandContext commandContext, Task task, String comment, String userId) { if (StringUtils.hasLength(comment)) { Authentication.setAuthenticatedUserId(userId); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EngineEntityEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EngineEntityEventListener.java new file mode 100644 index 000000000..7dd04b9e3 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EngineEntityEventListener.java @@ -0,0 +1,115 @@ +package cn.axzo.workflow.core.engine.listener.entity; + +import com.google.common.collect.ImmutableSet; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListener; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEvent; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_ACTIVATED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_CREATED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_DELETED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_INITIALIZED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_SUSPENDED; +import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_UPDATED; + +/** + * TODO + * + * @author wangli + * @since 2024-09-02 15:34 + */ +@Component +@Slf4j +@AllArgsConstructor +public class EngineEntityEventListener extends AbstractFlowableEventListener { + + private final List handles; + public static final Set SUPPORTED = + ImmutableSet.builder() + .add(ENTITY_CREATED) + .add(ENTITY_INITIALIZED) + .add(ENTITY_UPDATED) + .add(ENTITY_DELETED) + .add(ENTITY_SUSPENDED) + .add(ENTITY_ACTIVATED) + .build(); + + @Override + public void onEvent(FlowableEvent event) { + if (event instanceof FlowableEntityEvent && SUPPORTED.contains(event.getType())) { + FlowableEntityEvent entityEvent = (FlowableEntityEvent) event; +// log.warn("entity event type: {}, class: {}",entityEvent.getType(), entityEvent.getEntity().getClass()); + handles.forEach(handle -> { + Object entity = entityEvent.getEntity(); + if (handle.support(entity)) { + Object convert = handle.convert(entity); + if (Objects.equals(event.getType(), ENTITY_CREATED)) { + handle.onCreate(convert); + } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) { + handle.onInitialized(convert); + } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) { + handle.onUpdated(convert); + } else if (Objects.equals(event.getType(), ENTITY_DELETED)) { + handle.onDeleted(convert); + } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) { + handle.onSuspended(convert); + } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) { + handle.onActivated(convert); + } + } + }); +// if (entityEvent.getEntity() instanceof TaskEntity) { +// TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity(); +// log.error("event taskId :{}, taskDefKey: {}", taskEntity.getId(), taskEntity.getTaskDefinitionKey()); +// +// if (Objects.equals(event.getType(), ENTITY_CREATED)) { +// onCreate(taskEntity); +// } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) { +// onInitialized(taskEntity); +// } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) { +// onUpdated(taskEntity); +// } else if (Objects.equals(event.getType(), ENTITY_DELETED)) { +// onDeleted(taskEntity); +// } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) { +// onSuspended(taskEntity); +// } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) { +// onActivated(taskEntity); +// } +// } else if(entityEvent.getEntity() instanceof CommentEntity) { +// CommentEntity commentEntity = (CommentEntity) entityEvent.getEntity(); +// log.error("event taskId :{}", commentEntity.getId()); +// +// if (Objects.equals(event.getType(), ENTITY_CREATED)) { +// onCreate(commentEntity); +// } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) { +// onInitialized(commentEntity); +// } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) { +// onUpdated(commentEntity); +// } else if (Objects.equals(event.getType(), ENTITY_DELETED)) { +// onDeleted(commentEntity); +// } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) { +// onSuspended(commentEntity); +// } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) { +// onActivated(commentEntity); +// } +// } + + } + } + + + + + @Override + public boolean isFailOnException() { + return true; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EntityEventHandle.java new file mode 100644 index 000000000..e3ae053ff --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/EntityEventHandle.java @@ -0,0 +1,27 @@ +package cn.axzo.workflow.core.engine.listener.entity; + +/** + * TODO + * + * @author wangli + * @since 2024-09-06 00:03 + */ +public interface EntityEventHandle { + + boolean support(Object entity); + + T convert(Object entity); + + void onCreate(T entity); + + void onInitialized(T entity); + + void onUpdated(T entity); + + void onDeleted(T entity); + + void onSuspended(T entity); + + void onActivated(T entity); + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java new file mode 100644 index 000000000..d3f416f6a --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java @@ -0,0 +1,82 @@ +package cn.axzo.workflow.core.engine.listener.entity.type; + +import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle; +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.impl.persistence.entity.CommentEntity; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; + +/** + * TODO + * + * @author wangli + * @since 2024-09-06 00:14 + */ +@Slf4j +@Component +@AllArgsConstructor +public class CommentEntityEventHandle implements EntityEventHandle { + private final ExtAxProcessLogService processLogService; + + @Override + public boolean support(Object entity) { + return entity instanceof CommentEntity; + } + + @Override + public CommentEntity convert(Object entity) { + return (CommentEntity) entity; + } + + @Override + public void onCreate(CommentEntity entity) { + log.info("comment event onCreate: {}", entity.getId()); + ExtAxProcessLog queryLog = new ExtAxProcessLog(); + queryLog.setProcessInstanceId(entity.getProcessInstanceId()); + queryLog.setTaskId(entity.getId()); + ExtAxProcessLog update = new ExtAxProcessLog(); + if (Objects.equals(COMMENT_TYPE_ADVICE, entity.getType())) { + update.setAdvice(entity.getFullMessage()); + } else if (Objects.equals(COMMENT_TYPE_OPERATION_DESC, entity.getType())) { + update.setOperationDesc(entity.getFullMessage()); + } + processLogService.update(queryLog, update); + } + + @Override + public void onInitialized(CommentEntity entity) { + log.info("comment event onInitialized: {}", entity.getId()); + + } + + @Override + public void onUpdated(CommentEntity entity) { + log.info("comment event onUpdated: {}", entity.getId()); + + } + + @Override + public void onDeleted(CommentEntity entity) { + log.info("comment event onDeleted: {}", entity.getId()); + + } + + @Override + public void onSuspended(CommentEntity entity) { + log.info("comment event onSuspended: {}", entity.getId()); + + } + + @Override + public void onActivated(CommentEntity entity) { + log.info("comment event onSuspended: {}", entity.getId()); + + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java similarity index 63% rename from workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java rename to workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 44673e646..3514e6614 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineEntityEventListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -1,23 +1,19 @@ -package cn.axzo.workflow.core.engine.listener; +package cn.axzo.workflow.core.engine.listener.entity.type; import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.ExtAxProcessLogService; -import com.google.common.collect.ImmutableSet; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; -import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListener; -import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; -import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; -import org.flowable.common.engine.api.delegate.event.FlowableEvent; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; @@ -31,15 +27,12 @@ import org.springframework.stereotype.Component; import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.Set; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; -import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; -import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; @@ -51,79 +44,60 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.PENDING; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_ACTIVATED; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_CREATED; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_DELETED; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_INITIALIZED; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_SUSPENDED; -import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_UPDATED; /** * TODO * * @author wangli - * @since 2024-09-02 15:34 + * @since 2024-09-06 00:02 */ -@Component @Slf4j +@Component @AllArgsConstructor -public class EngineEntityEventListener extends AbstractFlowableEventListener { - +public class TaskEntityEventHandle implements EntityEventHandle { private final ExtAxProcessLogService processLogService; - public static final Set SUPPORTED = - ImmutableSet.builder() - .add(ENTITY_CREATED) - .add(ENTITY_INITIALIZED) - .add(ENTITY_UPDATED) - .add(ENTITY_DELETED) - .add(ENTITY_SUSPENDED) - .add(ENTITY_ACTIVATED) - .build(); - @Override - public void onEvent(FlowableEvent event) { - if (event instanceof FlowableEntityEvent) { - FlowableEntityEvent entityEvent = (FlowableEntityEvent) event; -// log.warn("entity event type: {}, class: {}",entityEvent.getType(), entityEvent.getEntity().getClass()); - if (entityEvent.getEntity() instanceof TaskEntity) { - TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity(); - log.error("event taskId :{}, taskDefKey: {}", taskEntity.getId(), taskEntity.getTaskDefinitionKey()); - if (Objects.equals(event.getType(), ENTITY_CREATED)) { - onCreate(taskEntity); - } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) { - onInitialized(taskEntity); - } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) { - onUpdated(taskEntity); - } else if (Objects.equals(event.getType(), ENTITY_DELETED)) { - onDeleted(taskEntity); - } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) { - onSuspended(taskEntity); - } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) { - onActivated(taskEntity); - } - } - } + public boolean support(Object entity) { + return entity instanceof TaskEntity; } - private void onActivated(TaskEntity taskEntity) { + @Override + public TaskEntity convert(Object entity) { + return (TaskEntity) entity; + } + + @Override + public void onActivated(TaskEntity taskEntity) { log.error("onActivated"); } - private void onSuspended(TaskEntity taskEntity) { + public void onSuspended(TaskEntity taskEntity) { log.error("onSuspended"); } - private void onDeleted(TaskEntity taskEntity) { + public void onDeleted(TaskEntity taskEntity) { log.error("onDeleted"); ExtAxProcessLog queryLog = new ExtAxProcessLog(); queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); queryLog.setTaskId(taskEntity.getId()); ExtAxProcessLog update = new ExtAxProcessLog(); + + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); +// BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); + BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(taskEntity.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); + if (Objects.nonNull(assignee)) { + update.setAssigneeFull(assignee); + update.setAssigneeId(Long.valueOf(assignee.getPersonId())); + update.setAssigneeTenantId(assignee.getTenantId()); + update.setAssigneeName(assignee.getAssignerName()); + update.setAssigneeOuId(assignee.getOuId()); + } + if (Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType())) { update.setStatus(APPROVED.getStatus()); } else { - ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); List comments = processEngineConfiguration.getCommandExecutor() .execute(new GetTaskCommentsByTypeCmd(taskEntity.getId(), COMMENT_TYPE_OPERATION_DESC)); comments.stream().max(Comparator.comparing(Comment::getTime)).ifPresent(e -> update.setOperationDesc(e.getFullMessage())); @@ -137,7 +111,7 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { processLogService.update(queryLog, update); } - private void onUpdated(TaskEntity taskEntity) { + public void onUpdated(TaskEntity taskEntity) { log.error("onUpdated"); if (Objects.equals(HIDDEN_ASSIGNEE_ID, taskEntity.getAssignee())) { ExtAxProcessLog queryLog = new ExtAxProcessLog(); @@ -160,28 +134,28 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { } } - private void onInitialized(TaskEntity taskEntity) { + public void onInitialized(TaskEntity taskEntity) { log.error("onInitialized"); } - private void onCreate(TaskEntity taskEntity) { + public void onCreate(TaskEntity taskEntity) { log.error("onCreate"); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); - RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - BpmnTaskDelegateAssigner assignee; - - // 记录发起人 +// RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); +// BpmnTaskDelegateAssigner assignee; +// +// // 记录发起人 boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType()); - if (isNodeStarter) { - assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), - INTERNAL_INITIATOR)); - if (Objects.isNull(assignee)) { - // 兼容历史数据 - assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), OLD_INTERNAL_INITIATOR)); - } - } else { - assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); - } +// if (isNodeStarter) { +// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), +// INTERNAL_INITIATOR)); +// if (Objects.isNull(assignee)) { +// // 兼容历史数据 +// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), OLD_INTERNAL_INITIATOR)); +// } +// } else { +// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); +// } RepositoryService repositoryService = processEngineConfiguration.getRepositoryService(); BpmnModel bpmnModel = repositoryService.getBpmnModel(taskEntity.getProcessDefinitionId()); @@ -197,13 +171,13 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType()); log.setTaskId(taskEntity.getId()); log.setOperationDesc(PENDING.getDesc()); - if (Objects.nonNull(assignee)) { - log.setAssigneeFull(assignee); - log.setAssigneeId(Long.valueOf(assignee.getPersonId())); - log.setAssigneeTenantId(assignee.getTenantId()); - log.setAssigneeName(assignee.getAssignerName()); - log.setAssigneeOuId(assignee.getOuId()); - } +// if (Objects.nonNull(assignee)) { +// log.setAssigneeFull(assignee); +// log.setAssigneeId(Long.valueOf(assignee.getPersonId())); +// log.setAssigneeTenantId(assignee.getTenantId()); +// log.setAssigneeName(assignee.getAssignerName()); +// log.setAssigneeOuId(assignee.getOuId()); +// } log.setStartTime(taskEntity.getCreateTime()); log.setStatus(PROCESSING.getStatus()); @@ -222,10 +196,4 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener { } return node; } - - - @Override - public boolean isFailOnException() { - return true; - } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/model/AddComment.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/model/AddComment.java new file mode 100644 index 000000000..acbce8564 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/model/AddComment.java @@ -0,0 +1,40 @@ +package cn.axzo.workflow.core.engine.model; + +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; + +/** + * 评论模型 + * + * @author wangli + * @since 2024-09-05 23:18 + */ +public class AddComment { + private String commentType; + private String content; + + public AddComment(String commentType, String content) { + this.commentType = commentType; + this.content = content; + } + + public AddComment(String content) { + this.commentType = COMMENT_TYPE_OPERATION_DESC; + this.content = content; + } + + public String getCommentType() { + return commentType; + } + + public void setCommentType(String commentType) { + this.commentType = commentType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/converter/BpmnProcessInstanceAdminPageItemConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/converter/BpmnProcessInstanceAdminPageItemConverter.java index 42ff1140f..a4a51262e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/converter/BpmnProcessInstanceAdminPageItemConverter.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/converter/BpmnProcessInstanceAdminPageItemConverter.java @@ -30,12 +30,12 @@ import static org.mapstruct.NullValueCheckStrategy.ALWAYS; * @since 2024/1/25 16:31 */ @Mapper( - componentModel = "spring", - nullValueCheckStrategy = ALWAYS, - imports = Arrays.class + componentModel = "spring", + nullValueCheckStrategy = ALWAYS, + imports = Arrays.class ) public interface BpmnProcessInstanceAdminPageItemConverter extends EntityConverter { + HistoricProcessInstance> { @Mapping(target = "processInstanceId", source = "id") @Mapping(target = "processInstanceName", source = "name") @@ -58,8 +58,8 @@ public interface BpmnProcessInstanceAdminPageItemConverter extends EntityConvert if (Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) { List flowElements = instanceFlowElementMap.get(i.getId()).stream() - .filter(j -> j instanceof UserTask || j instanceof ReceiveTask || j instanceof ServiceTask) - .collect(Collectors.toList()); + .filter(j -> j instanceof UserTask || j instanceof ReceiveTask || j instanceof ServiceTask) + .collect(Collectors.toList()); vo.setTotalNodeCount(flowElements.size()); // 进行中的节点 @@ -85,7 +85,7 @@ public interface BpmnProcessInstanceAdminPageItemConverter extends EntityConvert vo.setCategoryDesc(category.getLabel()); vo.setWorkspaceTypeCode(category.getWorkspaceTypeCode()); vo.setBusinessStatusDesc(BpmnProcessInstanceResultEnum.valueOfStatus(vo.getBusinessStatus()).getDesc()); - vo.setWorkspaceType(WorkspaceType.getType(Integer.valueOf(vo.getWorkspaceTypeCode()))); + vo.setWorkspaceType(WorkspaceType.getType(Integer.valueOf(Objects.nonNull(vo.getWorkspaceTypeCode()) ? vo.getWorkspaceTypeCode() : "0"))); result.add(vo); }); return result; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 78809f2da..be5f34628 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,77 +1,63 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.axzo.workflow.common.util.ThreadUtil; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; -import cn.azxo.framework.common.model.CommonResponse; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import java.util.List; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import com.fasterxml.jackson.databind.node.ObjectNode; -import javax.annotation.Nullable; -import java.util.Map; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; -import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryItemVO; -import org.springframework.web.bind.annotation.PathVariable; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import cn.axzo.workflow.common.util.ThreadUtil; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; -import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; /** * Workflow Engine Starter Management Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 From 9e63eb6a0615783c96eaccee6fd6e4faaaf794a5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 6 Sep 2024 10:30:33 +0800 Subject: [PATCH 017/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20Task=20=E4=B8=BA=20TaskEntity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomApproveTaskCmd.java | 4 ++-- .../workflow/core/engine/cmd/CustomBackTaskCmd.java | 7 +++---- .../core/engine/cmd/CustomCompleteDummyTaskCmd.java | 4 ++-- .../core/engine/cmd/CustomTransferUserTaskCmd.java | 9 ++++----- .../core/engine/cmd/helper/CustomTaskHelper.java | 12 +++++++----- .../listener/entity/type/TaskEntityEventHandle.java | 12 ++++++------ 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index e6e961069..4e4720113 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -115,8 +115,8 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); - Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, approver, nodeTypes); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult(); + validTask(historicTaskInstance, task, approver, nodeTypes); // TODO 所有的跟 Task 相关的动作都可以在这里进行扩展,用于扩展八大按钮标准动作以外的一些逻辑,但这里需要结合 Spring 能力,需设计好扩展点,否则无法进行扩展 // 其他动态也应该在类似的地方预留扩展点 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 83e9f806d..2535978b0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -9,7 +9,6 @@ import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; @@ -76,8 +75,8 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); - Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, dto.getApprover(), dto.getNodeTypes()); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); + validTask(historicTaskInstance, task, dto.getApprover(), dto.getNodeTypes()); if (StringUtils.hasLength(dto.getAdvice())) { Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); @@ -91,7 +90,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ Authentication.setAuthenticatedUserId(null); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java index a00361cbf..d193f80cb 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java @@ -7,12 +7,12 @@ import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.identity.Authentication; -import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.Task; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -65,7 +65,7 @@ public class CustomCompleteDummyTaskCmd extends AbstractCommand implements CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = taskService.createTaskQuery().processInstanceId(processInstanceId) + TaskEntity task = (TaskEntity) taskService.createTaskQuery().processInstanceId(processInstanceId) .taskId(taskId).singleResult(); if (Objects.isNull(task)) { throw new WorkflowEngineException(DUMMY_TASK_NOT_EXISTS, processInstanceId, taskId); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java index 5cf121307..bc51f1f04 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java @@ -6,7 +6,6 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import org.flowable.common.engine.impl.identity.Authentication; -import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; @@ -83,11 +82,11 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = taskService.createTaskQuery().taskId(originTaskId).singleResult(); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, originTaskAssignee, null); + validTask(historicTaskInstance, task, originTaskAssignee, null); - validTaskAssignerDuplicated(commandContext, (TaskEntity) task, Lists.newArrayList(targetTaskAssignee)); + validTaskAssignerDuplicated(commandContext, task, Lists.newArrayList(targetTaskAssignee)); processAssignee(processEngineConfiguration, task); @@ -103,7 +102,7 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements return null; } - private void resolveOriginTask(CommandContext commandContext, TaskService taskService, Task task) { + private void resolveOriginTask(CommandContext commandContext, TaskService taskService, TaskEntity task) { BpmnTaskDelegateAssigner assigner = buildDummyAssigner("transfer", TASK_ASSIGNEE_SKIP_FLAT, "dummyApprover"); task.setAssignee(assigner.buildAssigneeId()); ((TaskEntity) task).setScopeType("TRANSFER"); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index 2c607957c..5fd11f522 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -247,10 +247,11 @@ public class CustomTaskHelper { addComment(commandContext, task, type, message); } - public static void addComment(CommandContext commandContext, Task task, AddComment addComment) { + public static void addComment(CommandContext commandContext, TaskEntity task, AddComment addComment) { addComment(commandContext, task, addComment.getCommentType(), addComment.getContent()); } - public static void addComment(CommandContext commandContext, Task task, String type, String message) { + + public static void addComment(CommandContext commandContext, TaskEntity task, String type, String message) { if (!StringUtils.hasText(type) || !StringUtils.hasText(message)) { return; } @@ -276,6 +277,7 @@ public class CustomTaskHelper { processEngineConfiguration.getCommentEntityManager().insert(comment); + task.setTransientVariable(type, message); } public static Attachment addAttachment(CommandContext commandContext, Task task, AttachmentDTO attachmentDto) { @@ -341,8 +343,7 @@ public class CustomTaskHelper { task.setTaskDefinitionKey(taskDefinitionKey); task.setPriority(DEFAULT_PRIORITY); task.setCreateTime(new Date()); - // 创建临时节点 - taskService.saveTask(task); + if (Objects.nonNull(assigner)) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() @@ -382,10 +383,11 @@ public class CustomTaskHelper { return task; } - private static void addAdvice(CommandContext commandContext, Task task, String comment, String userId) { + private static void addAdvice(CommandContext commandContext, TaskEntity task, String comment, String userId) { if (StringUtils.hasLength(comment)) { Authentication.setAuthenticatedUserId(userId); addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); + task.setTransientVariable(COMMENT_TYPE_ADVICE + task.getId(), comment); Authentication.setAuthenticatedUserId(null); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 3514e6614..6c7e61a96 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -18,17 +18,15 @@ import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.flowable.engine.impl.cmd.GetTaskCommentsByTypeCmd; import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.engine.task.Comment; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Component; -import java.util.Comparator; import java.util.List; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; @@ -98,11 +96,13 @@ public class TaskEntityEventHandle implements EntityEventHandle { if (Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType())) { update.setStatus(APPROVED.getStatus()); } else { - List comments = processEngineConfiguration.getCommandExecutor() - .execute(new GetTaskCommentsByTypeCmd(taskEntity.getId(), COMMENT_TYPE_OPERATION_DESC)); - comments.stream().max(Comparator.comparing(Comment::getTime)).ifPresent(e -> update.setOperationDesc(e.getFullMessage())); String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); + Object advice = taskEntity.getTransientVariable(COMMENT_TYPE_ADVICE); + log.info("COMMENT_TYPE_ADVICE: {}", advice); + Object operationDesc = taskEntity.getTransientVariable(COMMENT_TYPE_OPERATION_DESC); + log.info("COMMENT_TYPE_OPERATION_DESC: {}", operationDesc); + update.setStatus(completionType); queryLog.setOperationDesc(PENDING.getDesc()); From 879e1a8cafb4f23ff86dba1146a84f6e98877919 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 6 Sep 2024 12:08:06 +0800 Subject: [PATCH 018/139] =?UTF-8?q?REQ-2924-=E5=A4=84=E7=90=86=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpmn/task/BpmnOptionalNodeDTO.java | 21 +++++++++++++++++++ .../web/bpmn/BpmnProcessTaskController.java | 12 +++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java index 665a5b19f..b5581813b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java @@ -15,17 +15,38 @@ import lombok.NoArgsConstructor; @Builder public class BpmnOptionalNodeDTO { + /** + * 对应流程实例id + */ private String processInstanceId; + /** + * 对应流程定义id + */ private String processDefinitionId; + /** + * 节点id + */ private String processNodeId; + /** + * 节点名称 + */ private String processNodeName; + /** + * 节点描述,用于页面展示 + */ private String processNodeDesc; + /** + * 节点类型 + */ private BpmnFlowNodeType nodeType; + /** + * 序号,越小越靠近发起节点 + */ private Integer ordinal; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index bcf08eaaf..f2c638b06 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -136,9 +136,9 @@ public class BpmnProcessTaskController implements ProcessTaskApi { } /** - * 回退 + * 回退到指定节点 */ - @Operation(summary = "回退任务") + @Operation(summary = "回退任务到指定节点") @PostMapping("/back") @RepeatSubmit @Override @@ -148,12 +148,10 @@ public class BpmnProcessTaskController implements ProcessTaskApi { } /** - * 回退到指定节点 - * @param dto - * @return + * 驳回 */ - @Operation(summary = "回退") - @PostMapping("/api/process/task/back") + @Operation(summary = "驳回任务") + @PostMapping("/reject") @Override @RepeatSubmit public CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto) { From b6ab7db0ed2f1c3f4c8401a7d6e3a237a8254598 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 6 Sep 2024 14:10:04 +0800 Subject: [PATCH 019/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=80=80=E5=9B=9E=E8=8A=82=E7=82=B9=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessTaskApi.java | 9 +++--- .../bpmn/task/BpmnUserTaskNodeDTO.java | 32 ------------------- .../core/service/BpmnProcessTaskService.java | 3 +- .../impl/BpmnProcessTaskServiceImpl.java | 3 +- .../web/bpmn/BpmnProcessTaskController.java | 9 +++--- .../starter/api/WorkflowCoreService.java | 9 +++--- 6 files changed, 15 insertions(+), 50 deletions(-) delete mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 214ab75a8..0d9828443 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -13,7 +13,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; @@ -74,12 +73,12 @@ public interface ProcessTaskApi { /** * 获取当前节点可退回节点选项列表 - * @param bpmnUserTaskNodeDTO 参数 - * @return + * @param taskId 当前任务id + * @return 可以退回节点列表 */ @Operation(summary = "获取当前节点可退回节点选项列表") - @PostMapping("/api/process/task/back/optional/nodes") - CommonResponse> getBackOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); + @GetMapping("/api/process/task/back/optional/nodes") + CommonResponse> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); /** * 回退到指定节点 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java deleted file mode 100644 index c1a228742..000000000 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnUserTaskNodeDTO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.axzo.workflow.common.model.request.bpmn.task; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import javax.validation.constraints.NotBlank; - -@ApiModel("节点信息模型") -@Data -@Accessors(chain = true) -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class BpmnUserTaskNodeDTO { - - @ApiModelProperty(value = "租户id") - @NotBlank(message = "租户id不能为空") - private String tenantId; - - @ApiModelProperty(value = "流程实例id") - @NotBlank(message = "流程实例id不能为空") - private String processInstanceId; - - @ApiModelProperty(value = "审批任务id") - @NotBlank(message = "审批任务id不能为空") - private String taskId; -} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java index f78bff7bc..346b2fd31 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java @@ -56,10 +56,9 @@ public interface BpmnProcessTaskService { /** * 退回到指定节点,可以退回节点选项 - * @param processInstanceId 流程实例id * @param taskId 任务id */ - List getApproveOptionalNodes(String processInstanceId, String taskId, String tenantId); + List getBackOptionalNodes(String taskId); /** * 驳回 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 283cdce74..77d7a6646 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -343,11 +343,12 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } @Override - public List getApproveOptionalNodes(String processInstanceId, String taskId, String tenantId) { + public List getBackOptionalNodes(String taskId) { Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(taskId).singleResult(); if (task == null) { throw new WorkflowEngineException(PROCESS_TASK_NOT_EXISTS); } + String processInstanceId = task.getProcessInstanceId(); //1.获取当前的流程实例 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); if (processInstance == null) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index f2c638b06..096805280 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -14,7 +14,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; @@ -123,15 +122,15 @@ public class BpmnProcessTaskController implements ProcessTaskApi { /** * 获取当前节点可退回节点选项列表 - * @param dto 参数 + * @param taskId 当前任务id * @return 可选退回节点列表 */ @Operation(summary = "获取当前节点可退回节点选项列表") - @PostMapping("/back/optional/nodes") + @GetMapping("/back/optional/nodes") @Override @RepeatSubmit - public CommonResponse> getBackOptionalNodes(@RequestBody @Validated BpmnUserTaskNodeDTO dto) { - List approveOptionalNodes = bpmnProcessTaskService.getApproveOptionalNodes(dto.getProcessInstanceId(), dto.getTaskId(), dto.getTenantId()); + public CommonResponse> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId) { + List approveOptionalNodes = bpmnProcessTaskService.getBackOptionalNodes(taskId); return success(approveOptionalNodes); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index fd86467fc..b9074162b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -15,7 +15,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnUserTaskNodeDTO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.util.ThreadUtil; @@ -178,12 +177,12 @@ public interface WorkflowCoreService { /** * 获取当前节点可退回节点选项列表 - * @param bpmnUserTaskNodeDTO 参数 - * @return + * @param taskId 当前任务id + * @return 可以退回节点列表 */ @Operation(summary = "获取当前节点可退回节点选项列表") - @PostMapping("/api/process/task/back/optional/nodes") - List getBackOptionalNodes(@Validated @RequestBody BpmnUserTaskNodeDTO bpmnUserTaskNodeDTO); + @GetMapping("/api/process/task/back/optional/nodes") + List getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); /** * 回退到指定节点 From f610bc9a97f79aec4b36f797ae9f04f1353531e7 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 6 Sep 2024 14:49:16 +0800 Subject: [PATCH 020/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=AF=84=E8=AE=BA=E5=8A=9F=E8=83=BD=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomCommentTaskCmd.java | 48 ++++++++++--------- .../engine/cmd/helper/CustomTaskHelper.java | 4 +- .../entity/type/TaskEntityEventHandle.java | 29 +++++++---- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java index 0faf9d4ee..c712829b0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java @@ -4,13 +4,11 @@ import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentExtDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; -import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.cfg.IdGenerator; import org.flowable.common.engine.impl.identity.Authentication; -import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; import org.flowable.engine.TaskService; @@ -22,7 +20,6 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.flowable.variable.service.HistoricVariableService; import org.flowable.variable.service.impl.persistence.entity.HistoricVariableInstanceEntity; import org.flowable.variable.service.impl.types.StringType; -import org.springframework.util.StringUtils; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; @@ -36,9 +33,13 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_COMMENT_EXT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_COMMENT; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COMMENTED; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.TASK_CANT_COMMENT_INSTANCE_NOT_EXISTS; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createExtTaskInst; import static org.flowable.task.api.Task.DEFAULT_PRIORITY; /** @@ -80,11 +81,11 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); HistoricProcessInstance processInstance = - historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); if (Objects.isNull(processInstance)) { throw new WorkflowEngineException(TASK_CANT_COMMENT_INSTANCE_NOT_EXISTS, processInstanceId); } @@ -103,32 +104,35 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria task.setTaskDefinitionKey(NODE_COMMENT.getType()); task.setPriority(DEFAULT_PRIORITY); task.setCreateTime(new Date()); - // 创建临时节点 - taskService.saveTask(task); + // 处理该评论节点的评论人 buildAndInsertHistoryVariable(task, processInstance, processEngineConfiguration); CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream() - .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() - .ifPresent(i -> i.setAssignee(operator.buildAssigneeId())); - // 完成临时节点 - taskService.complete(task.getId()); + .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() + .ifPresent(i -> i.setAssignee(operator.buildAssigneeId())); // 新增评论 Authentication.setAuthenticatedUserId(operator.buildAssigneeId()); - if (StringUtils.hasText(comment)) { - CustomTaskHelper.addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); - } - if (Objects.nonNull(commentExt)) { - CustomTaskHelper.addComment(commandContext, task, COMMENT_TYPE_COMMENT_EXT, JSONUtil.toJsonStr(commentExt)); - } + addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); + addComment(commandContext, task, COMMENT_TYPE_COMMENT_EXT, JSONUtil.toJsonStr(commentExt)); Authentication.setAuthenticatedUserId(null); // 处理附件 - CustomTaskHelper.batchAddAttachment(commandContext, processInstanceId, task.getId(), attachmentList, operator); + batchAddAttachment(commandContext, processInstanceId, task.getId(), attachmentList, operator); - CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, processInstanceId, - task.getId(), task.getTaskDefinitionKey(), operator, COMMENTED.getStatus()); + createExtTaskInst(extAxHiTaskInstService, processInstanceId, + task.getId(), task.getTaskDefinitionKey(), operator, COMMENTED.getStatus()); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), COMMENTED.getStatus()); + + // 保存临时节点 + taskService.saveTask(task); + + // 设置快照信息 + task.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), operator.toJson()); + + // 完成临时节点 + taskService.complete(task.getId()); return null; } @@ -136,9 +140,9 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria HistoricProcessInstance processInstance, ProcessEngineConfigurationImpl processEngineConfiguration) { HistoricVariableService historicVariableService = - processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService(); + processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService(); HistoricVariableInstanceEntity historicVariableInstance = - historicVariableService.createHistoricVariableInstance(); + historicVariableService.createHistoricVariableInstance(); historicVariableInstance.setTaskId(task.getId()); historicVariableInstance.setExecutionId(task.getExecutionId()); historicVariableInstance.setProcessInstanceId(processInstance.getId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index 5fd11f522..c506a981d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -344,7 +344,6 @@ public class CustomTaskHelper { task.setPriority(DEFAULT_PRIORITY); task.setCreateTime(new Date()); - if (Objects.nonNull(assigner)) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() @@ -364,6 +363,9 @@ public class CustomTaskHelper { task.getTaskDefinitionKey(), assigner, extTaskInstStatus); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), extTaskInstStatus); + // 保存任务 + taskService.saveTask(task); + if (Objects.nonNull(assigner)) { // 设置快照信息 task.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), assigner.toJson()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 6c7e61a96..7df816d11 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -3,7 +3,6 @@ package cn.axzo.workflow.core.engine.listener.entity.type; import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; -import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; @@ -21,7 +20,9 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import java.util.Date; import java.util.List; import java.util.Objects; @@ -79,6 +80,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { ExtAxProcessLog queryLog = new ExtAxProcessLog(); queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); queryLog.setTaskId(taskEntity.getId()); + queryLog.setOperationDesc(PENDING.getDesc()); ExtAxProcessLog update = new ExtAxProcessLog(); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); @@ -97,17 +99,26 @@ public class TaskEntityEventHandle implements EntityEventHandle { update.setStatus(APPROVED.getStatus()); } else { String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); - log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); + if (StringUtils.hasText(completionType)) { + log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); + update.setStatus(completionType); + } Object advice = taskEntity.getTransientVariable(COMMENT_TYPE_ADVICE); - log.info("COMMENT_TYPE_ADVICE: {}", advice); + if (Objects.nonNull(advice) && StringUtils.hasText(advice.toString())) { + log.info("COMMENT_TYPE_ADVICE: {}", advice); + update.setAdvice(advice.toString()); + } Object operationDesc = taskEntity.getTransientVariable(COMMENT_TYPE_OPERATION_DESC); - log.info("COMMENT_TYPE_OPERATION_DESC: {}", operationDesc); - - update.setStatus(completionType); - - queryLog.setOperationDesc(PENDING.getDesc()); - update.setOperationDesc(BpmnProcessInstanceResultEnum.valueOfStatus(completionType).getDesc()); + if (Objects.nonNull(operationDesc) && StringUtils.hasText(operationDesc.toString())) { + log.info("COMMENT_TYPE_OPERATION_DESC: {}", operationDesc); + update.setOperationDesc(Objects.nonNull(assignee) ? assignee.getAssignerName() + operationDesc : operationDesc.toString()); + } else { + update.setOperationDesc(Objects.nonNull(assignee) ? assignee.getAssignerName() : ""); + // 评论节点会给 operationDesc 赋 COMMENTED 的值,所以注释 +// update.setOperationDesc(BpmnProcessInstanceResultEnum.valueOfStatus(completionType).getDesc()); + } } + update.setEndTime(new Date()); processLogService.update(queryLog, update); } From 155537c130050d943f25852ce37abff939d689da Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 6 Sep 2024 18:31:31 +0800 Subject: [PATCH 021/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=BD=AC=E4=BA=A4=E5=8A=9F=E8=83=BD=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../engine/cmd/CustomTransferUserTaskCmd.java | 35 ++++++++++--------- .../entity/type/TaskEntityEventHandle.java | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java index bc51f1f04..51778165d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java @@ -15,7 +15,6 @@ import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.HashMap; @@ -76,9 +75,9 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); @@ -88,16 +87,19 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements validTaskAssignerDuplicated(commandContext, task, Lists.newArrayList(targetTaskAssignee)); + // 修改节点对应的审批人集合快照信息 processAssignee(processEngineConfiguration, task); + // 对被转交的任务进行建议和附件的处理 resolveOriginTask(commandContext, taskService, task); - batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, - originTaskAssignee); + originTaskAssignee); - addMultiTask(commandContext, (TaskEntity) task, targetTaskAssignee); - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), TRANSFER.getStatus()); - deleteMultiTask(commandContext, (TaskEntity) task); + // 生成转交任务 + addMultiTask(commandContext, task, targetTaskAssignee); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), TRANSFER.getStatus()); + // 结束被转交任务 + deleteMultiTask(commandContext, task); return null; } @@ -105,23 +107,22 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements private void resolveOriginTask(CommandContext commandContext, TaskService taskService, TaskEntity task) { BpmnTaskDelegateAssigner assigner = buildDummyAssigner("transfer", TASK_ASSIGNEE_SKIP_FLAT, "dummyApprover"); task.setAssignee(assigner.buildAssigneeId()); - ((TaskEntity) task).setScopeType("TRANSFER"); - taskService.saveTask(task); + task.setScopeType("TRANSFER"); Authentication.setAuthenticatedUserId(originTaskAssignee.buildAssigneeId()); addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "转交给" + targetTaskAssignee.getAssignerName()); - if (StringUtils.hasLength(advice)) { - addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice); - } + addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice); Authentication.setAuthenticatedUserId(null); + + taskService.saveTask(task); } public void processAssignee(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) { RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); List originAssingeeList = runtimeService.getVariable(task.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class); Optional exists = originAssingeeList.stream() - .filter(i -> Objects.equals(i.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())).findAny(); + .filter(i -> Objects.equals(i.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())).findAny(); if (exists.isPresent()) { throw new WorkflowEngineException(ASSIGNEE_HAS_BEEN_EXISTS); } @@ -134,8 +135,8 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements } originAssingeeList.add(targetTaskAssignee); runtimeService.setVariable(task.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), - originAssingeeList); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), + originAssingeeList); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 7df816d11..a852e0786 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -45,7 +45,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprova import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; /** - * TODO + * 评论、加签、转交 * * @author wangli * @since 2024-09-06 00:02 From ddc4bd64da37ead46cf41047f2387658749dde29 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 6 Sep 2024 18:31:48 +0800 Subject: [PATCH 022/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomBackTaskCmd.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 2535978b0..6acc44fa0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -12,7 +12,6 @@ import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.Collections; @@ -68,24 +67,20 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); TaskService taskService = processEngineConfiguration.getTaskService(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); validTask(historicTaskInstance, task, dto.getApprover(), dto.getNodeTypes()); - if (StringUtils.hasLength(dto.getAdvice())) { - Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); - addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); - Authentication.setAuthenticatedUserId(null); - } batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); - Authentication.setAuthenticatedUserId(Objects.nonNull(dto.getApprover()) ? dto.getApprover().buildAssigneeId() : null); + Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); + addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc); Authentication.setAuthenticatedUserId(null); @@ -93,9 +88,9 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); runtimeService.createChangeActivityStateBuilder() - .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) - .changeState(); + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) + .changeState(); return null; } From 5e5d27a5eefea0aee40618ac6805b81e1203b597 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 6 Sep 2024 20:57:43 +0800 Subject: [PATCH 023/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=97=A0=E7=94=A8=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/interceptor/CustomRetryInterceptor.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index 04671e6f4..c4a634bad 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -38,9 +38,6 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { try { // try to execute the command - if (log.isDebugEnabled()) { - log.debug("assignableFrom result: {}", AbstractCommand.class.isAssignableFrom(command.getClass())); - } if (AbstractCommand.class.isAssignableFrom(command.getClass())) { // 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行. log.info("Executing command params: {} traceId:{} ", TraceUtil.traceId(), From 105a9229ac287749d79a3d2d929ffdd7f944c689 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 6 Sep 2024 23:54:56 +0800 Subject: [PATCH 024/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=A9=B3=E5=9B=9E=E3=80=81=E6=92=A4=E5=9B=9E=E3=80=81=E4=B8=AD?= =?UTF-8?q?=E6=AD=A2=E3=80=81=E6=8A=84=E9=80=81=E5=8A=9F=E8=83=BD=E7=9A=84?= =?UTF-8?q?=E6=96=B0=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 2 + .../process/BpmnProcessInstanceCancelDTO.java | 1 + .../CustomReceiveTaskActivityBehavior.java | 5 +- ...askDelegateExpressionActivityBehavior.java | 26 +++++++-- .../cmd/CustomAbortProcessInstanceCmd.java | 2 +- .../cmd/CustomCancelProcessInstanceCmd.java | 2 +- .../engine/cmd/CustomRejectionTaskCmd.java | 8 +-- .../entity/type/CommentEntityEventHandle.java | 3 +- .../entity/type/TaskEntityEventHandle.java | 55 ++++++++++++++++--- .../DeleteProcessInstanceOperation.java | 11 +++- .../repository/entity/ExtAxProcessLog.java | 3 +- .../core/service/ExtAxProcessLogService.java | 6 +- .../impl/ExtAxProcessLogServiceImpl.java | 10 +++- 13 files changed, 103 insertions(+), 31 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 6c132c786..91f4ab550 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -108,6 +108,7 @@ public interface BpmnConstants { String BPM_MODEL_CATEGORY = "bpm_model_category"; String BPM_ALLOW_SKIP_USER_TASK = "_INTERNAL_SKIP_USER_TASK_"; String AUTO_APPROVAL_TYPE = "autoApprovalType"; + String PROCESS_CLOSING_TYPE = "[_PROCESS_CLOSING_TYPE]"; /** * 用于国内审批节点填写审批建议 *

@@ -120,6 +121,7 @@ public interface BpmnConstants { String NUMBER_OF_INSTANCES = "nrOfInstances"; String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter"; String TASK_COMPLETE_OPERATION_TYPE = "_TASK_COMPLETE_TYPE"; + /** * 会签表达式 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java index 5b44b327c..4bf8718b5 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCancelDTO.java @@ -36,6 +36,7 @@ public class BpmnProcessInstanceCancelDTO { * 工作台 ID */ @ApiModelProperty(value = "工作台 ID") + @NotBlank(message = "工作台不能为空") private String tenantId; /** diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java index 5c0db9d78..1837174b1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomReceiveTaskActivityBehavior.java @@ -75,11 +75,8 @@ public class CustomReceiveTaskActivityBehavior extends ReceiveTaskActivityBehavi eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), receiveTask.getId(), task.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); -// // 新版日志使用 -// eventDispatcher.dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_DELETED, task), -// processEngineConfiguration.getEngineCfgKey()); } else { - log.warn("task is null, executionId: {}, activityId: {}", execution.getId(), + log.warn("ReceiveTask is null, executionId: {}, activityId: {}", execution.getId(), execution.getCurrentActivityId()); } super.leave(execution); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index 378fa8998..108939712 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -2,6 +2,7 @@ package cn.axzo.workflow.core.engine.behavior; import cn.axzo.workflow.core.engine.event.ExtTaskInstCreateEvent; import cn.axzo.workflow.core.engine.event.ExtTaskInstUpdateEvent; +import cn.axzo.workflow.core.engine.listener.EngineCarbonCopyEventListener; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.MapExceptionEntry; import org.flowable.bpmn.model.ServiceTask; @@ -19,14 +20,16 @@ import org.flowable.task.service.TaskService; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.util.List; +import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; /** * 自定义的服务任务活动行为处理器 *

- * 主要用来创建审批日志 + * 主要用来创建抄送节点审批日志,真实计算抄送人的集合是由 {@link EngineCarbonCopyEventListener} 来完成的 * * @author wangli * @since 13/03/2024 14:17 @@ -35,6 +38,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES public class CustomServiceTaskDelegateExpressionActivityBehavior extends ServiceTaskDelegateExpressionActivityBehavior { protected final ServiceTask serviceTask; + // thread safe private TaskEntity task; public CustomServiceTaskDelegateExpressionActivityBehavior(String serviceTaskId, Expression expression, @@ -57,7 +61,7 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service task.setTaskDefinitionKey(serviceTask.getId()); task.setPropagatedStageInstanceId(execution.getPropagatedStageInstanceId()); task.setName(serviceTask.getName()); - TaskHelper.insertTask(task, (ExecutionEntity) execution, false, false); + TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false); // 添加 taskInst 扩展表数据 FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); @@ -72,11 +76,23 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service CommandContext commandContext = CommandContextUtil.getCommandContext(); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); - FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); - eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), - execution.getCurrentActivityId(), task.getId(), APPROVED), + + org.flowable.engine.TaskService taskService = processEngineConfiguration.getTaskService(); + TaskEntity serviceTask = (TaskEntity) taskService.createTaskQuery().taskId(task.getId()) + .taskDefinitionKey(execution.getCurrentActivityId()).singleResult(); + if (Objects.nonNull(serviceTask)) { + // 用于新版日志 + serviceTask.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + serviceTask.getId(), APPROVED.getStatus()); + + eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), + execution.getCurrentActivityId(), serviceTask.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); + } else { + log.warn("ServiceTask is null, executionId: {}, activityId: {}", execution.getId(), + execution.getCurrentActivityId()); + } + super.leave(execution); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java index 69faa460c..2ccd617a4 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java @@ -101,7 +101,7 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand impleme runtimeService.setVariables(instance.getId(), variables); CommandContextUtil.getAgenda(commandContext).planOperation(new DeleteProcessInstanceOperation(commandContext, - processInstanceId, extAxHiTaskInstService)); + processInstanceId, extAxHiTaskInstService, ABORTED)); // 添加自定义的节点,用于展示最后的操作 Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId, diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java index cb1996e3a..f32129f5c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java @@ -104,7 +104,7 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand implem runtimeService.setVariables(instance.getId(), variables); CommandContextUtil.getAgenda(commandContext).planOperation(new DeleteProcessInstanceOperation(commandContext, - processInstanceId, extAxHiTaskInstService)); + processInstanceId, extAxHiTaskInstService, CANCELLED)); // 添加自定义的节点,用于展示最后的操作 Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId, diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 02fc23b46..2ee944c96 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -97,11 +97,11 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, approver, nodeTypes); + validTask(historicTaskInstance, task, approver, nodeTypes); - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), REJECTED.getStatus()); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), REJECTED.getStatus()); Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), task.getTaskDefinitionKey(), advice, Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus(), @@ -126,7 +126,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser runtimeService.setVariables(task.getProcessInstanceId(), variables); CommandContextUtil.getAgenda(commandContext) .planOperation(new DeleteProcessInstanceOperation(commandContext, task.getProcessInstanceId(), - extAxHiTaskInstService)); + extAxHiTaskInstService, REJECTED)); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java index d3f416f6a..c7e03e86d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/CommentEntityEventHandle.java @@ -6,7 +6,6 @@ import cn.axzo.workflow.core.service.ExtAxProcessLogService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.impl.persistence.entity.CommentEntity; -import org.springframework.stereotype.Component; import java.util.Objects; @@ -20,7 +19,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERAT * @since 2024-09-06 00:14 */ @Slf4j -@Component +//@Component @AllArgsConstructor public class CommentEntityEventHandle implements EntityEventHandle { private final ExtAxProcessLogService processLogService; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index a852e0786..a221541a8 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.ExtAxProcessLogService; +import com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; @@ -20,6 +21,7 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.Date; @@ -32,6 +34,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERAT import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; @@ -39,13 +42,16 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.PENDING; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType; /** - * 评论、加签、转交 + * 同意、评论、加签、转交、驳回、撤回、中止、抄送 + *

+ * 退回 * * @author wangli * @since 2024-09-06 00:02 @@ -87,22 +93,19 @@ public class TaskEntityEventHandle implements EntityEventHandle { RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); // BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(taskEntity.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); - if (Objects.nonNull(assignee)) { - update.setAssigneeFull(assignee); + if (Objects.nonNull(assignee) && !Objects.equals(NO_ASSIGNEE, assignee.buildAssigneeId())) { + update.setAssigneeFull(Lists.newArrayList(assignee)); update.setAssigneeId(Long.valueOf(assignee.getPersonId())); update.setAssigneeTenantId(assignee.getTenantId()); update.setAssigneeName(assignee.getAssignerName()); update.setAssigneeOuId(assignee.getOuId()); } + boolean needDelete = false; if (Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType())) { update.setStatus(APPROVED.getStatus()); } else { - String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); - if (StringUtils.hasText(completionType)) { - log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); - update.setStatus(completionType); - } + Object advice = taskEntity.getTransientVariable(COMMENT_TYPE_ADVICE); if (Objects.nonNull(advice) && StringUtils.hasText(advice.toString())) { log.info("COMMENT_TYPE_ADVICE: {}", advice); @@ -117,9 +120,45 @@ public class TaskEntityEventHandle implements EntityEventHandle { // 评论节点会给 operationDesc 赋 COMMENTED 的值,所以注释 // update.setOperationDesc(BpmnProcessInstanceResultEnum.valueOfStatus(completionType).getDesc()); } + + + String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); + if (StringUtils.hasText(completionType)) { + log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); + update.setStatus(completionType); + } else { + // 多实例除操作人以外的任务,直接删除日志, 例如一个节点有两个人或签,A 人驳回了,那么 B 人不再需要操作,任务自动删除。而会签也同理 + update.setStatus(DELETED.getStatus());// delete标志着是多实例删除 + needDelete = true; + } } update.setEndTime(new Date()); + + // 判断是否抄送节点,如果是的话,需要将抄送人集合放入对应字段 + if (isCarbonCopyNode(queryLog)) { + // 抄送人集合 + List carbonCopies = runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class); + update.setAssigneeFull(carbonCopies); + update.setOperationDesc("抄送" + carbonCopies.size() + "人"); + } + processLogService.update(queryLog, update); + + if (needDelete) { + // 再逻辑删除该记录 + ExtAxProcessLog deleteLog = new ExtAxProcessLog(); + deleteLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); + deleteLog.setTaskId(taskEntity.getId()); + processLogService.delete(deleteLog); + } + } + + private boolean isCarbonCopyNode(ExtAxProcessLog queryLog) { + List logs = processLogService.genericQuery(queryLog); + if (CollectionUtils.isEmpty(logs) || logs.size() != 1) { + return false; + } + return Objects.equals(logs.get(0).getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()); } public void onUpdated(TaskEntity taskEntity) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/operation/DeleteProcessInstanceOperation.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/operation/DeleteProcessInstanceOperation.java index df7346997..d1e14ba0b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/operation/DeleteProcessInstanceOperation.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/operation/DeleteProcessInstanceOperation.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.engine.operation; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; @@ -16,6 +17,7 @@ import java.util.List; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_CLOSING_TYPE; /** * 通用的在 Command 内执行删除流程实例时的额外操作 @@ -27,21 +29,25 @@ public class DeleteProcessInstanceOperation extends AbstractOperation { private final String processInstanceId; private final ExtAxHiTaskInstService extAxHiTaskInstService; private String customDeleteReason; + private final BpmnProcessInstanceResultEnum closingType; public DeleteProcessInstanceOperation(CommandContext commandContext, String processInstanceId, - ExtAxHiTaskInstService extAxHiTaskInstService) { + ExtAxHiTaskInstService extAxHiTaskInstService, + BpmnProcessInstanceResultEnum closingType) { super(commandContext, null); this.processInstanceId = processInstanceId; this.extAxHiTaskInstService = extAxHiTaskInstService; + this.closingType = closingType; } public DeleteProcessInstanceOperation(CommandContext commandContext, String processInstanceId, ExtAxHiTaskInstService extAxHiTaskInstService, - String customDeleteReason) { + String customDeleteReason, BpmnProcessInstanceResultEnum closingType) { super(commandContext, null); this.processInstanceId = processInstanceId; this.extAxHiTaskInstService = extAxHiTaskInstService; this.customDeleteReason = customDeleteReason; + this.closingType = closingType; } @Override @@ -65,6 +71,7 @@ public class DeleteProcessInstanceOperation extends AbstractOperation { } RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + runtimeService.setVariableLocal(processInstanceId, PROCESS_CLOSING_TYPE, closingType); runtimeService.deleteProcessInstance(processInstanceId, StringUtils.hasText(customDeleteReason) ? customDeleteReason : HIDDEN_ASSIGNEE_ID); // 将结束流程实例的原因记录下来 // runtimeService.deleteProcessInstance(processInstanceId, reason); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java index 179b8d732..569569c39 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java @@ -11,6 +11,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.Date; +import java.util.List; /** * 审批日志 @@ -68,7 +69,7 @@ public class ExtAxProcessLog extends BaseEntity { * 审批人对象信息 */ @TableField(typeHandler = JacksonTypeHandler.class) - private BpmnTaskDelegateAssigner assigneeFull; + private List assigneeFull; /** * 审批人标识 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java index 99b9ef4e8..ef2791f63 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java @@ -3,6 +3,8 @@ package cn.axzo.workflow.core.service; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; +import java.util.List; + /** * Api Log 表操作服务 * @@ -21,7 +23,7 @@ public interface ExtAxProcessLogService { /** * 根据参数删除指定任务 * - * @param deleteLog + * @param deleteLog 查询条件 */ void delete(ExtAxProcessLog deleteLog); @@ -49,4 +51,6 @@ public interface ExtAxProcessLogService { void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee); void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, String operationDesc); + + List genericQuery(ExtAxProcessLog query); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java index 67c30f0e7..c9c1e8005 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java @@ -65,7 +65,7 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService { } ExtAxProcessLog update = new ExtAxProcessLog(); update.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : assignee.getAssignerName()); - update.setAssigneeFull(assignee); + update.setAssigneeFull(Lists.newArrayList(assignee)); update.setAssigneeId(Long.valueOf(assignee.getPersonId())); update.setAssigneeTenantId(assignee.getTenantId()); update.setAssigneeOuId(assignee.getOuId()); @@ -73,6 +73,11 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService { extAxProcessLogMapper.update(update, buildQueryWrapper(queryLog)); } + @Override + public List genericQuery(ExtAxProcessLog query) { + return extAxProcessLogMapper.selectList(buildQueryWrapper(query)); + } + LambdaQueryWrapper buildQueryWrapper(ExtAxProcessLog log) { return new LambdaQueryWrapper() .eq(Objects.nonNull(log.getId()), ExtAxProcessLog::getId, log.getId()) @@ -80,6 +85,7 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService { .eq(StringUtils.hasText(log.getActivityId()), ExtAxProcessLog::getActivityId, log.getActivityId()) .eq(StringUtils.hasText(log.getActivityName()), ExtAxProcessLog::getActivityName, log.getActivityName()) .eq(StringUtils.hasText(log.getTaskId()), ExtAxProcessLog::getTaskId, log.getTaskId()) - .eq(StringUtils.hasText(log.getTenantId()), ExtAxProcessLog::getTenantId, log.getTenantId()); + .eq(StringUtils.hasText(log.getTenantId()), ExtAxProcessLog::getTenantId, log.getTenantId()) + .eq(ExtAxProcessLog::getIsDelete, 0); } } From f30d891f82a6f09e2d62a208a95baeeb79c8a54b Mon Sep 17 00:00:00 2001 From: wangli Date: Sat, 7 Sep 2024 23:00:07 +0800 Subject: [PATCH 025/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=E6=9F=A5=E8=AF=A2=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessInstanceApi.java | 15 +- .../common/enums/ApprovalMethodEnum.java | 10 + .../workflow/common/enums/BpmnButtonEnum.java | 2 +- .../common/enums/BpmnFlowNodeMode.java | 10 + .../common/model/request/BpmnApproveConf.java | 9 +- .../model/request/bpmn/BpmnButtonConf.java | 9 +- .../BpmnProcessInstanceLogQueryDTO.java | 54 +++ .../request/bpmn/task/AttachmentDTO.java | 6 + .../bpmn/task/BpmnOptionalNodeDTO.java | 4 +- .../process/BpmnProcessInstanceLogVO.java | 143 ++++++ .../bpmn/task/BpmnTaskInstanceLogVO.java | 123 ++++++ .../core/common/code/BpmnTaskRespCode.java | 1 + .../conf/handler/ButtonConfTypeHandler.java | 57 +++ .../conf/handler/ListAssigneeTypeHandler.java | 57 +++ .../core/engine/cmd/CustomBackTaskCmd.java | 24 +- .../engine/job/AsyncBackTaskJobHandler.java | 11 +- .../entity/type/TaskEntityEventHandle.java | 35 +- .../repository/entity/ExtAxProcessLog.java | 10 +- .../service/BpmnProcessInstanceService.java | 24 +- .../impl/BpmnProcessInstanceServiceImpl.java | 414 +++++++++++++----- .../impl/BpmnProcessTaskServiceImpl.java | 6 +- .../support/FlowNodeForecastService.java | 56 ++- .../main/resources/sql/upgrade_to_1.4.2.sql | 5 +- .../AbstractBpmnTaskAssigneeSelector.java | 143 ++++-- .../BasedIdentityTaskAssigneeSelector.java | 5 - .../TransferToAdminTaskAssigneeSelector.java | 5 - .../server/controller/web/TestController.java | 11 +- .../bpmn/BpmnProcessInstanceController.java | 36 +- .../web/bpmn/BpmnProcessTaskController.java | 35 +- 29 files changed, 1081 insertions(+), 239 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceLogQueryDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ButtonConfTypeHandler.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ListAssigneeTypeHandler.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index e2368600f..465d79c4f 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; @@ -10,18 +9,19 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCar import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.azxo.framework.common.model.CommonResponse; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; -import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -241,4 +241,15 @@ public interface ProcessInstanceApi { @Manageable @InvokeMode(SYNC) CommonResponse checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + + /** + * 获取指定流程的日志 + * + * @param dto + * @return + */ + @Operation(summary = "获取指定流程的日志") + @PostMapping("/api/process/instance/log") + @InvokeMode(SYNC) + CommonResponse getProcessInstanceLog(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ApprovalMethodEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ApprovalMethodEnum.java index 81f213001..2d6451b8e 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ApprovalMethodEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/ApprovalMethodEnum.java @@ -1,5 +1,8 @@ package cn.axzo.workflow.common.enums; +import java.util.Arrays; +import java.util.Objects; + /** * 审批方式枚举 * @@ -48,4 +51,11 @@ public enum ApprovalMethodEnum { public void setRemark(String remark) { this.remark = remark; } + + public static ApprovalMethodEnum valueOfType(String type) { + return Arrays.stream(ApprovalMethodEnum.values()) + .filter(i -> Objects.equals(i.getType(), type)) + .findAny() + .orElse(null); + } } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java index d9cc769c1..e7c72e8fd 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java @@ -33,7 +33,7 @@ public enum BpmnButtonEnum { */ BPMN_COMMENT(6, "BPMN_COMMENT", "评论"), /** - * 回退按钮 + * 退回按钮 */ BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "退回"), /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeMode.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeMode.java index e812d2986..00bad8570 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeMode.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeMode.java @@ -1,6 +1,9 @@ package cn.axzo.workflow.common.enums; +import java.util.Arrays; +import java.util.Objects; + public enum BpmnFlowNodeMode { GENERAL("GENERAL", "普通节点"), OR("OR", "或签节点"), @@ -35,4 +38,11 @@ public enum BpmnFlowNodeMode { public void setDesc(String desc) { this.desc = desc; } + + public static BpmnFlowNodeMode valueOfType(String type) { + return Arrays.stream(BpmnFlowNodeMode.values()) + .filter(i -> Objects.equals(i.getType(), type)) + .findAny() + .orElse(null); + } } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/BpmnApproveConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/BpmnApproveConf.java index abc5fe45e..ed9af9805 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/BpmnApproveConf.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/BpmnApproveConf.java @@ -3,18 +3,23 @@ package cn.axzo.workflow.common.model.request; import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import javax.validation.Valid; @ApiModel("JSON 版本的 BPMN 协议模型中流程配置管理") @Data -@NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) public class BpmnApproveConf { + public BpmnApproveConf() { + this.supportBatchOperation = false; + this.userAgreeSignature = false; + } + /** * 是否支持批量审批 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java index cf78a06ed..61f052ac0 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; /** @@ -25,25 +26,25 @@ public class BpmnButtonConf implements Serializable { * 发起人的按钮配置信息, 需要给全量按钮的配置 */ @ApiModelProperty(value = "发起人的按钮配置信息") - private List initiator; + private List initiator = new ArrayList<>(); /** * 当前审批人的按钮配置信息, JSON 格式 */ @ApiModelProperty(value = "当前审批人的按钮配置信息") - private List current; + private List current = new ArrayList<>(); /** * 历史审批人的按钮配置信息, JSON 格式 */ @ApiModelProperty(value = "历史审批人的按钮配置信息") - private List history; + private List history = new ArrayList<>(); /** * 抄送人的按钮配置信息, JSON 格式 */ @ApiModelProperty(value = "抄送人的按钮配置信息") - private List carbonCopy; + private List carbonCopy = new ArrayList<>(); public List getInitiator() { return initiator; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceLogQueryDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceLogQueryDTO.java new file mode 100644 index 000000000..17e7ad583 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceLogQueryDTO.java @@ -0,0 +1,54 @@ +package cn.axzo.workflow.common.model.request.bpmn.process; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; + +/** + * 查询流程实例日志 + * + * @author wangli + * @since 2024-09-07 17:32 + */ +@ApiModel("查询流程实例日志") +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BpmnProcessInstanceLogQueryDTO { + + /** + * 流程实例 ID + */ + @ApiModelProperty(value = "流程实例 ID") + @NotBlank(message = "流程实例 ID 不能为空") + private String processInstanceId; + + /** + * 谁来访问该实例日志,如果为空,则始终不就返回按钮信息 + *

+ * 注意,为了确保历史审批数据的查询,需要将除 avatar 外的其他所有属性补全 + */ + @ApiModelProperty(value = "访问者信息", notes = "如果为空,则始终不就返回按钮信息") + private BpmnTaskDelegateAssigner visitor; + + /** + * 返回结果中是否包含按钮 + */ + @ApiModelProperty(value = "返回结果中是否包含按钮", notes = "如果访问者为空,该属性为 true 时,同样也不会返回按钮") + private Boolean hasButton = false; + + /** + * 是否需要加密(同一个实例的日志,在不同端[cms/oms]下,审批人的信息需要按一定规则进行隐藏控制) + */ + @ApiModelProperty(value = "是否需要加密", notes = "同一个实例的日志,在不同端[cms/oms]下,审批人的信息需要按一定规则进行隐藏控制") + private Boolean encrypt; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java index 0ce3b76f0..b71352af2 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java @@ -3,7 +3,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task; import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @@ -16,6 +19,9 @@ import javax.validation.constraints.NotNull; */ @ApiModel("附件模型") @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class AttachmentDTO { /** diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java index b5581813b..459bfb13e 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java @@ -28,12 +28,12 @@ public class BpmnOptionalNodeDTO { /** * 节点id */ - private String processNodeId; + private String processActivityId; /** * 节点名称 */ - private String processNodeName; + private String processActivityName; /** * 节点描述,用于页面展示 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java new file mode 100644 index 000000000..4d2ad7731 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java @@ -0,0 +1,143 @@ +package cn.axzo.workflow.common.model.response.bpmn.process; + +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; +import cn.axzo.workflow.common.enums.WorkspaceType; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceLogVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.List; + +/** + * 流程实例日志模型 + * + * @author wangli + * @since 2024-09-07 17:07 + */ +@ApiModel("流程实例日志模型") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BpmnProcessInstanceLogVO { + /** + * 流程实例的编号 + */ + @ApiModelProperty(value = "流程实例的编号", example = "1024") + private String id; + + /** + * 流程名称 + */ + @ApiModelProperty(value = "流程名称", example = "权限点申请") + private String name; + + /** + * 流程分类 + */ + @ApiModelProperty(value = "流程分类", notes = "关联的业务分类", example = "1") + private String category; + + /** + * 审核状态 + */ + @ApiModelProperty(value = "审核状态(PROCESSING:审核中,APPROVED:已通过,REJECTED:已拒绝,CANCELLED:已取消)", example = "APPROVED") + private BpmnProcessInstanceResultEnum result; + + /** + * 发起时间 + */ + @ApiModelProperty("发起时间") + private Date startTime; + + /** + * 结束时间 + */ + @ApiModelProperty("结束时间") + private Date endTime; + + /** + * 流程定义 KEY + */ + @ApiModelProperty("流程定义 KEY") + private String processDefinitionKey; + + /** + * 流程定义 ID + */ + @ApiModelProperty("流程定义 ID") + private String processDefinitionId; + + /** + * 业务的唯一标识 + */ + @ApiModelProperty(value = "业务的唯一标识", example = "1", notes = "例如说,请假申请的编号") + private String businessKey; + + /** + * 流程最终状态 + */ + @ApiModelProperty("流程最终状态") + private String businessStatus; + + /** + * 发起人 + */ + @ApiModelProperty("发起人") + private BpmnTaskDelegateAssigner initiator; + + /** + * 当前流程发起租户 + */ + @ApiModelProperty("当前流程发起租户") + private String tenantId; + + /** + * 是代运营的流程 + */ + @ApiModelProperty("是代运营的流程") + private Boolean agented; + + /** + * 任务信息集合 + */ + @ApiModelProperty("任务信息集合") + private List tasks; + + /** + * 当前实例对应模型的全局兜底按钮配置 + */ + @ApiModelProperty(value = "当前实例对应模型的全局兜底按钮配置") + private BpmnButtonConf defaultButtonConf; + + /** + * 是否支持批量审批 + */ + @ApiModelProperty(value = "是否支持批量审批") + private Boolean supportBatchOperation; + + /** + * 审批同意录入手写签名 + */ + @ApiModelProperty(value = "审批同意录入手写签名") + private Boolean userAgreeSignature; + + /** + * 数据产生版本 + */ + @ApiModelProperty(value = "数据产生版本") + private String workflowEngineVersion; + + /** + * 当前流程对应工作台类型 + */ + @ApiModelProperty(value = "工作台类型") + private WorkspaceType workspaceType; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java new file mode 100644 index 000000000..32172360a --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java @@ -0,0 +1,123 @@ +package cn.axzo.workflow.common.model.response.bpmn.task; + +import cn.axzo.workflow.common.enums.ApprovalMethodEnum; +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; +import java.util.List; + +/** + * 流程任务日志模型 + * + * @author wangli + * @since 2024-09-07 17:08 + */ +@ApiModel("流程任务日志模型") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BpmnTaskInstanceLogVO { + + /** + * 审批任务 ID + */ + @ApiModelProperty(value = "审批任务 ID") + private String taskId; + /** + * 审批任务节点定义KEY + */ + @ApiModelProperty(value = "审批任务节点定义KEY") + private String taskDefinitionKey; + /** + * 审批任务节点名称 + */ + @ApiModelProperty(value = "审批任务节点名称") + private String name; + /** + * 任务创建时间 + */ + @ApiModelProperty(value = "任务创建时间") + private Date createTime; + /** + * 任务结束时间 + */ + @ApiModelProperty(value = "任务结束时间") + private Date endTime; + /** + * 审批方式 + */ + @ApiModelProperty(value = "审批方式") + private ApprovalMethodEnum approvalMethod; + /** + * 节点类型 + */ + @ApiModelProperty(value = "节点类型") + private BpmnFlowNodeType nodeType; + /** + * 审批任务节点的类型 + */ + @ApiModelProperty(value = "审批任务节点的类型") + private BpmnFlowNodeMode nodeMode; + /** + * 任务状态 + */ + @ApiModelProperty(value = "任务状态") + private BpmnProcessInstanceResultEnum result; + + /** + * 操作描述 + */ + @ApiModelProperty(value = "操作描述") + private String operationDesc; + /** + * 审批建议 + */ + @ApiModelProperty(value = "审批建议") + private String advice; + /** + * 一些扩展信息 + */ + @ApiModelProperty(value = "一些扩展信息") + private String commentExt; + /** + * 图片列表 + */ + @ApiModelProperty(value = "图片列表") + private List imageList; + /** + * 附件列表 + */ + @ApiModelProperty(value = "附件列表") + private List fileList; + /** + * 手写签名地址 + */ + @ApiModelProperty(value = "手写签名地址") + private String signatureUrl; + /** + * 审批人快照信息 + */ + @ApiModelProperty(value = "审批人快照信息") + private BpmnTaskDelegateAssigner assigneeSnapshot; + /** + * 未完成节点多实例模式的审批人信息 + */ + @ApiModelProperty(value = "未完成节点多实例模式的审批人信息") + private List forecastAssignees; + + public boolean isVirtual() { + return StringUtils.isBlank(this.taskId); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java index 3fdbeea92..663f31544 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java @@ -37,6 +37,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { TASK_TYPE_MISMATCH("020", "节点类型不匹配,当前节点类型:【{}】,指定节点类型:【{}】!"), PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"), ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT("022", String.format("人员数量超过限制,节点审批人限制数量为: %d!", APPROVAL_ASSIGNER_LIMIT_NUMBER)), + BACK_TARGET_ACTIVITY_NOT_EXISTS("023", "回退到指定节点【{}】失败!"), ; private final String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ButtonConfTypeHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ButtonConfTypeHandler.java new file mode 100644 index 000000000..c235e42c9 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ButtonConfTypeHandler.java @@ -0,0 +1,57 @@ +package cn.axzo.workflow.core.conf.handler; + +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; + +import java.io.IOException; +import java.util.List; + +/** + * BpmnButtonConf 数据映射转换 + * + * @author wangli + * @since 2024-09-07 22:40 + */ +@Slf4j +@MappedTypes({List.class}) +@MappedJdbcTypes({JdbcType.VARCHAR}) +public class ButtonConfTypeHandler extends AbstractJsonTypeHandler { + private static ObjectMapper objectMapper = new ObjectMapper(); + + public ButtonConfTypeHandler(Class type) { + if (log.isTraceEnabled()) { + log.trace("JacksonTypeHandler(" + type + ")"); + } + Assert.notNull(type, "Type argument cannot be null", new Object[0]); + } + + protected BpmnButtonConf parse(String json) { + try { + // 这里进行了json解析,同样在这里也可以进行字段查询后的处理,如对象内部的手机号字段的加密展示等 + return objectMapper.readValue(json, new TypeReference() { + }); + } catch (IOException var3) { + throw new RuntimeException(var3); + } + } + + protected String toJson(BpmnButtonConf obj) { + try { + return objectMapper.writeValueAsString(obj); + } catch (JsonProcessingException var3) { + throw new RuntimeException(var3); + } + } + + public static void setObjectMapper(ObjectMapper om) { + objectMapper = om; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ListAssigneeTypeHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ListAssigneeTypeHandler.java new file mode 100644 index 000000000..cd54a7f40 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/handler/ListAssigneeTypeHandler.java @@ -0,0 +1,57 @@ +package cn.axzo.workflow.core.conf.handler; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; + +import java.io.IOException; +import java.util.List; + +/** + * BpmnTaskDelegateAssigner 数据映射转换 + * + * @author wangli + * @since 2024-09-07 22:40 + */ +@Slf4j +@MappedTypes({List.class}) +@MappedJdbcTypes({JdbcType.VARCHAR}) +public class ListAssigneeTypeHandler extends AbstractJsonTypeHandler> { + private static ObjectMapper objectMapper = new ObjectMapper(); + + public ListAssigneeTypeHandler(Class type) { + if (log.isTraceEnabled()) { + log.trace("JacksonTypeHandler(" + type + ")"); + } + Assert.notNull(type, "Type argument cannot be null", new Object[0]); + } + + protected List parse(String json) { + try { + // 这里进行了json解析,同样在这里也可以进行字段查询后的处理,如对象内部的手机号字段的加密展示等 + return objectMapper.readValue(json, new TypeReference>() { + }); + } catch (IOException var3) { + throw new RuntimeException(var3); + } + } + + protected String toJson(List obj) { + try { + return objectMapper.writeValueAsString(obj); + } catch (JsonProcessingException var3) { + throw new RuntimeException(var3); + } + } + + public static void setObjectMapper(ObjectMapper om) { + objectMapper = om; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 6acc44fa0..706c8af42 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -1,8 +1,11 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; @@ -23,6 +26,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_TARGET_ACTIVITY_NOT_EXISTS; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; @@ -36,7 +40,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ private final BpmnTaskBackAuditDTO dto; - private final String operationDesc; + private static String operationDesc = "已回退"; @Override public String paramToJsonString() { @@ -51,17 +55,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ } public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto) { - this(dto, null); - } - - public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto, String operationDesc) { this.dto = dto; - // 这里的不能直接使用字符串的比较,因为外部可能传入空字符串,比如发起人的通过时,就是传入的空字符串 - if (Objects.nonNull(operationDesc)) { - this.operationDesc = operationDesc; - } else { - this.operationDesc = "已回退"; - } } @Override @@ -77,11 +71,17 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); validTask(historicTaskInstance, task, dto.getApprover(), dto.getNodeTypes()); + BpmnModel bpmnModel = processEngineConfiguration.getRepositoryService().getBpmnModel(historicTaskInstance.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(dto.getToActivityId()); + if (Objects.isNull(flowElement)) { + throw new WorkflowEngineException(BACK_TARGET_ACTIVITY_NOT_EXISTS, dto.getToActivityId()); + } + batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); - addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc); + addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc + flowElement.getName()); Authentication.setAuthenticatedUserId(null); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java index bfec5ab1a..ec466959c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBackTaskJobHandler.java @@ -14,8 +14,6 @@ import org.flowable.variable.api.delegate.VariableScope; import java.util.Objects; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; - @Slf4j public class AsyncBackTaskJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { @@ -37,14 +35,7 @@ public class AsyncBackTaskJobHandler extends AbstractExecuteWithLockJobHandler i if (Objects.isNull(task)) { return; } - CustomBackTaskCmd command; - if (Objects.equals(task.getTaskDefinitionKey(), NODE_STARTER.getType())) { - // 这里的 operationDesc 设置为“” 是为了在日志中不显示(已通过) - command = new CustomBackTaskCmd(dto, ""); - } else { - command = new CustomBackTaskCmd(dto); - } - processEngineConfiguration.getCommandExecutor().execute(command); + processEngineConfiguration.getCommandExecutor().execute(new CustomBackTaskCmd(dto)); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index a221541a8..65597e5eb 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -4,6 +4,7 @@ import cn.axzo.framework.jackson.utility.JSON; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.ExtAxProcessLogService; @@ -19,6 +20,7 @@ import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -186,26 +188,23 @@ public class TaskEntityEventHandle implements EntityEventHandle { public void onInitialized(TaskEntity taskEntity) { log.error("onInitialized"); + BpmnMetaParserHelper.getButtonConfig(ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId()), taskEntity.getTaskDefinitionKey()) + .ifPresent(buttons -> { + ExtAxProcessLog queryLog = new ExtAxProcessLog(); + queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); + queryLog.setTaskId(taskEntity.getId()); + + ExtAxProcessLog updateLog = new ExtAxProcessLog(); + updateLog.setButtonConf(buttons); + processLogService.update(queryLog, updateLog); + }); } public void onCreate(TaskEntity taskEntity) { log.error("onCreate"); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); -// RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); -// BpmnTaskDelegateAssigner assignee; -// -// // 记录发起人 + // 记录发起人 boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType()); -// if (isNodeStarter) { -// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), -// INTERNAL_INITIATOR)); -// if (Objects.isNull(assignee)) { -// // 兼容历史数据 -// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), OLD_INTERNAL_INITIATOR)); -// } -// } else { -// assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); -// } RepositoryService repositoryService = processEngineConfiguration.getRepositoryService(); BpmnModel bpmnModel = repositoryService.getBpmnModel(taskEntity.getProcessDefinitionId()); @@ -221,13 +220,6 @@ public class TaskEntityEventHandle implements EntityEventHandle { log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType()); log.setTaskId(taskEntity.getId()); log.setOperationDesc(PENDING.getDesc()); -// if (Objects.nonNull(assignee)) { -// log.setAssigneeFull(assignee); -// log.setAssigneeId(Long.valueOf(assignee.getPersonId())); -// log.setAssigneeTenantId(assignee.getTenantId()); -// log.setAssigneeName(assignee.getAssignerName()); -// log.setAssigneeOuId(assignee.getOuId()); -// } log.setStartTime(taskEntity.getCreateTime()); log.setStatus(PROCESSING.getStatus()); @@ -246,4 +238,5 @@ public class TaskEntityEventHandle implements EntityEventHandle { } return node; } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java index 569569c39..c78bdfe7e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java @@ -1,7 +1,10 @@ package cn.axzo.workflow.core.repository.entity; import cn.axzo.framework.data.mybatisplus.model.BaseEntity; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.conf.handler.ButtonConfTypeHandler; +import cn.axzo.workflow.core.conf.handler.ListAssigneeTypeHandler; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; @@ -68,7 +71,7 @@ public class ExtAxProcessLog extends BaseEntity { /** * 审批人对象信息 */ - @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(typeHandler = ListAssigneeTypeHandler.class) private List assigneeFull; /** * 审批人标识 @@ -95,9 +98,10 @@ public class ExtAxProcessLog extends BaseEntity { */ private Date endTime; /** - * 已回退标志 + * 节点按钮的全量配置 */ - private Boolean returned; + @TableField(typeHandler = ButtonConfTypeHandler.class) + private BpmnButtonConf buttonConf; /** * 任务状态:审批中/通过/驳回/转交/加签/退回 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessInstanceService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessInstanceService.java index 82e629a77..4de469d2a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessInstanceService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessInstanceService.java @@ -7,18 +7,21 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCar import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.HistoricProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import com.fasterxml.jackson.databind.node.ObjectNode; import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; import org.flowable.form.api.FormInfo; import javax.annotation.Nullable; @@ -107,7 +110,7 @@ public interface BpmnProcessInstanceService { * 获得流程实例 * * @param processDefinitionId 流程实例的编号 - * @param status 状态 + * @param status 状态 * @link SuspensionState.ACTIVE.getStateCode() */ Boolean updateProcessStatus(String processDefinitionId, Integer status); @@ -143,9 +146,28 @@ public interface BpmnProcessInstanceService { */ List getProcessInstanceNodeForecast(String processInstanceId, String tenantId); + /** + * 对指定流程的指定节点开始推送未来的结点,并结合变量计算正确的分支 + * + * @param processInstanceId 实例编号 + * @param startNodeDefinitionKey 从该节点开始推断后续的节点 + * @param containSelf 是否包含起始节点 + * @param checkAliveThrowException 如果给的实例编号已到终态,不会执行推测,用该参数为 true 时,抛出实例完结的异常信息,如果为 false时,直接返回空集合 + * @return + */ + List getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String processInstanceId, ProcessInstance instance, String startNodeDefinitionKey, Boolean containSelf, Boolean checkAliveThrowException); + List getProcessInstanceNodeFilterForecast(String processInstanceId, String tenantId, List nodeDefinitionKeys); List getTenantIds(); Boolean checkInstanceApprover(BpmnProcessInstanceCheckApproverDTO dto); + + /** + * 获取指定流程实例的日志 + * + * @param dto + * @return + */ + BpmnProcessInstanceLogVO getProcessInstanceLog(BpmnProcessInstanceLogQueryDTO dto); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 50ef58cf9..46fa043d0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1,8 +1,14 @@ package cn.axzo.workflow.core.service.impl; import cn.axzo.workflow.common.constant.BpmnConstants; +import cn.axzo.workflow.common.enums.ApprovalMethodEnum; +import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.WorkspaceType; +import cn.axzo.workflow.common.model.request.BpmnApproveConf; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; @@ -10,9 +16,11 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCar import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; @@ -20,10 +28,12 @@ import cn.axzo.workflow.common.model.response.bpmn.BatchOperationItemResultVO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.HistoricProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceLogVO; import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnCollectionUtils; @@ -34,10 +44,12 @@ import cn.axzo.workflow.core.engine.cmd.CustomCancelProcessInstanceCmd; import cn.axzo.workflow.core.engine.cmd.CustomCarbonCopyUserSelectorCmd; import cn.axzo.workflow.core.engine.cmd.CustomForecastUserTaskAssigneeCmd; import cn.axzo.workflow.core.engine.listener.EngineExecutionStartListener; +import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.BpmnProcessDefinitionService; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.core.service.CategoryService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; import cn.axzo.workflow.core.service.converter.BpmnHistoricProcessInstanceConverter; import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter; import cn.axzo.workflow.core.service.converter.BpmnProcessInstanceAdminPageItemConverter; @@ -77,6 +89,7 @@ import org.flowable.engine.runtime.NativeActivityInstanceQuery; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstanceBuilder; import org.flowable.engine.runtime.ProcessInstanceQuery; +import org.flowable.engine.task.Attachment; import org.flowable.form.api.FormInfo; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.task.api.Task; @@ -95,6 +108,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -187,12 +201,14 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Resource @Lazy private BpmnProcessInstanceService bpmnProcessInstanceService; + @Resource + private ExtAxProcessLogService processLogService; @Override public HistoricProcessInstance getProcessInstanceByBusinessKey(String businessKey, @Nullable String tenantId, @Nullable Boolean hasVariable) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); + historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); if (Boolean.TRUE.equals(hasVariable)) { query.includeProcessVariables(); } @@ -205,7 +221,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Override public BpmPageResult getMyProcessInstancePage(@Valid BpmnProcessInstanceMyPageReqVO dto) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(dto.getTenantId()); + historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(dto.getTenantId()); if (StringUtils.isNotBlank(dto.getName())) { query.processInstanceName(dto.getName()); } @@ -234,7 +250,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic query.processInstanceTenantId(dto.getTenantId()); } List instances = query.orderByProcessInstanceStartTime().desc() - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); if (CollectionUtils.isEmpty(instances)) { return BpmPageResult.empty(); @@ -343,11 +359,11 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置流程名字 ProcessInstanceBuilder instanceBuilder = runtimeService.createProcessInstanceBuilder() - .processDefinitionId(definition.getId()) - .businessKey(dto.getBusinessKey()) - .variables(dto.getVariables()) - .name(name) - .overrideProcessDefinitionTenantId(dto.getTenantId()); + .processDefinitionId(definition.getId()) + .businessKey(dto.getBusinessKey()) + .variables(dto.getVariables()) + .name(name) + .overrideProcessDefinitionTenantId(dto.getTenantId()); ProcessInstance instance; if (dto.getAsync()) { // 异步开始 @@ -363,8 +379,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Override public String createProcessInstanceWithForm(BpmnProcessInstanceCreateWithFormDTO dto) { BpmnProcessDefinitionVO definition = - processDefinitionService.getActiveProcessDefinitionByKey(dto.getProcessDefinitionKey(), - dto.getInitiator().getTenantId()); + processDefinitionService.getActiveProcessDefinitionByKey(dto.getProcessDefinitionKey(), + dto.getInitiator().getTenantId()); // 校验流程定义 if (definition == null) { throw new WorkflowEngineException(PROCESS_DEFINITION_KEY_NOT_EXISTS, dto.getProcessDefinitionKey()); @@ -378,11 +394,11 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置流程实例的开始人,参考https://wenku.baidu.com/view/5538062e7a563c1ec5da50e2524de518964bd3f9.html Authentication.setAuthenticatedUserId(dto.getInitiator().buildAssigneeId()); String name = StringUtils.isNotBlank(dto.getCustomProcessInstanceName()) ? - dto.getCustomProcessInstanceName() - : definition.getName(); + dto.getCustomProcessInstanceName() + : definition.getName(); ProcessInstance instance = runtimeService.startProcessInstanceWithForm(definition.getId(), - dto.getOutcome(), dto.getVariables(), name); + dto.getOutcome(), dto.getVariables(), name); Authentication.setAuthenticatedUserId(null); return instance.getProcessInstanceId(); } @@ -399,7 +415,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic commandExecutor.execute(new CustomCancelProcessInstanceAsyncCmd(dto)); } else { commandExecutor.execute(new CustomCancelProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(), - dto.getReason(), dto.getInitiator(), extAxHiTaskInstService)); + dto.getReason(), dto.getInitiator(), extAxHiTaskInstService)); } return true; } @@ -412,7 +428,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic commandExecutor.execute(new CustomAbortProcessInstanceAsyncCmd(dto)); } else { commandExecutor.execute(new CustomAbortProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(), - dto.getReason(), extAxHiTaskInstService)); + dto.getReason(), extAxHiTaskInstService)); } return true; } @@ -461,13 +477,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery query = historyService.createNativeHistoricProcessInstanceQuery(); String tableName = managementService.getTableName(HistoricProcessInstance.class); StringBuilder baseQuerySql = new StringBuilder("SELECT RES.*, ") - .append("DEF.KEY_ as PROC_DEF_KEY_,") - .append("DEF.NAME_ as PROC_DEF_NAME_,") - .append("DEF.VERSION_ as PROC_DEF_VERSION_,") - .append("DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_") - .append(" FROM ").append(tableName) - .append(" RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_") - .append(" WHERE 1 = 1"); + .append("DEF.KEY_ as PROC_DEF_KEY_,") + .append("DEF.NAME_ as PROC_DEF_NAME_,") + .append("DEF.VERSION_ as PROC_DEF_VERSION_,") + .append("DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_") + .append(" FROM ").append(tableName) + .append(" RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_") + .append(" WHERE 1 = 1"); if (StringUtils.isNotBlank(dto.getProcessInstanceId())) { List ids = Lists.newArrayList(dto.getProcessInstanceId().replaceAll(" ", "").split(",")); baseQuerySql.append(" AND RES.PROC_INST_ID_ IN ("); @@ -519,8 +535,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic baseQuerySql.append(" ORDER BY RES.START_TIME_ DESC "); List instances = query.sql(baseQuerySql.toString()) - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), - dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), + dto.getPageSize()); baseQuerySql.replace(7, 163, "count(1)"); NativeHistoricProcessInstanceQuery countSqlQuery = query.sql(baseQuerySql.toString()); @@ -529,8 +545,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } List processingInstanceIds = - instances.stream().filter(i -> Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) - .map(HistoricProcessInstance::getId).distinct().collect(Collectors.toList()); + instances.stream().filter(i -> Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) + .map(HistoricProcessInstance::getId).distinct().collect(Collectors.toList()); Map> instanceFlowElementMap = new HashMap<>(); processingInstanceIds.forEach(i -> { // 查询每个流程推测出来的总节点数 @@ -543,13 +559,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic Map leastEndActivityMap = getInstanceLastActivity(processingInstanceIds); List categories = instances.stream().map(HistoricProcessInstance::getProcessDefinitionKey) - .distinct().collect(Collectors.toList()); + .distinct().collect(Collectors.toList()); Map categoryLabelMap = categoryService.listByValue(BPM_MODEL_CATEGORY, categories) - .stream().collect(Collectors.toMap(CategoryItemVO::getValue, Function.identity(), (s, t) -> s)); + .stream().collect(Collectors.toMap(CategoryItemVO::getValue, Function.identity(), (s, t) -> s)); List vos = instanceAdminPageItemConverter.toVos(instances, - instanceFlowElementMap, liveActivityMap, leastEndActivityMap, - categoryLabelMap); + instanceFlowElementMap, liveActivityMap, leastEndActivityMap, + categoryLabelMap); return new BpmPageResult<>(vos, countSqlQuery.count()); } @@ -567,10 +583,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic String tableName = managementService.getTableName(ActivityInstanceEntity.class); StringBuilder querySql = new StringBuilder(); querySql.append("SELECT * FROM (") - .append("SELECT *, ROW_NUMBER() OVER (PARTITION BY PROC_INST_ID_ ORDER BY START_TIME_ DESC) AS rn ") - .append(" FROM ") - .append(tableName) - .append(" WHERE PROC_INST_ID_ in ("); + .append("SELECT *, ROW_NUMBER() OVER (PARTITION BY PROC_INST_ID_ ORDER BY START_TIME_ DESC) AS rn ") + .append(" FROM ") + .append(tableName) + .append(" WHERE PROC_INST_ID_ in ("); for (int i = 0; i < processInstanceIds.size(); i++) { querySql.append("#{processInstanceId_").append(i).append("}"); if (i < processInstanceIds.size() - 1) { @@ -584,8 +600,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } querySql.append(") as t WHERE rn = 1"); return nativeQuery.sql(querySql.toString()).list().stream() - .collect(Collectors.toMap(ActivityInstance::getProcessInstanceId, Function.identity(), - (s, t) -> s)); + .collect(Collectors.toMap(ActivityInstance::getProcessInstanceId, Function.identity(), + (s, t) -> s)); } @@ -601,7 +617,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic public HistoricProcessInstance getHistoricProcessInstanceByBusinessKey(String businessKey, String tenantId) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); + historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -615,7 +631,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic processInstance = getProcessInstance(dto.getProcessInstanceId(), dto.getTenantId(), dto.getHasVariable()); } else if (StringUtils.isNotBlank(dto.getBusinessKey())) { processInstance = getProcessInstanceByBusinessKey(dto.getBusinessKey(), dto.getTenantId(), - dto.getHasVariable()); + dto.getHasVariable()); } // 获得流程实例 @@ -624,10 +640,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } // 获得流程定义 BpmnProcessDefinitionVO processDefinition = processDefinitionService - .getProcessDefinition(processInstance.getProcessDefinitionId()); + .getProcessDefinition(processInstance.getProcessDefinitionId()); if (Objects.isNull(processDefinition)) { throw new WorkflowEngineException(PROCESS_DEFINITION_ID_NOT_EXISTS, - processInstance.getProcessDefinitionId()); + processInstance.getProcessDefinitionId()); } Object tempAssigner = null; @@ -641,10 +657,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } else { List variableInstances = historyService.createHistoricVariableInstanceQuery() - .processInstanceId(processInstance.getId()).list(); + .processInstanceId(processInstance.getId()).list(); for (HistoricVariableInstance i : variableInstances) { if (Objects.equals(i.getVariableName(), INTERNAL_INITIATOR) || Objects.equals(i.getVariableName(), - OLD_INTERNAL_INITIATOR)) { + OLD_INTERNAL_INITIATOR)) { tempAssigner = i.getValue(); } if (Objects.equals(i.getVariableName(), WORKFLOW_ENGINE_VERSION)) { @@ -658,17 +674,17 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } List runningTasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()) - .active() - .orderByTaskCreateTime() - .desc() - .list(); + .active() + .orderByTaskCreateTime() + .desc() + .list(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); return instanceConverter.toVo(processInstance, processDefinition, - getButtonConfig(bpmnModel.getMainProcess()), - getProcessApproveConf(bpmnModel.getMainProcess()), - BpmnTaskDelegateAssigner.toObjectCompatible(tempAssigner), version, categoryService.get(BPM_MODEL_CATEGORY, - processInstance.getProcessDefinitionKey()), runningTasks); + getButtonConfig(bpmnModel.getMainProcess()), + getProcessApproveConf(bpmnModel.getMainProcess()), + BpmnTaskDelegateAssigner.toObjectCompatible(tempAssigner), version, categoryService.get(BPM_MODEL_CATEGORY, + processInstance.getProcessDefinitionKey()), runningTasks); } /** @@ -679,7 +695,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic */ public Map getProcessInstanceMap(Set ids) { return BpmnCollectionUtils.convertMap(getProcessInstances(ids), - ProcessInstance::getProcessInstanceId); + ProcessInstance::getProcessInstanceId); } @@ -691,19 +707,19 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic */ public Map getHistoricProcessInstanceMap(Set ids) { return BpmnCollectionUtils.convertMap(getHistoricProcessInstances(ids), - HistoricProcessInstance::getId); + HistoricProcessInstance::getId); } public List getHistoricProcessInstances(Set ids) { HistoricProcessInstanceQuery historicProcessInstanceQuery = - historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids); + historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids); return historicProcessInstanceQuery.list(); } @Override public ObjectNode getProcessInstanceGraphical(String processInstanceId, @Nullable String tenantId) { HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery() - .processInstanceId(processInstanceId); + .processInstanceId(processInstanceId); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -714,7 +730,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); List activityInstances = - historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); Set completedActivityInstances = new HashSet<>(); Set currentElements = new HashSet<>(); @@ -729,13 +745,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } // Gather completed flows List completedFlows = graphicService.gatherCompletedFlows(completedActivityInstances, currentElements - , bpmnModel); + , bpmnModel); Set completedElements = new HashSet<>(completedActivityInstances); completedElements.addAll(completedFlows); ObjectNode displayNode = graphicService.processProcessElements(bpmnModel, completedElements, currentElements, - new ArrayList<>(), processInstanceId); + new ArrayList<>(), processInstanceId); if (!CollectionUtils.isEmpty(completedActivityInstances)) { ArrayNode completedActivities = displayNode.putArray("completedActivities"); for (String completed : completedActivityInstances) { @@ -766,30 +782,30 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic StringBuilder baseQuerySql = new StringBuilder("SELECT a.* FROM ").append(tableName).append(" a"); if (StringUtils.isNotBlank(dto.getCategory())) { baseQuerySql.append(" LEFT JOIN ACT_RE_PROCDEF b ON a.PROC_DEF_ID_ = b.ID_ ") - .append(sqlConnectors(baseQuerySql)) - .append(" b.CATEGORY_ = #{category}"); + .append(sqlConnectors(baseQuerySql)) + .append(" b.CATEGORY_ = #{category}"); query.parameter("category", dto.getCategory()); } if (StringUtils.isNotBlank(dto.getSearchKey())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" (a.BUSINESS_KEY_ LIKE #{searchKey}") - .append(" or") - .append(" a.NAME_ LIKE #{searchKey})"); + .append(" (a.BUSINESS_KEY_ LIKE #{searchKey}") + .append(" or") + .append(" a.NAME_ LIKE #{searchKey})"); query.parameter("searchKey", "%" + dto.getSearchKey() + "%"); } if (StringUtils.isNotBlank(dto.getResult())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.BUSINESS_STATUS_ = #{result}"); + .append(" a.BUSINESS_STATUS_ = #{result}"); query.parameter("result", dto.getResult()); } if (Objects.nonNull(dto.getTenantId())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.TENANT_ID_ = #{tenantId}"); + .append(" a.TENANT_ID_ = #{tenantId}"); query.parameter("tenantId", dto.getTenantId()); } if (!CollectionUtils.isEmpty(dto.getUserIds())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.START_USER_ID_ in ("); + .append(" a.START_USER_ID_ in ("); for (int i = 0; i < dto.getUserIds().size(); i++) { baseQuerySql.append("#{userId").append(i).append("}"); if (i < dto.getUserIds().size() - 1) { @@ -801,20 +817,20 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } if (Objects.nonNull(dto.getStartBeginTime()) && Objects.nonNull(dto.getStartEndTime())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.START_TIME_ between #{startBeginTime} and #{startEndTime}"); + .append(" a.START_TIME_ between #{startBeginTime} and #{startEndTime}"); query.parameter("startBeginTime", dto.getStartBeginTime()); query.parameter("startEndTime", dto.getStartEndTime()); } if (Objects.nonNull(dto.getFinishedBeginTime()) && Objects.nonNull(dto.getFinishedEndTime())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.END_TIME_ between #{finishedBeginTime} and #{finishedEndTime}"); + .append(" a.END_TIME_ between #{finishedBeginTime} and #{finishedEndTime}"); query.parameter("finishedBeginTime", dto.getFinishedBeginTime()); query.parameter("finishedEndTime", dto.getFinishedEndTime()); } baseQuerySql.append(" ORDER BY a.START_TIME_ DESC"); NativeHistoricProcessInstanceQuery dataSqlQuery = query.sql(baseQuerySql.toString()); List instances = dataSqlQuery - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); if (CollectionUtils.isEmpty(instances)) { return BpmPageResult.empty(); } @@ -822,17 +838,17 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery countSqlQuery = query.sql(countSql(baseQuerySql)); if (StringUtils.isNotBlank(dto.getCategory())) { return new BpmPageResult(historicProcessInstanceConverter.toVos(instances, dto.getCategory()), - countSqlQuery.count()); + countSqlQuery.count()); } else { Set procDefIds = new HashSet<>(); instances.forEach(i -> procDefIds.add(i.getProcessDefinitionId())); Map defCategoryMap = - repositoryService.createProcessDefinitionQuery().processDefinitionIds(procDefIds).list() - .stream().collect(Collectors.toMap(ProcessDefinition::getId, - ProcessDefinition::getCategory, (s, t) -> s)); + repositoryService.createProcessDefinitionQuery().processDefinitionIds(procDefIds).list() + .stream().collect(Collectors.toMap(ProcessDefinition::getId, + ProcessDefinition::getCategory, (s, t) -> s)); List vos = new ArrayList<>(); instances.forEach(i -> vos.add(historicProcessInstanceConverter.toVo(i, - defCategoryMap.getOrDefault(i.getProcessDefinitionId(), "")))); + defCategoryMap.getOrDefault(i.getProcessDefinitionId(), "")))); return new BpmPageResult(vos, countSqlQuery.count()); } } @@ -844,10 +860,34 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic return getProcessInstanceNodeFilterForecast(processInstanceId, tenantId, Collections.emptyList()); } + @Override + public List getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String processInstanceId, + ProcessInstance instance, + String startNodeDefinitionKey, + Boolean containSelf, + Boolean checkAliveThrowException) { + if (Objects.isNull(instance)) { + instance = runtimeService.createProcessInstanceQuery() + .processInstanceId(processInstanceId).singleResult(); + if (Objects.isNull(instance)) { + if (checkAliveThrowException) { + throw new WorkflowEngineException(RUNNING_INSTANCE_ONLY_FORECAST); + } else { + return Collections.emptyList(); + } + } + } + + List flowElements = forecastService.performProcessForecasting(instance.getProcessInstanceId(), instance, startNodeDefinitionKey, containSelf); + + return buildNodeDetailVos(processInstanceId, Collections.emptyList(), instance, flowElements); + } + + @Override public List getProcessInstanceNodeFilterForecast(String processInstanceId, String tenantId, List nodeDefinitionKeys) { ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId); + .processInstanceId(processInstanceId); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -857,31 +897,35 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } List flowElements = forecastService.performProcessForecasting(processInstanceId, instance); + return buildNodeDetailVos(processInstanceId, nodeDefinitionKeys, instance, flowElements); + } + + private List buildNodeDetailVos(String processInstanceId, List nodeDefinitionKeys, ProcessInstance instance, List flowElements) { BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId()); List resultList = new ArrayList<>(flowElements.size()); // 发起人节点,也是一个 UserTask 节点, 所以这里默认就包含了发起人节点 flowElements.stream() - .filter(i -> (i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)) - .forEach(i -> { - ProcessNodeDetailVO node = new ProcessNodeDetailVO(); - node.setForecastAssigners(Collections.emptyList()); - // 每个节点设置的按钮配置 - getButtonConfig(bpmnModel.getMainProcess(), i.getId()).ifPresent(node::setButtonConf); - // 设置审批方式 - getApprovalMethod(i).ifPresent(node::setApprovalMethod); - getNodeType(i).ifPresent(node::setNodeType); - if (Objects.equals(NODE_STARTER.getType(), i.getId())) { - node.setNodeType(NODE_STARTER); - } - node.setNodeMode(GENERAL); - node.setId(i.getId()).setName(i.getName()); - if (i instanceof UserTask) { - parseUserTask(processInstanceId, (UserTask) i, node, nodeDefinitionKeys); - } else if (i instanceof ServiceTask) { - parseServiceTask(processInstanceId, (ServiceTask) i, node, nodeDefinitionKeys); - } - resultList.add(node); - }); + .filter(i -> (i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)) + .forEach(i -> { + ProcessNodeDetailVO node = new ProcessNodeDetailVO(); + node.setForecastAssigners(Collections.emptyList()); + // 每个节点设置的按钮配置 + getButtonConfig(bpmnModel.getMainProcess(), i.getId()).ifPresent(node::setButtonConf); + // 设置审批方式 + getApprovalMethod(i).ifPresent(node::setApprovalMethod); + getNodeType(i).ifPresent(node::setNodeType); + if (Objects.equals(NODE_STARTER.getType(), i.getId())) { + node.setNodeType(NODE_STARTER); + } + node.setNodeMode(GENERAL); + node.setId(i.getId()).setName(i.getName()); + if (i instanceof UserTask) { + parseUserTask(processInstanceId, (UserTask) i, node, nodeDefinitionKeys); + } else if (i instanceof ServiceTask) { + parseServiceTask(processInstanceId, (ServiceTask) i, node, nodeDefinitionKeys); + } + resultList.add(node); + }); return resultList; } @@ -892,10 +936,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic return; } getCarbonCopyConfigs(i).ifPresent(carbons -> - node.setForecastAssigners(springProcessEngineConfiguration.getCommandExecutor() - .execute(new CustomCarbonCopyUserSelectorCmd(processInstanceId, carbons, - i, engineExecutionStartListener, - historicTaskInstanceConverter, serviceVersion)))); + node.setForecastAssigners(springProcessEngineConfiguration.getCommandExecutor() + .execute(new CustomCarbonCopyUserSelectorCmd(processInstanceId, carbons, + i, engineExecutionStartListener, + historicTaskInstanceConverter, serviceVersion)))); } private void parseUserTask(String processInstanceId, UserTask i, ProcessNodeDetailVO node, List skipTaskDefinitionKeys) { @@ -903,10 +947,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置审批模式, if (i.getBehavior() instanceof MultiInstanceActivityBehavior) { MultiInstanceActivityBehavior behavior = - (MultiInstanceActivityBehavior) i.getBehavior(); + (MultiInstanceActivityBehavior) i.getBehavior(); node.setNodeMode(Objects.equals(AND_SIGN_EXPRESSION, - behavior.getCompletionCondition()) ? - AND : OR); + behavior.getCompletionCondition()) ? + AND : OR); } else { node.setNodeMode(BpmnFlowNodeMode.GENERAL); } @@ -917,9 +961,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic if (Objects.equals(node.getApprovalMethod(), human)) { // 推测当前节点的审批人,并且如果审批人为空,也会根据审批人为空的策略去找人 List forecastAssigners = - springProcessEngineConfiguration.getCommandExecutor() - .execute(new CustomForecastUserTaskAssigneeCmd(processInstanceId, - i, engineExecutionStartListener)); + springProcessEngineConfiguration.getCommandExecutor() + .execute(new CustomForecastUserTaskAssigneeCmd(processInstanceId, + i, engineExecutionStartListener)); node.setForecastAssigners(forecastAssigners); if (CollectionUtils.isEmpty(forecastAssigners)) { getApproverEmptyHandleType(i).ifPresent(emptyHandleType -> { @@ -944,7 +988,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery query = historyService.createNativeHistoricProcessInstanceQuery(); String tableName = managementService.getTableName(HistoricProcessInstance.class); String baseQuerySql = "SELECT DISTINCT TENANT_ID_ FROM " + tableName + - " WHERE TENANT_ID_ IS NOT NULL AND TENANT_ID_ != '' AND TENANT_ID_ != 0 AND TENANT_ID_ != 'NULL'"; + " WHERE TENANT_ID_ IS NOT NULL AND TENANT_ID_ != '' AND TENANT_ID_ != 0 AND TENANT_ID_ != 'NULL'"; NativeHistoricProcessInstanceQuery dataSqlQuery = query.sql(baseQuerySql); return ListUtils.emptyIfNull(dataSqlQuery.list()).stream().map(HistoricProcessInstance::getTenantId).distinct().collect(Collectors.toList()); } @@ -955,10 +999,160 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getApprover().setOuId(null); } List list = taskService.createTaskQuery() - .processInstanceId(dto.getProcessInstanceId()) - .taskAssigneeLikeIgnoreCase(dto.getApprover().buildAssigneeId()) - .active() - .list(); + .processInstanceId(dto.getProcessInstanceId()) + .taskAssigneeLikeIgnoreCase(dto.getApprover().buildAssigneeId()) + .active() + .list(); return !CollectionUtils.isEmpty(list); } + + @Override + public BpmnProcessInstanceLogVO getProcessInstanceLog(BpmnProcessInstanceLogQueryDTO dto) { + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(dto.getProcessInstanceId()) + .includeProcessVariables().singleResult(); + if (Objects.isNull(historicProcessInstance)) { + throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, dto.getProcessInstanceId()); + } + + ExtAxProcessLog query = new ExtAxProcessLog(); + query.setProcessInstanceId(dto.getProcessInstanceId()); + List logs = processLogService.genericQuery(query).stream() + .sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder()))) + .collect(Collectors.toList()); + + List forecasting = new ArrayList<>(); + // 只有还在运行中的实例才需要推测后续节点 + if (Objects.equals(historicProcessInstance.getBusinessStatus(), PROCESSING.getStatus())) { + ProcessInstance instance = runtimeService.createProcessInstanceQuery() + .processInstanceId(dto.getProcessInstanceId()) + .includeProcessVariables() + .singleResult(); + logs.stream().reduce((f, s) -> s).ifPresent(e -> forecasting.addAll( + getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false)) + ); + } + + BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId()); + + Map variables = historicProcessInstance.getProcessVariables(); + BpmnProcessInstanceLogVO logVO = BpmnProcessInstanceLogVO.builder() + .id(historicProcessInstance.getId()) + .name(historicProcessInstance.getName()) + .result(BpmnProcessInstanceResultEnum.valueOfStatus(historicProcessInstance.getBusinessStatus())) + .startTime(historicProcessInstance.getStartTime()) + .endTime(historicProcessInstance.getEndTime()) + .processDefinitionKey(historicProcessInstance.getProcessDefinitionKey()) + .processDefinitionId(historicProcessInstance.getProcessDefinitionId()) + .businessKey(historicProcessInstance.getBusinessKey()) + .businessStatus(historicProcessInstance.getBusinessStatus()) + .initiator(BpmnTaskDelegateAssigner.toObjectCompatible(Optional.ofNullable(variables.getOrDefault(INTERNAL_INITIATOR, null)) + .orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)))) + .tenantId(historicProcessInstance.getTenantId()) + .agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false)) + .tasks(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting)) + .defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf())) + .supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation()) + .userAgreeSignature(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getUserAgreeSignature()) + .workflowEngineVersion((String) variables.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121)) + .build(); + + + categoryService.get(BPM_MODEL_CATEGORY, historicProcessInstance.getProcessDefinitionKey()).ifPresent(category -> { + logVO.setWorkspaceType(WorkspaceType.getType(Integer.valueOf(category.getWorkspaceTypeCode()))); + logVO.setCategory(category.getValue()); + }); + return logVO; + } + + private List genericTaskLogVos(String processInstanceId, List logs, List forecasting) { + List tasks = new ArrayList<>(); + Map> attachmentByTaskMap = + taskService.getProcessInstanceAttachments(processInstanceId).stream() + .collect(Collectors.groupingBy(Attachment::getTaskId)); + // 已完成的和进行中的 + ListUtils.emptyIfNull(logs).forEach(e -> { + Optional processingTask = tasks.stream().filter(i -> Objects.equals(PROCESSING, i.getResult())) + .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); + + if (processingTask.isPresent()) { + processingTask.ifPresent(i -> { + List assigners = new ArrayList<>(); + assigners.add(i.getAssigneeSnapshot()); + assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))); + i.setAssigneeSnapshot(null); + i.setForecastAssignees(assigners); + }); + } else { + tasks.add(BpmnTaskInstanceLogVO.builder() + .taskId(e.getTaskId()) + .taskDefinitionKey(e.getActivityId()) + .name(e.getActivityName()) + .createTime(e.getStartTime()) + .endTime(e.getEndTime()) + .approvalMethod(ApprovalMethodEnum.valueOfType(e.getApprovalMethod())) + .nodeType(BpmnFlowNodeType.valueOfType(e.getNodeType())) + .nodeMode(BpmnFlowNodeMode.valueOfType(e.getNodeMode())) + .result(BpmnProcessInstanceResultEnum.valueOfStatus(e.getStatus())) + .operationDesc(e.getOperationDesc()) + .advice(e.getAdvice()) + .commentExt("") + .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) + .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) + .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) + .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))) + .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? e.getAssigneeFull() : Collections.emptyList()) + .build()); + } + + }); + // 未来节点 + ListUtils.emptyIfNull(forecasting).forEach(e -> { + tasks.add(BpmnTaskInstanceLogVO.builder() +// .taskId(e.getTaskId()) + .taskDefinitionKey(e.getId()) + .name(e.getName()) +// .createTime(e.getStartTime()) +// .endTime(e.getEndTime()) + .approvalMethod(e.getApprovalMethod()) + .nodeType(e.getNodeType()) + .nodeMode(e.getNodeMode()) +// .result(BpmnProcessInstanceResultEnum.valueOfStatus(e.getStatus())) +// .operationDesc(e.getOperationDesc()) +// .advice(e.getAdvice()) +// .commentExt("") +// .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) +// .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) +// .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) +// .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))) + .forecastAssignees(e.getForecastAssigners()) + .build()); + }); + return tasks; + } + + public List getAttachmentByType(Map> attachmentByTaskMap, String taskId, AttachmentTypeEnum type) { + return ListUtils.emptyIfNull(attachmentByTaskMap.get(taskId)).stream() + .filter(attachment -> Objects.equals(type.getType(), attachment.getType())) + .map(e -> AttachmentDTO.builder() + .id(e.getId()) + .type(type) + .name(e.getName()) + .description(e.getDescription()) + .url(e.getUrl()) + .build()) + .collect(Collectors.toList()); + } + +// List attachments = task.getAttachments(); +// // 图片 +// List imageList = attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.image, attachment.getType())).collect(Collectors.toList()); +// detail.setImageList(imageList); +// // 附件 +// List fileList = attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.file, attachment.getType())).collect(Collectors.toList()); +// detail.setFileList(fileList); +// // 手写签名 +// attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.signature, attachment.getType())).findAny().ifPresent(i -> detail.setSignatureUrl(i.getUrl())); + + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 77d7a6646..0f90c1ca1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -399,8 +399,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { .builder() .processInstanceId(task.getProcessInstanceId()) .processDefinitionId(task.getProcessDefinitionId()) - .processNodeId(flowElement.getId()) - .processNodeName(flowElement.getName()) + .processActivityId(flowElement.getId()) + .processActivityName(flowElement.getName()) .processNodeDesc(flowElement.getName()) .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) .ordinal(index.incrementAndGet()) @@ -408,7 +408,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(resultList)) { BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); - bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessNodeId() + "(上一级)"); + bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessActivityName() + "(上一级)"); } return resultList; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/FlowNodeForecastService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/FlowNodeForecastService.java index 96ebf4e17..a28d48fbd 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/FlowNodeForecastService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/support/FlowNodeForecastService.java @@ -6,7 +6,6 @@ import cn.axzo.workflow.core.service.support.forecast.Forecast; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.StartEvent; -import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.runtime.ProcessInstance; @@ -98,8 +97,6 @@ public class FlowNodeForecastService implements InitializingBean { @Resource private RepositoryService repositoryService; @Resource - private HistoryService historyService; - @Resource private RuntimeService runtimeService; @Resource private List> forecasts; @@ -114,15 +111,31 @@ public class FlowNodeForecastService implements InitializingBean { */ public List performProcessForecasting(@Nullable String processInstanceId, @Nullable ProcessInstance instance) { + return performProcessForecasting(processInstanceId, instance, null, null); + } + + /** + * 执行运行中的流程预测 + *

+ * 已完成的流程可以直接查询流程审批记录就行 + * + * @param processInstanceId 指定运行时的流程实例 ID + * @param instance 外部传入流程实例 (与另外一个参数必须二选一) + * @param taskDefinitionKey 从哪个节点开始推测 + * @param containSelf 配合第三个参数使用,为 true 时,推送的起始节点为第三个参数,否则,以第三个参数的下个节点开始 + */ + public List performProcessForecasting(@Nullable String processInstanceId, + @Nullable ProcessInstance instance, + @Nullable String taskDefinitionKey, + Boolean containSelf) { if (Objects.nonNull(instance)) { processInstanceId = instance.getProcessInstanceId(); } else if (!StringUtils.hasLength(processInstanceId)) { throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); } else { instance = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId) - // .includeProcessVariables() - .singleResult(); + .processInstanceId(processInstanceId) + .singleResult(); } if (Objects.isNull(instance)) { throw new WorkflowEngineException(RUNNING_INSTANCE_ONLY_FORECAST); @@ -134,10 +147,27 @@ public class FlowNodeForecastService implements InitializingBean { // 流程定义中所有的FlowElement Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); - // 开始节点 - findStartNode(flowElements).ifPresent(startNode -> { - addOrderFlowNodes(orderedNodes, startNode); - }); + if (StringUtils.hasText(taskDefinitionKey)) { + if (Boolean.TRUE.equals(containSelf)) { + flowElements.stream().filter(e -> Objects.equals(e.getId(), taskDefinitionKey)).findFirst().ifPresent(orderedNodes::add); + } else { + FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); + String finalProcessInstanceId = processInstanceId; + forecasts.forEach(i -> { + if (i.support(flowElement)) { + List list = i.nextFlowElement(flowElement, finalProcessInstanceId); + if (!CollectionUtils.isEmpty(list)) { + addOrderFlowNodes(orderedNodes, list.get(0)); + } + } + }); + } + } else { + // 开始节点 + findStartNode(flowElements).ifPresent(startNode -> { + addOrderFlowNodes(orderedNodes, startNode); + }); + } startForecasting(orderedNodes, processInstanceId); return orderedNodes; @@ -165,8 +195,8 @@ public class FlowNodeForecastService implements InitializingBean { */ private Optional findStartNode(Collection flowElements) { return Optional.ofNullable(flowElements.stream().filter(StartEvent.class::isInstance).findFirst() - .map(StartEvent.class::cast) - .orElseThrow(() -> new IllegalArgumentException("非法的参数, 正确的流程定义一定有一个 StartEvent 节点"))); + .map(StartEvent.class::cast) + .orElseThrow(() -> new IllegalArgumentException("非法的参数, 正确的流程定义一定有一个 StartEvent 节点"))); } @@ -187,7 +217,7 @@ public class FlowNodeForecastService implements InitializingBean { public void afterPropertiesSet() { forecasts.forEach(i -> { Class rawClass = ResolvableType.forClass(i.getClass(), Forecast.class) - .getSuperType().getGenerics()[0].getRawClass(); + .getSuperType().getGenerics()[0].getRawClass(); FORECAST_MAP.put(rawClass, (AbstractForecast) i); }); } diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index 28639e798..e7d619d3a 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -19,11 +19,10 @@ create table `workflow-engine`.ext_ax_process_log assignee_ou_id bigint default 0 not null comment '审批人归属单位', start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', end_time datetime(3) null comment '任务结束时间', - returned tinyint(1) default 0 not null comment '已回退标志', + button_conf json null comment '按钮配置', status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', extra json null comment '扩展字段', create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', is_delete bigint default 0 not null comment '是否删除' -) - comment '审批日志持久化'; +) comment '审批日志持久化'; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 0d32c68cf..38833c963 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -1,6 +1,9 @@ package cn.axzo.workflow.server.controller.delegate; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.PersonProfileQueryReq; +import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.common.enums.ApproverScopeEnum; import cn.axzo.workflow.common.enums.CarbonCopyObjectType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; @@ -29,9 +32,13 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StopWatch; import org.springframework.util.StringUtils; +import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -49,6 +56,8 @@ import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_US */ @Slf4j public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssigneeSelector, ApplicationContextAware { + @Resource + protected FlowSupportApi flowSupportApi; private ApplicationContext applicationContext; private EngineExecutionStartListener executionStartListener; @@ -58,15 +67,15 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign List assigners = new ArrayList<>(); if (flowElement instanceof UserTask) { assigners.addAll(BpmnMetaParserHelper.getApproverScope((UserTask) flowElement) - .map(approverScopeEnum -> privateSelector(approverScopeEnum, flowElement, execution, - throwException)) - .orElseGet(Collections::emptyList)); + .map(approverScopeEnum -> privateSelector(approverScopeEnum, flowElement, execution, + throwException)) + .orElseGet(Collections::emptyList)); } else if (flowElement instanceof ServiceTask) { List customProperties = ((ServiceTask) flowElement).getCustomProperties(); if (!CollectionUtils.isEmpty(customProperties)) { String processor = CarbonCopyObjectType.valueOfType(customProperties.get(0).getName()).getProcessor(); assigners.addAll(privateSelector(ApproverScopeEnum.valueOfProcessor(processor), flowElement, - execution, throwException)); + execution, throwException)); } } else if (flowElement instanceof NoticeFlowElement) { ApproverScopeEnum processor = ((NoticeFlowElement) flowElement).getProcessor(); @@ -78,22 +87,22 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign private List privateSelector(ApproverScopeEnum processorType, FlowElement flowElement, DelegateExecution execution, Boolean throwException) { ApproverScopeProcessor processor = applicationContext.getBean(processorType.getProcessor(), - ApproverScopeProcessor.class); + ApproverScopeProcessor.class); ApproverScopeDTO scopeDto = processor.build(flowElement, execution); if (CollectionUtils.isEmpty(scopeDto.getOrgScopes()) - && CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes())) { + && CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes())) { if (throwException) { throw new WorkflowEngineException(ENGINE_USER_TASK_PARAM_ERROR, flowElement.getId(), - processorType.getDesc()); + processorType.getDesc()); } } try { - return invokeService(flowElement, execution, scopeDto); + return populateAvatar(invokeService(flowElement, execution, scopeDto)); } catch (Throwable t) { if (throwException) { if (!(t instanceof WorkflowEngineException)) { throw new WorkflowEngineException(ENGINE_USER_TASK_CALC_ERROR, flowElement.getId(), - this.getType(), t.getMessage()); + this.getType(), t.getMessage()); } throw t; } else { @@ -107,24 +116,43 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return Collections.emptyList(); } - protected final T parseApiResult(Supplier> supplier, String operatorDesc, - String extInfo, Object... param) { + public static T parseApiResult(Supplier> supplier, String operatorDesc, + String extInfo, Object... param) { StopWatch stopWatch = new StopWatch(operatorDesc); log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); stopWatch.start(); ApiResult result = supplier.get(); stopWatch.stop(); log.info("{}-Cost:{}, Result: {}", operatorDesc, - "API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's", - JSONUtil.toJsonStr(result)); + "API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's", + JSONUtil.toJsonStr(result)); + Assert.notNull(result, "服务调用异常"); + // 200自定义处理 + if (HttpStatus.HTTP_OK != result.getCode()) { + throw new WorkflowEngineException(CALC_TASK_ASSIGNEE_ERROR, "[API:" + extInfo + "]" + result.getMsg()); + } + return result.getData(); + } + + + protected final T parseApiResult(Supplier> supplier, String operatorDesc, + String extInfo, Consumer> consumer, Object... param) { + StopWatch stopWatch = new StopWatch(operatorDesc); + log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); + stopWatch.start(); + ApiResult result = supplier.get(); + stopWatch.stop(); + log.info("{}-Cost:{}, Result: {}", operatorDesc, + "API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's", + JSONUtil.toJsonStr(result)); try { if (stopWatch.getTotalTimeSeconds() > executionStartListener.getApiTimeout()) { DingTalkUtils.sendDingTalkForSlowUrl(applicationContext.getEnvironment() - .getProperty("spring.profiles.active"), - stopWatch.getTotalTimeSeconds(), - extInfo, - param, - result); + .getProperty("spring.profiles.active"), + stopWatch.getTotalTimeSeconds(), + extInfo, + param, + result); } } catch (Exception e) { // ignore @@ -143,26 +171,26 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign try { if (flowElement instanceof UserTask) { return BpmnMetaParserHelper.getApproverSpecifyValue((UserTask) flowElement) - .map(value -> JSON.parseArray(value, String.class).stream().map(JSON::parseObject) - .map(i -> i.getString("value")) - .collect(Collectors.toList())) - .orElse(Collections.emptyList()); + .map(value -> JSON.parseArray(value, String.class).stream().map(JSON::parseObject) + .map(i -> i.getString("value")) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); } else if (flowElement instanceof ServiceTask) { List customProperties = ((ServiceTask) flowElement).getCustomProperties(); if (CollectionUtils.isEmpty(customProperties)) { return Collections.emptyList(); } return JSON.parseArray(customProperties.get(0).getSimpleValue(), String.class) - .stream().map(JSON::parseObject) - .map(i -> i.getString("value")) - .collect(Collectors.toList()); + .stream().map(JSON::parseObject) + .map(i -> i.getString("value")) + .collect(Collectors.toList()); } else if (flowElement instanceof NoticeFlowElement) { String customValues = ((NoticeFlowElement) flowElement).getCustomValues(); if (StringUtils.hasText(customValues)) { return JSON.parseArray(customValues, String.class) - .stream().map(JSON::parseObject) - .map(i -> i.getString("value")) - .collect(Collectors.toList()); + .stream().map(JSON::parseObject) + .map(i -> i.getString("value")) + .collect(Collectors.toList()); } return Collections.emptyList(); } else { @@ -170,13 +198,70 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign } } catch (Exception e) { throw new WorkflowEngineException(CONVERTOR_META_DATA_FORMAT_ERROR, "AbstractBpmnTaskAssigneeSelector" + - "#getTypes", e.getMessage()); + "#getTypes", e.getMessage()); } } + private List populateAvatar(List assigners) { + if (CollectionUtils.isEmpty(assigners)) { + return assigners; + } + List personIds = assigners.stream() + .filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) + .map(BpmnTaskDelegateAssigner::getPersonId) + .map(Long::parseLong) + .distinct().collect(Collectors.toList()); + Map personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), + "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds) + .stream().collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl, (s, t) -> s)); + assigners.forEach(assigner -> { + long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1")); + if (personProfileMap.containsKey(personId)) { + assigner.setAvatar(personProfileMap.getOrDefault(personId, "")); + } + }); + return assigners; + } + @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.applicationContext = context; executionStartListener = applicationContext.getBean(EngineExecutionStartListener.class); } + + static class ParseConsumer { + private String extInfo; + private ApiResult result; + private Object[] params; + + public ParseConsumer(String extInfo, ApiResult result, Object[] params) { + this.extInfo = extInfo; + this.result = result; + this.params = params; + } + + public String getExtInfo() { + return extInfo; + } + + public void setExtInfo(String extInfo) { + this.extInfo = extInfo; + } + + public ApiResult getResult() { + return result; + } + + public void setResult(ApiResult result) { + this.result = result; + } + + public Object[] getParams() { + return params; + } + + public void setParams(Object[] params) { + this.params = params; + } + } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java index 0e2317c09..d137fa30f 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.server.controller.delegate; -import cn.axzo.karma.client.feign.FlowSupportApi; import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq; import cn.axzo.karma.client.model.response.FlowTaskAssignerResp; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; @@ -12,7 +11,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @@ -28,9 +26,6 @@ import java.util.stream.Collectors; @Component public class BasedIdentityTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { - @Autowired - private FlowSupportApi flowSupportApi; - @Override public String getType() { return ApproverSpecifyEnum.identity.getType(); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index e06411435..62e47c22c 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.server.controller.delegate; -import cn.axzo.karma.client.feign.FlowSupportApi; import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq; import cn.axzo.karma.client.model.response.FlowTaskAssignerResp; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; @@ -15,7 +14,6 @@ import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @@ -33,9 +31,6 @@ import java.util.stream.Collectors; @Component public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { - @Autowired - private FlowSupportApi flowSupportApi; - @Override public String getType() { return ApproverEmptyHandleTypeEnum.transferToAdmin.getType(); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java index a3fe66874..c66f1934f 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/TestController.java @@ -1,13 +1,8 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; -import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; @@ -30,10 +25,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.InputStream; -import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -73,8 +66,8 @@ public class TestController { @RepeatSubmit @GetMapping("/test") - public void test(@RequestParam String processInstanceId) { - List flowElements = forecastService.performProcessForecasting(processInstanceId, null); + public void test(@RequestParam String processInstanceId, @RequestParam(required = false) String taskDefinitionKey, @RequestParam(required = false) Boolean containSelf) { + List flowElements = forecastService.performProcessForecasting(processInstanceId, null, taskDefinitionKey, containSelf); System.out.println("flowElements = " + flowElements); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index 173adfd8b..2da69ca63 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -1,5 +1,8 @@ package cn.axzo.workflow.server.controller.web.bpmn; +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.PersonProfileQueryReq; +import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; @@ -8,12 +11,14 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCar import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.HistoricProcessInstanceVO; @@ -27,7 +32,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.history.HistoricProcessInstance; -import org.springframework.cache.annotation.CachePut; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -44,7 +48,10 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -59,6 +66,8 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { @Resource private BpmnProcessInstanceService bpmnProcessInstanceService; + @Resource + private FlowSupportApi flowSupportApi; /** * 超管查询所有流程实例 @@ -94,6 +103,13 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { @RepeatSubmit public CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) { log.info("发起审核createProcessInstance===>>>参数:{}", JSONUtil.toJsonStr(dto)); + long personId = Long.parseLong(Optional.ofNullable(dto.getInitiator().getPersonId()).orElse("-1")); + Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), + "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() + .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); + if (personMap.containsKey(personId)) { + dto.getInitiator().setAvatar(personMap.getOrDefault(personId, "")); + } return success(bpmnProcessInstanceService.createProcessInstance(dto)); } @@ -272,7 +288,7 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { public CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) { HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId, - tenantId, true); + tenantId, true); return success(processInstance.getProcessVariables()); } @@ -305,10 +321,24 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { * @return true 是在当前流程实例中,存在指定的审批人 */ @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") - @PostMapping("/api/process/instance/check/approver") + @PostMapping("/check/approver") @Override public CommonResponse checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto) { log.info("校验指定流程实例下,是否存在指定的审批人 checkInstanceApprover===>>>参数:{}", dto); return success(bpmnProcessInstanceService.checkInstanceApprover(dto)); } + + /** + * 获取指定流程实例的日志 + * + * @param dto + * @return + */ + @Operation(summary = "获取指定流程实例的日志") + @PostMapping("/log") + @Override + public CommonResponse getProcessInstanceLog(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto) { + log.info("获取指定流程实例的日志 getProcessInstanceLog===>>>参数:{}", JSONUtil.toJsonStr(dto)); + return success(bpmnProcessInstanceService.getProcessInstanceLog(dto)); + } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 096805280..d42ac86f1 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -1,5 +1,8 @@ package cn.axzo.workflow.server.controller.web.bpmn; +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.PersonProfileQueryReq; +import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi; import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; @@ -11,6 +14,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; @@ -46,7 +50,10 @@ import javax.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -61,7 +68,8 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @Resource private BpmnProcessTaskService bpmnProcessTaskService; - + @Resource + private FlowSupportApi flowSupportApi; /** * 待审核列表 @@ -142,6 +150,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @RepeatSubmit @Override public CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto) { + log.info("回退 backTask===>>>参数:{}", JSON.toJSONString(dto)); bpmnProcessTaskService.backTask(dto); return success(true); } @@ -180,6 +189,15 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @RepeatSubmit public CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto) { log.info("转交任务 transferTask===>>>参数:{}", JSON.toJSONString(dto)); + + long personId = Long.parseLong(Optional.ofNullable(dto.getTargetAssigner().getPersonId()).orElse("-1")); + Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), + "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() + .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); + if (personMap.containsKey(personId)) { + dto.getTargetAssigner().setAvatar(personMap.getOrDefault(personId, "")); + } + bpmnProcessTaskService.transferTask(dto); return success(true); } @@ -216,6 +234,21 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @RepeatSubmit public CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) { log.info("加签任务 countersignTask===>>>参数:{}", JSON.toJSONString(countersignDTO)); + + List personIds = countersignDTO.getTargetAssignerList().stream().filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) + .map(BpmnTaskDelegateAssigner::getPersonId) + .map(Long::parseLong) + .distinct().collect(Collectors.toList()); + Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), + "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds).stream() + .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); + countersignDTO.getTargetAssignerList().forEach(e -> { + long personId = Long.parseLong(Optional.ofNullable(e.getPersonId()).orElse("-1")); + if (personMap.containsKey(personId)) { + e.setAvatar(personMap.getOrDefault(personId, "")); + } + }); + bpmnProcessTaskService.countersignTask(countersignDTO); return success(true); } From 89e33fb7666551d8080b243cc6493a7db876d492 Mon Sep 17 00:00:00 2001 From: wangli Date: Sun, 8 Sep 2024 14:57:12 +0800 Subject: [PATCH 026/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=EF=BC=8C=E5=B9=B6=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E5=A4=96=E9=83=A8=E6=9F=A5=E8=AF=A2=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E7=9A=84=E8=81=9A=E5=90=88=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 2 - .../client/feign/bpmn/ProcessInstanceApi.java | 4 +- .../process/BpmnProcessInstanceLogVO.java | 12 +- .../bpmn/task/BpmnTaskInstanceLogVO.java | 4 + .../core/engine/cmd/CustomApproveTaskCmd.java | 2 +- .../engine/cmd/CustomRejectionTaskCmd.java | 2 +- .../listener/AutoPassTransactionListener.java | 2 +- .../impl/BpmnProcessInstanceServiceImpl.java | 219 +++++++++++++++--- workflow-engine-server/pom.xml | 13 +- .../server/WorkflowEnginApplication.java | 5 +- .../server/common/util/RpcExternalUtil.java | 114 +++++++++ .../AbstractBpmnTaskAssigneeSelector.java | 56 +---- .../bpmn/BpmnProcessInstanceController.java | 44 +++- .../web/bpmn/BpmnProcessTaskController.java | 6 +- .../starter/api/WorkflowCoreService.java | 13 ++ 15 files changed, 379 insertions(+), 119 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RpcExternalUtil.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 1f319c9c4..166b5ea57 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -1,10 +1,8 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; -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; diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index 465d79c4f..aa14705d7 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -249,7 +249,7 @@ public interface ProcessInstanceApi { * @return */ @Operation(summary = "获取指定流程的日志") - @PostMapping("/api/process/instance/log") + @PostMapping("/api/process/instance/logs") @InvokeMode(SYNC) - CommonResponse getProcessInstanceLog(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); + CommonResponse getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java index 4d2ad7731..aa580364d 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.common.model.response.bpmn.process; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.WorkspaceType; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceLogVO; import io.swagger.annotations.ApiModel; @@ -109,7 +110,7 @@ public class BpmnProcessInstanceLogVO { * 任务信息集合 */ @ApiModelProperty("任务信息集合") - private List tasks; + private List taskDetails; /** * 当前实例对应模型的全局兜底按钮配置 @@ -117,6 +118,12 @@ public class BpmnProcessInstanceLogVO { @ApiModelProperty(value = "当前实例对应模型的全局兜底按钮配置") private BpmnButtonConf defaultButtonConf; + /** + * 指定人访问实例日志时,计算其流程应该有权限操作的按钮 + */ + @ApiModelProperty(value = "指定人访问实例日志时,计算其流程应该有权限操作的按钮", notes = "流程有权限,不代表待办消息中一定能看到按钮") + private List currentUserButtons; + /** * 是否支持批量审批 */ @@ -140,4 +147,7 @@ public class BpmnProcessInstanceLogVO { */ @ApiModelProperty(value = "工作台类型") private WorkspaceType workspaceType; + + @ApiModelProperty(value = "程序计算按钮使用,非对外使用", hidden = true) + private transient BpmnButtonConf calculatingButtonConf; } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java index 32172360a..2c191b8d4 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.ApprovalMethodEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; @@ -117,6 +118,9 @@ public class BpmnTaskInstanceLogVO { @ApiModelProperty(value = "未完成节点多实例模式的审批人信息") private List forecastAssignees; + @ApiModelProperty(value = "程序计算按钮使用,非对外使用", hidden = true) + private transient BpmnButtonConf buttonConf; + public boolean isVirtual() { return StringUtils.isBlank(this.taskId); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index 4e4720113..fe3aca1e0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -101,7 +101,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria if (Objects.nonNull(operationDesc)) { this.operationDesc = operationDesc; } else { - this.operationDesc = "已通过"; + this.operationDesc = "(已通过)"; } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 2ee944c96..9dc1225a3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -69,7 +69,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser if (Objects.nonNull(operationDesc)) { this.operationDesc = operationDesc; } else { - this.operationDesc = "已驳回"; + this.operationDesc = "(已驳回)"; } this.attachmentList = dto.getAttachmentList(); this.approver = dto.getApprover(); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AutoPassTransactionListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AutoPassTransactionListener.java index 886585c98..f6f7b4259 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AutoPassTransactionListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/tx/listener/AutoPassTransactionListener.java @@ -59,7 +59,7 @@ public class AutoPassTransactionListener implements TransactionListener { pass.setTaskId(delegateTask.getId()); pass.setAdvice(advice); pass.setApprover(assigner); - pass.setOperationDesc("自动通过"); + pass.setOperationDesc("(自动通过)"); String jobId = commandExecutor.execute(commandConfig, new CustomApproveTaskAsyncCmd(pass)); // 重置任务,因为上面的 cmd 和这个 cmd 的 lock 对象不一致 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 46fa043d0..98be35bf1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -9,6 +9,7 @@ import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.WorkspaceType; import cn.axzo.workflow.common.model.request.BpmnApproveConf; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; @@ -123,6 +124,10 @@ import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_S import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CARBON_COPY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_CURRENT; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_HISTORY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_TYPE_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.CREATE_INSTANCE_PARAMS; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; @@ -139,8 +144,14 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.EXCEPTIONAL; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL; import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CARBON_COPY; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.common.enums.WorkspaceType.GOVERNMENT; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; @@ -1050,7 +1061,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)))) .tenantId(historicProcessInstance.getTenantId()) .agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false)) - .tasks(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting)) + .taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto.getEncrypt())) .defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf())) .supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation()) .userAgreeSignature(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getUserAgreeSignature()) @@ -1062,15 +1073,183 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic logVO.setWorkspaceType(WorkspaceType.getType(Integer.valueOf(category.getWorkspaceTypeCode()))); logVO.setCategory(category.getValue()); }); + + // 根据传入的访问人计算有权限的按钮 + calcAuthorizedButtons(logVO, dto.getVisitor()); return logVO; } - private List genericTaskLogVos(String processInstanceId, List logs, List forecasting) { + private void calcAuthorizedButtons(BpmnProcessInstanceLogVO logVO, BpmnTaskDelegateAssigner visitor) { + List authorizedButtons = new ArrayList<>(); + if (Objects.nonNull(logVO.getDefaultButtonConf()) + && CollectionUtils.isEmpty(logVO.getDefaultButtonConf().getCarbonCopy())) { + authorizedButtons.addAll(logVO.getDefaultButtonConf().getCarbonCopy()); + } + + if (Objects.equals(PROCESSING, logVO.getResult())) { + String ge130Assignee = getGe130Assignee(visitor); + String le130Assignee = getLe130Assignee(visitor); + + // 运行到的当前节点的按钮配置 + logVO.getTaskDetails().stream() + .filter(i -> Objects.equals(PROCESSING, i.getResult())) + .findFirst() + .ifPresent(i -> logVO.setCalculatingButtonConf(i.getButtonConf())); + + + // 比对发起人 + if (Objects.nonNull(logVO.getInitiator()) && + (Objects.equals(logVO.getInitiator().buildAssigneeId_1_2_1(), le130Assignee) + || logVO.getInitiator().buildAssigneeId().contains(ge130Assignee))) { + authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_INITIATOR)); + } + + + // 比对当前审批人 + logVO.getTaskDetails().stream().filter(i -> Objects.equals(PROCESSING, i.getResult()) + || (Objects.equals(DELETED, i.getResult()) && Objects.isNull(i.getEndTime()))) + .findFirst() + .map(i -> { + List list = new ArrayList<>(); + if (Objects.nonNull(i.getAssigneeSnapshot())) { + list.add(i.getAssigneeSnapshot()); + } + if (!CollectionUtils.isEmpty(i.getForecastAssignees())) { + list.addAll(i.getForecastAssignees()); + } + return list; + }) + .orElse(Collections.emptyList()) + .stream() + .filter(Objects::nonNull) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CURRENT))); + + + // 比对历史审批人 + logVO.getTaskDetails().stream() + .filter(i -> Objects.equals(i.getNodeType(), NODE_TASK) || Objects.equals(i.getNodeType(), NODE_BUSINESS)) + .filter(i -> !Objects.equals(PROCESSING, i.getResult())) + .map(BpmnTaskInstanceLogVO::getAssigneeSnapshot) + .filter(Objects::nonNull) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_HISTORY))); + + // 比对抄送人 + logVO.getTaskDetails().stream() + .filter(i -> Objects.equals(i.getNodeType(), NODE_CARBON_COPY)) + .flatMap(i -> i.getForecastAssignees().stream()) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CARBON_COPY))); + } + logVO.setCurrentUserButtons(authorizedButtons); + } + + /** + * 按钮的通用处理, 有限使用节点的按钮配置,如果没有则按兜底按钮配置 + * + * @param logVO 该对象中的 calcButtonConf 字段为当前节点的按钮配置 + * @param buttonConfigName String CONFIG_BUTTON_TYPE_INITIATOR = "initiator"; + * String CONFIG_BUTTON_TYPE_CURRENT = "current"; + * String CONFIG_BUTTON_TYPE_HISTORY = "history"; + * String CONFIG_BUTTON_TYPE_CARBON_COPY = "carbonCopy"; + * @return + */ + private List chooseButtons(BpmnProcessInstanceLogVO logVO, String buttonConfigName) { + List mergeButtons = new ArrayList<>(); + if (Objects.isNull(logVO.getCalculatingButtonConf())) { + BpmnButtonConf defaultButtonConf = logVO.getDefaultButtonConf(); + if (Objects.isNull(defaultButtonConf)) { + return mergeButtons; + } + logVO.setCalculatingButtonConf(defaultButtonConf); + } + switch (buttonConfigName) { + case CONFIG_BUTTON_TYPE_INITIATOR: + mergeButtons.addAll(logVO.getCalculatingButtonConf().getInitiator()); + break; + case CONFIG_BUTTON_TYPE_CURRENT: + mergeButtons.addAll(logVO.getCalculatingButtonConf().getCurrent()); + break; + case CONFIG_BUTTON_TYPE_HISTORY: + mergeButtons.addAll(logVO.getCalculatingButtonConf().getHistory()); + break; + case CONFIG_BUTTON_TYPE_CARBON_COPY: + mergeButtons.addAll(logVO.getCalculatingButtonConf().getCarbonCopy()); + break; + default: + break; + } + return mergeButtons; + } + + public static String getLe130Assignee(BpmnTaskDelegateAssigner visitor) { + return visitor.getTenantId() + "|" + visitor.getAssignee() + "|" + visitor.getAssigneeType(); + } + + public static String getGe130Assignee(BpmnTaskDelegateAssigner visitor) { + // String ge130Assignee = contextInfo.getOuId() + "|" + contextInfo.getUserInfo().getPersonId(); + // 130版本以上,产品要求仅校验 personId + return "|" + visitor.getPersonId(); + } + + private List genericTaskLogVos(String processInstanceId, + List logs, + List forecasting, + Boolean encrypt) { List tasks = new ArrayList<>(); Map> attachmentByTaskMap = taskService.getProcessInstanceAttachments(processInstanceId).stream() .collect(Collectors.groupingBy(Attachment::getTaskId)); // 已完成的和进行中的 + getHistoricTasks(logs, tasks, attachmentByTaskMap); + // 未来节点 + getFutureTasks(forecasting, tasks); + // 处理是否加密 + handleEncrypt(encrypt, tasks); + return tasks; + } + + private static void handleEncrypt(Boolean encrypt, List tasks) { + if (!encrypt) { + return; + } + tasks.forEach(i -> { + if (Objects.equals(NODE_STARTER.getType(), i.getTaskDefinitionKey())) { + i.setOperationDesc(i.getAssigneeSnapshot().getAssignerName()); + } else if (Objects.equals(i.getResult(), APPROVED)) { + i.setOperationDesc(APPROVED.getDesc()); + } else if (Objects.equals(i.getResult(), REJECTED)) { + i.setOperationDesc(REJECTED.getDesc()); + } else if (Objects.equals(i.getResult(), PROCESSING) || Objects.isNull(i.getTaskId())) { + i.setOperationDesc("待处理"); + } else { + i.setOperationDesc("已处理"); + } + // 统一将多人节点数据全部置空 + i.setForecastAssignees(Collections.emptyList()); + // 统一将签名数据置空 + i.setSignatureUrl(null); + }); + } + + private static void getFutureTasks(List forecasting, List tasks) { + ListUtils.emptyIfNull(forecasting).forEach(e -> { + tasks.add(BpmnTaskInstanceLogVO.builder() + .taskDefinitionKey(e.getId()) + .name(e.getName()) + .approvalMethod(e.getApprovalMethod()) + .nodeType(e.getNodeType()) + .nodeMode(e.getNodeMode()) + .forecastAssignees(e.getForecastAssigners()) + .build()); + }); + } + + private void getHistoricTasks(List logs, List tasks, Map> attachmentByTaskMap) { ListUtils.emptyIfNull(logs).forEach(e -> { Optional processingTask = tasks.stream().filter(i -> Objects.equals(PROCESSING, i.getResult())) .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); @@ -1104,31 +1283,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? e.getAssigneeFull() : Collections.emptyList()) .build()); } + }); - }); - // 未来节点 - ListUtils.emptyIfNull(forecasting).forEach(e -> { - tasks.add(BpmnTaskInstanceLogVO.builder() -// .taskId(e.getTaskId()) - .taskDefinitionKey(e.getId()) - .name(e.getName()) -// .createTime(e.getStartTime()) -// .endTime(e.getEndTime()) - .approvalMethod(e.getApprovalMethod()) - .nodeType(e.getNodeType()) - .nodeMode(e.getNodeMode()) -// .result(BpmnProcessInstanceResultEnum.valueOfStatus(e.getStatus())) -// .operationDesc(e.getOperationDesc()) -// .advice(e.getAdvice()) -// .commentExt("") -// .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) -// .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) -// .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) -// .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))) - .forecastAssignees(e.getForecastAssigners()) - .build()); - }); - return tasks; } public List getAttachmentByType(Map> attachmentByTaskMap, String taskId, AttachmentTypeEnum type) { @@ -1144,15 +1300,4 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .collect(Collectors.toList()); } -// List attachments = task.getAttachments(); -// // 图片 -// List imageList = attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.image, attachment.getType())).collect(Collectors.toList()); -// detail.setImageList(imageList); -// // 附件 -// List fileList = attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.file, attachment.getType())).collect(Collectors.toList()); -// detail.setFileList(fileList); -// // 手写签名 -// attachments.stream().filter(attachment -> Objects.equals(AttachmentTypeEnum.signature, attachment.getType())).findAny().ifPresent(i -> detail.setSignatureUrl(i.getUrl())); - - } diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index afb7ae83a..8b5c81251 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -21,10 +21,6 @@ 3.25.0 - cn.axzo.framework axzo-web-spring-boot-starter @@ -75,7 +71,6 @@ mysql mysql-connector-java - cn.axzo.framework axzo-processor-spring-boot-starter @@ -100,14 +95,14 @@ cn.axzo.maokai maokai-api - - - - cn.axzo.karma karma-api + + cn.axzo.oss + oss-http-api + com.aliyun alibaba-dingtalk-service-sdk diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java index 697702527..1e1d7729a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java @@ -1,17 +1,18 @@ package cn.axzo.workflow.server; -import liquibase.pro.packaged.E; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement; @MapperScan({"cn.axzo.workflow.core.**.mapper"}) -@ComponentScan({"cn.axzo.workflow", "cn.axzo.maokai"}) +@ComponentScan({"cn.axzo.workflow"}) +@EnableFeignClients("cn.axzo.oss") @SpringBootApplication(exclude = RabbitAutoConfiguration.class) @EnableTransactionManagement @EnableCaching diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RpcExternalUtil.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RpcExternalUtil.java new file mode 100644 index 000000000..36a99bede --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/RpcExternalUtil.java @@ -0,0 +1,114 @@ +package cn.axzo.workflow.server.common.util; + +import cn.axzo.apollo.core.web.Result; +import cn.axzo.basics.common.util.AssertUtil; +import cn.axzo.framework.domain.ServiceException; +import cn.axzo.framework.domain.web.result.ApiListResult; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.azxo.framework.common.model.CommonResponse; +import cn.hutool.core.date.StopWatch; +import cn.hutool.core.lang.Assert; +import cn.hutool.http.HttpStatus; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * 外部rpc接口 返回 CommonResponse + * + * @author tanjie@axzo.cn + * @date 2022/5/23 11:08 + */ +@Slf4j +public class RpcExternalUtil { + + /** + * 常用的RPC请求返回值解析,如果 被请求方 返回非200会抛出异常 + */ + public static T rpcProcessor(Supplier> supplier, String operationType, Object... param) { + + return rpcProcessorMayThrow(supplier, operationType, commonResponse -> { + throw new ServiceException(commonResponse.getMsg()); + }, param); + } + + public static T rpcApolloProcessor(Supplier> supplier, String operationType, Object... param) { + log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param)); + Result result = printLatency(supplier, operationType); + log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result)); + Assert.notNull(result, "服务调用异常"); + Assert.isTrue(result.getCode() == 200, "服务调用异常:" + result.getMsg()); + return result.getData(); + } + + public static T rpcApiResultProcessor(Supplier> supplier, String operationType, Object... param) { + log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param)); + ApiResult result = printLatency(supplier, operationType); + log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result)); + Assert.notNull(result, "服务调用异常"); + Assert.isTrue(result.getCode() == 200, "服务调用异常:" + result.getMsg()); + return result.getData(); + } + + /** + * 常用的RPC请求返回值解析,如果 被请求方 返回非200会抛出异常 + * + * @param supplier ApiListResult类型的RPC接口 + * @param operationType 接口方法描述 + * @param param 接口入参 + * @return 接口返回值 + */ + public static List rpcApiListResultProcessor(Supplier> supplier, String operationType, Object... param) { + log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param)); + ApiListResult result = printLatency(supplier, operationType); + log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result)); + Assert.notNull(result, "服务调用异常"); + Assert.isTrue(result.isSuccess(), "服务调用异常:" + result.getMsg()); + return result.getData(); + } + + public static T rpcProcessorMayThrow(Supplier> supplier, String operationType, Consumer> throwConsumer, Object... param) { + AssertUtil.notNull(throwConsumer, "自定义的异常处理不可为空"); + log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param)); + CommonResponse result = printLatency(supplier, operationType); + log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result)); + + Assert.notNull(result, "服务调用异常"); + // 200自定义处理 + if (HttpStatus.HTTP_OK != result.getCode()) { + throwConsumer.accept(result); + } + return result.getData(); + } + + public static R printLatency(Supplier function, String optType) { + StopWatch stopWatch = new StopWatch(optType); + stopWatch.start(optType); + R r = function.get(); + stopWatch.stop(); + log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS)); + return r; + } + + + public static T rpcProfileProcessor(Supplier> supplier, String operationType, Object... param) { + log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param)); + StopWatch stopWatch = new StopWatch(operationType); + stopWatch.start(operationType); + CommonResponse result = supplier.get(); + stopWatch.stop(); + log.info("-Result: " + JSONUtil.toJsonStr(result)); + log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS)); + Assert.notNull(result, "服务调用异常"); + // 200自定义处理 + if (HttpStatus.HTTP_OK != result.getCode() && 404 != result.getCode()) { + throw new ServiceException(result.getMsg()); + } + + return result.getData(); + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 38833c963..af15e04bc 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -38,7 +38,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -116,27 +115,9 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return Collections.emptyList(); } - public static T parseApiResult(Supplier> supplier, String operatorDesc, - String extInfo, Object... param) { - StopWatch stopWatch = new StopWatch(operatorDesc); - log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); - stopWatch.start(); - ApiResult result = supplier.get(); - stopWatch.stop(); - log.info("{}-Cost:{}, Result: {}", operatorDesc, - "API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's", - JSONUtil.toJsonStr(result)); - Assert.notNull(result, "服务调用异常"); - // 200自定义处理 - if (HttpStatus.HTTP_OK != result.getCode()) { - throw new WorkflowEngineException(CALC_TASK_ASSIGNEE_ERROR, "[API:" + extInfo + "]" + result.getMsg()); - } - return result.getData(); - } - protected final T parseApiResult(Supplier> supplier, String operatorDesc, - String extInfo, Consumer> consumer, Object... param) { + String extInfo, Object... param) { StopWatch stopWatch = new StopWatch(operatorDesc); log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); stopWatch.start(); @@ -229,39 +210,4 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign executionStartListener = applicationContext.getBean(EngineExecutionStartListener.class); } - static class ParseConsumer { - private String extInfo; - private ApiResult result; - private Object[] params; - - public ParseConsumer(String extInfo, ApiResult result, Object[] params) { - this.extInfo = extInfo; - this.result = result; - this.params = params; - } - - public String getExtInfo() { - return extInfo; - } - - public void setExtInfo(String extInfo) { - this.extInfo = extInfo; - } - - public ApiResult getResult() { - return result; - } - - public void setResult(ApiResult result) { - this.result = result; - } - - public Object[] getParams() { - return params; - } - - public void setParams(Object[] params) { - this.params = params; - } - } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index 2da69ca63..6f50246cb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -3,6 +3,9 @@ package cn.axzo.workflow.server.controller.web.bpmn; import cn.axzo.karma.client.feign.FlowSupportApi; import cn.axzo.karma.client.model.request.PersonProfileQueryReq; import cn.axzo.karma.client.model.response.PersonProfileResp; +import cn.axzo.oss.http.api.ServerFileServiceApi; +import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest; +import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; @@ -23,15 +26,20 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePa import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.HistoricProcessInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceLogVO; import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.azxo.framework.common.model.CommonResponse; import cn.hutool.json.JSONUtil; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.ListUtils; import org.flowable.engine.history.HistoricProcessInstance; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -48,10 +56,10 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -68,6 +76,8 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { private BpmnProcessInstanceService bpmnProcessInstanceService; @Resource private FlowSupportApi flowSupportApi; + @Resource + private ServerFileServiceApi serverFileServiceApi; /** * 超管查询所有流程实例 @@ -104,7 +114,7 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { public CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) { log.info("发起审核createProcessInstance===>>>参数:{}", JSONUtil.toJsonStr(dto)); long personId = Long.parseLong(Optional.ofNullable(dto.getInitiator().getPersonId()).orElse("-1")); - Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), + Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); if (personMap.containsKey(personId)) { @@ -335,10 +345,34 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { * @return */ @Operation(summary = "获取指定流程实例的日志") - @PostMapping("/log") + @PostMapping("/logs") @Override - public CommonResponse getProcessInstanceLog(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto) { + public CommonResponse getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto) { log.info("获取指定流程实例的日志 getProcessInstanceLog===>>>参数:{}", JSONUtil.toJsonStr(dto)); - return success(bpmnProcessInstanceService.getProcessInstanceLog(dto)); + BpmnProcessInstanceLogVO log = bpmnProcessInstanceService.getProcessInstanceLog(dto); + parseSignatureUrl(log); + return success(log); + } + + private void parseSignatureUrl(BpmnProcessInstanceLogVO log) { + List signUrls = log.getTaskDetails().stream() + .filter(i -> StringUtils.hasText(i.getTaskId())) + .map(BpmnTaskInstanceLogVO::getSignatureUrl) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(signUrls)) { + Map ossUrlMap = ListUtils.emptyIfNull(getSignPrivateUrl(signUrls)).stream() + .collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, ApiSignUrlDownloadResponse::getSignUrl, (s, t) -> s)); + log.getTaskDetails().stream() + .filter(i -> StringUtils.hasText(i.getTaskId())) + .forEach(i -> i.setSignatureUrl(ossUrlMap.getOrDefault(i.getSignatureUrl(), null))); + } + } + + private List getSignPrivateUrl(List signUrls) { + ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest(); + request.setFileKeys(signUrls); + return RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(request), "批量获取手写签私有访问地址", request); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index d42ac86f1..257aaeb53 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -28,6 +28,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import cn.axzo.workflow.core.service.BpmnProcessTaskService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; @@ -53,7 +54,6 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -191,7 +191,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { log.info("转交任务 transferTask===>>>参数:{}", JSON.toJSONString(dto)); long personId = Long.parseLong(Optional.ofNullable(dto.getTargetAssigner().getPersonId()).orElse("-1")); - Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), + Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); if (personMap.containsKey(personId)) { @@ -239,7 +239,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi { .map(BpmnTaskDelegateAssigner::getPersonId) .map(Long::parseLong) .distinct().collect(Collectors.toList()); - Map personMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), + Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds).stream() .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); countersignDTO.getTargetAssignerList().forEach(e -> { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index b9074162b..b82850ce8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbo import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; @@ -16,6 +17,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; @@ -150,6 +152,17 @@ public interface WorkflowCoreService { @InvokeMode(SYNC) Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + /** + * 获取指定流程的日志 + * + * @param dto + * @return + */ + @Operation(summary = "获取指定流程的日志") + @PostMapping("/api/process/instance/logs") + @InvokeMode(SYNC) + BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); + /** * 同意 * From a6ad973e8587ecd4120e1b91e0bb5d94f39cd838 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 09:26:59 +0800 Subject: [PATCH 027/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E7=9A=84=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 706c8af42..3cb67d09b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -40,7 +40,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ private final BpmnTaskBackAuditDTO dto; - private static String operationDesc = "已回退"; + private static String operationDesc = "回退至"; @Override public String paramToJsonString() { From ed659a858b80fd7396269f9ff84d0ec887f40627 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 09:56:04 +0800 Subject: [PATCH 028/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E9=80=BB=E8=BE=91=EF=BC=8C=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E7=89=B9=E6=AE=8A=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 98be35bf1..2b1603062 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1258,7 +1258,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic processingTask.ifPresent(i -> { List assigners = new ArrayList<>(); assigners.add(i.getAssigneeSnapshot()); - assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))); + assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))); i.setAssigneeSnapshot(null); i.setForecastAssignees(assigners); }); @@ -1279,8 +1279,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) - .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : BpmnTaskDelegateAssigner.toObjectCompatible(e.getAssigneeFull().get(0))) - .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? e.getAssigneeFull() : Collections.emptyList()) + .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : + BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))) + .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? ListUtils.emptyIfNull(e.getAssigneeFull()) : Collections.emptyList()) .build()); } }); From e9d6a2306145150feb617ed7ad075a5d578603c9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 09:56:47 +0800 Subject: [PATCH 029/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E6=96=B0=E7=94=9F=E6=88=90=E7=9A=84=20Starter=20Service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 75 +++++++++------ .../starter/api/WorkflowManageService.java | 92 +++++++++++-------- 2 files changed, 103 insertions(+), 64 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index b82850ce8..7edf39e23 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,42 +1,63 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; -import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; 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 javax.annotation.Nullable; import javax.validation.constraints.NotBlank; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PutMapping; +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; - -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import org.springframework.cloud.openfeign.FeignClient; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import javax.validation.constraints.NotEmpty; /** * Workflow Engine Starter Core Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index be5f34628..24962a1a6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,63 +1,81 @@ package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; -import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; +import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import java.util.List; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; +import javax.annotation.Nullable; +import java.util.Map; import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import org.springframework.web.bind.annotation.PathVariable; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryItemVO; -import cn.axzo.workflow.common.util.ThreadUtil; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.annotation.Nullable; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.Map; - -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; /** * Workflow Engine Starter Management Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 From 7461a81aa390ed4afc15955feb2a8e657e9c8e9f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 10:04:49 +0800 Subject: [PATCH 030/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20Starter=20=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E7=9A=84=20Fe?= =?UTF-8?q?ignClient=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/support/api/CoreServiceCodeGeneration.java | 4 ++-- .../workflow/support/api/ManageServiceCodeGeneration.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index bb486ff9e..ec975d1e7 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -168,11 +168,11 @@ public class CoreServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); - classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service
" + + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service\r\n

\r\n" + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index c5ceff26b..834cd0dfb 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -158,11 +158,11 @@ public class ManageServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); - classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service
" + + classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service\r\n

\r\n" + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:workflow-engine:8080}")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine.starter:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); From 17a88044d096a3ec3e5d80467b995f3d0efb3c14 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 10:06:02 +0800 Subject: [PATCH 031/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20FeignClient=20=E9=85=8D=E7=BD=AE=E5=90=8E=EF=BC=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90=20Starter=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/api/WorkflowCoreService.java | 6 ++++-- .../cn/axzo/workflow/starter/api/WorkflowManageService.java | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 7edf39e23..2b5bded14 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -60,9 +60,11 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import javax.validation.constraints.NotEmpty; /** - * Workflow Engine Starter Core Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + * Workflow Engine Starter Core Service + *

+ * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ -@FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 24962a1a6..f2e08ac0e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -78,9 +78,11 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionP import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; /** - * Workflow Engine Starter Management Service
该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + * Workflow Engine Starter Management Service + *

+ * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ -@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine:workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine.starter:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { /** From 0cdccce1200677411117e64b267a95109e252fd5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 11:19:14 +0800 Subject: [PATCH 032/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20FeignClient=20=E9=85=8D=E7=BD=AE=E5=90=8E=EF=BC=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90=20Starter=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/starter/api/WorkflowManageService.java | 2 +- .../axzo/workflow/support/api/ManageServiceCodeGeneration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index f2e08ac0e..d3b3d564a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -82,7 +82,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinition *

* 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ -@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine.starter:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { /** diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index 834cd0dfb..db51d4146 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -162,7 +162,7 @@ public class ManageServiceCodeGeneration { "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine.starter:8080}")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); From 7d6561cb9fac899a27839226169e95e7ff7f2787 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 15:06:20 +0800 Subject: [PATCH 033/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20Activity=20Service=20=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E9=A3=8E=E6=A0=BC=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessActivityApi.java | 13 ++- .../bpmn/task/BpmnActivitySetAssigneeDTO.java | 1 - .../bpmn/task/BpmnActivityTriggerDTO.java | 37 +++++++ .../core/conf/FlowableConfiguration.java | 22 ++-- .../CustomAbortProcessInstanceAsyncCmd.java | 6 +- .../cmd/CustomActivityTriggerAsyncCmd.java | 85 +++++++++++++++ .../engine/cmd/CustomActivityTriggerCmd.java | 51 +++++++++ ...ustomBizSpecifyAssigneeToTaskAsyncCmd.java | 102 ++++++++++++++++++ .../CustomBizSpecifyAssigneeToTaskCmd.java | 4 +- .../CustomCancelProcessInstanceAsyncCmd.java | 6 +- .../cmd/CustomCommandContextFactory.java | 2 +- ... AsyncAbortProcessInstanceJobHandler.java} | 4 +- .../AsyncActivitySetAssigneeJobHandler.java | 37 +++++++ .../job/AsyncActivityTriggerJobHandler.java | 37 +++++++ .../AsyncBpmnProcessActivityJobHandler.java | 31 ------ ...AsyncCancelProcessInstanceJobHandler.java} | 4 +- .../service/BpmnProcessActivityService.java | 25 +---- .../impl/BpmnProcessActivityServiceImpl.java | 95 +++------------- .../bpmn/BpmnProcessActivityController.java | 55 +++++----- 19 files changed, 433 insertions(+), 184 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivityTriggerDTO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerAsyncCmd.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskAsyncCmd.java rename workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/{AsyncAbortProcessInstanceHandler.java => AsyncAbortProcessInstanceJobHandler.java} (88%) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivitySetAssigneeJobHandler.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java delete mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBpmnProcessActivityJobHandler.java rename workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/{AsyncCancelProcessInstanceHandler.java => AsyncCancelProcessInstanceJobHandler.java} (89%) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 166b5ea57..83840e58b 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; @@ -21,13 +22,23 @@ import javax.validation.constraints.NotBlank; public interface ProcessActivityApi { /** - * 业务节点唤醒 + * 业务节点唤醒, 该节点废弃,请换成 {@link ProcessActivityApi#trigger(cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO)} 接口 *

* 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行 */ + @Deprecated @GetMapping("/api/process/activity/trigger") CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); + /** + * 业务节点唤醒 + * + * @param dto + * @return + */ + @PostMapping("/api/process/activity/trigger") + CommonResponse trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto); + /** * 业务节点设置审批人, 不支持重复设置 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java index 6f5a22aff..14ab875fe 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivitySetAssigneeDTO.java @@ -53,7 +53,6 @@ public class BpmnActivitySetAssigneeDTO { * 业务如果传入的 assigners 集合为空, 引擎则会对该流程进行自动驳回处理,且驳回意见为“业务未指定审批人” */ @ApiModelProperty(value = "审批人集合信息", notes = "业务传参时,需要注意去重") - @Valid @Size(max = 60, message = "指定审批人数量限制为60") private List assigners; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivityTriggerDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivityTriggerDTO.java new file mode 100644 index 000000000..8165317fe --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnActivityTriggerDTO.java @@ -0,0 +1,37 @@ +package cn.axzo.workflow.common.model.request.bpmn.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 推动业务节点继续执行 + * + * @author wangli + * @since 2024-09-09 13:46 + */ +@ApiModel("业务节点设置审批人") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BpmnActivityTriggerDTO { + + /** + * 业务节点的触发 ID + */ + @NotBlank(message = "触发 ID 不能为空") + @ApiModelProperty(value = "触发 ID", notes = "数据来源于事件") + private String triggerId; + + /** + * 是否异步执行 + */ + @ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据") + private Boolean async = true; +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index b2d0216c5..6abda0f35 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -5,10 +5,12 @@ import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; import cn.axzo.workflow.core.engine.interceptor.CustomRetryInterceptor; -import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; +import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncActivitySetAssigneeJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncActivityTriggerJobHandler; import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; -import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler; -import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceHandler; +import cn.axzo.workflow.core.engine.job.AsyncBackTaskJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceJobHandler; import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler; import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler; import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler; @@ -81,14 +83,16 @@ public class FlowableConfiguration { configuration.setIdGenerator(new BasedNacosSnowflakeIdGenerator(nacosServiceManager, nacosDiscoveryProperties)); configuration.setHistoricProcessInstanceDataManager(new CustomMybatisHistoricProcessInstanceDataManager(configuration)); // 自定义的异步任务处理器 + configuration.addCustomJobHandler(new AsyncAbortProcessInstanceJobHandler(extAxHiTaskInstService)); + configuration.addCustomJobHandler(new AsyncActivitySetAssigneeJobHandler()); + configuration.addCustomJobHandler(new AsyncActivityTriggerJobHandler()); configuration.addCustomJobHandler(new AsyncApproveTaskJobHandler()); - configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); + configuration.addCustomJobHandler(new AsyncBackTaskJobHandler()); + configuration.addCustomJobHandler(new AsyncCancelProcessInstanceJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncCancelProcessInstanceHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncAbortProcessInstanceHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncBpmnProcessActivityJobHandler(bpmnProcessActivityService)); + configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService)); + configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService)); + configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); // 异步任务异常重试时间间隔 configuration.setDefaultFailedJobWaitTime(30); configuration.setAsyncFailedJobWaitTime(30); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java index ec87d66fa..e11e5ea2f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceAsyncCmd.java @@ -2,7 +2,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; -import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; +import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceJobHandler; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -73,9 +73,9 @@ public class CustomAbortProcessInstanceAsyncCmd extends AbstractCommand im job.setExecutionId(instance.getId()); job.setProcessInstanceId(instance.getId()); job.setProcessDefinitionId(instance.getProcessDefinitionId()); - job.setElementId(AsyncAbortProcessInstanceHandler.TYPE); + job.setElementId(AsyncAbortProcessInstanceJobHandler.TYPE); job.setElementName(instance.getName()); - job.setJobHandlerType(AsyncAbortProcessInstanceHandler.TYPE); + job.setJobHandlerType(AsyncAbortProcessInstanceJobHandler.TYPE); job.setTenantId(instance.getTenantId()); // 携带自定义的数据 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerAsyncCmd.java new file mode 100644 index 000000000..1e194e008 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerAsyncCmd.java @@ -0,0 +1,85 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.engine.job.AsyncActivityTriggerJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.runtime.Execution; +import org.flowable.job.service.JobService; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.Objects; + +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_TRIGGER_NOT_EXISTS; + +/** + * 自定义(异步)流转业务姐弟那的命令器实现 + * + * @author wangli + * @since 2024-09-09 13:58 + */ +public class CustomActivityTriggerAsyncCmd extends AbstractCommand implements Serializable { + + private static final Logger log = LoggerFactory.getLogger(CustomActivityTriggerAsyncCmd.class); + private final BpmnActivityTriggerDTO dto; + + public CustomActivityTriggerAsyncCmd(BpmnActivityTriggerDTO dto) { + this.dto = dto; + } + + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + + @Override + public String execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + Execution execution = runtimeService.createExecutionQuery().executionId(dto.getTriggerId()).singleResult(); + if (Objects.isNull(execution)) { + throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId()); + } + + return startAsync(commandContext); + } + + private String startAsync(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskService taskService = processEngineConfiguration.getTaskService(); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().executionId(dto.getTriggerId()).singleResult(); + JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService(); + + JobEntity job = jobService.createJob(); + // 这里的 executionId 可为 null + job.setExecutionId(task.getExecutionId()); + job.setProcessInstanceId(task.getProcessInstanceId()); + job.setProcessDefinitionId(task.getProcessDefinitionId()); + job.setElementId(task.getTaskDefinitionKey()); + job.setElementName(task.getName()); + job.setJobHandlerType(AsyncActivityTriggerJobHandler.TYPE); + job.setTenantId(task.getTenantId()); + + // 携带自定义的数据 + job.setCustomValues(JSONUtil.toJsonStr(dto)); + + // 创建异步任务并调度 + jobService.createAsyncJob(job, false); + jobService.scheduleAsyncJob(job); + return job.getId(); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java new file mode 100644 index 000000000..687f17fef --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java @@ -0,0 +1,51 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import com.alibaba.fastjson.JSON; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.runtime.Execution; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.Objects; + +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_TRIGGER_NOT_EXISTS; + +/** + * 自定义(同步)流转业务姐弟那的命令器实现 + * + * @author wangli + * @since 2024-09-09 13:58 + */ +public class CustomActivityTriggerCmd extends AbstractCommand implements Serializable { + + private static final Logger log = LoggerFactory.getLogger(CustomActivityTriggerCmd.class); + private final BpmnActivityTriggerDTO dto; + + public CustomActivityTriggerCmd(BpmnActivityTriggerDTO dto) { + this.dto = dto; + } + + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + + @Override + public Void execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + Execution execution = runtimeService.createExecutionQuery().executionId(dto.getTriggerId()).singleResult(); + if (Objects.isNull(execution)) { + throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId()); + } + runtimeService.trigger(dto.getTriggerId()); + return null; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskAsyncCmd.java new file mode 100644 index 000000000..af1e5d076 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskAsyncCmd.java @@ -0,0 +1,102 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; +import cn.axzo.workflow.core.engine.job.AsyncActivitySetAssigneeJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.HistoryService; +import org.flowable.engine.ProcessEngineConfiguration; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobService; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.springframework.util.CollectionUtils; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; +import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; +import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_CANT_SET_ASSIGNEE; +import static cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd.getOperateTask; +import static cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd.validProcessInstance; +import static cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd.validate; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount; + +/** + * 自定的业务指定审批人命令实现 + * + * @author wangli + * @since 2023/12/22 13:51 + */ +public class CustomBizSpecifyAssigneeToTaskAsyncCmd extends AbstractCommand implements Serializable { + + private final BpmnActivitySetAssigneeDTO dto; + + public CustomBizSpecifyAssigneeToTaskAsyncCmd(BpmnActivitySetAssigneeDTO dto) { + this.dto = dto; + } + + @Override + public String paramToJsonString() { + return JSON.toJSONString(dto); + } + + @Override + public String execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskService taskService = processEngineConfiguration.getTaskService(); + TaskEntity task = (TaskEntity) getOperateTask(taskService, dto.getTriggerId()); + //校验 + validate(processEngineConfiguration.getRuntimeService(), dto.getTriggerId(), task, dto.getAssigners()); + + validProcessInstance(commandContext, task); + + return startAsync(processEngineConfiguration, task); + } + + private String startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, TaskEntity task) { + JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService(); + + JobEntity job = jobService.createJob(); + // 这里的 executionId 可为 null + job.setExecutionId(task.getExecutionId()); + job.setProcessInstanceId(task.getProcessInstanceId()); + job.setProcessDefinitionId(task.getProcessDefinitionId()); + job.setElementId(task.getTaskDefinitionKey()); + job.setElementName(task.getName()); + job.setJobHandlerType(AsyncActivitySetAssigneeJobHandler.TYPE); + job.setTenantId(task.getTenantId()); + + // 携带自定义的数据 + job.setCustomValues(JSONUtil.toJsonStr(dto)); + + // 创建异步任务并调度 + jobService.createAsyncJob(job, false); + jobService.scheduleAsyncJob(job); + return job.getId(); + } + + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java index f108311bf..f1dd7acbc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java @@ -81,7 +81,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = getOperateTask(taskService, executionId); + TaskEntity task = (TaskEntity) getOperateTask(taskService, executionId); //校验 validate(processEngineConfiguration.getRuntimeService(), executionId, task, addedAssigners); @@ -94,7 +94,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand return true; } - private void validProcessInstance(CommandContext commandContext, Task task) { + public static void validProcessInstance(CommandContext commandContext, Task task) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java index 38e8174f8..effb4cebf 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceAsyncCmd.java @@ -3,7 +3,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; -import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceHandler; +import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceJobHandler; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -74,9 +74,9 @@ public class CustomCancelProcessInstanceAsyncCmd extends AbstractCommand i job.setExecutionId(instance.getId()); job.setProcessInstanceId(instance.getId()); job.setProcessDefinitionId(instance.getProcessDefinitionId()); - job.setElementId(AsyncCancelProcessInstanceHandler.TYPE); + job.setElementId(AsyncCancelProcessInstanceJobHandler.TYPE); job.setElementName(instance.getName()); - job.setJobHandlerType(AsyncCancelProcessInstanceHandler.TYPE); + job.setJobHandlerType(AsyncCancelProcessInstanceJobHandler.TYPE); job.setTenantId(instance.getTenantId()); // 携带自定义的数据 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContextFactory.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContextFactory.java index df53139bf..6e3cd116e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContextFactory.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContextFactory.java @@ -5,7 +5,7 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.common.engine.impl.interceptor.CommandContextFactory; /** - * TODO + * CommandContextFactory * * @author wangli * @since 2024/5/21 09:45 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceJobHandler.java similarity index 88% rename from workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceHandler.java rename to workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceJobHandler.java index 27b269614..979f305fd 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncAbortProcessInstanceJobHandler.java @@ -13,11 +13,11 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.variable.api.delegate.VariableScope; @Slf4j -public class AsyncAbortProcessInstanceHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { +public class AsyncAbortProcessInstanceJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler { public static final String TYPE = "async-abort-instance"; private final ExtAxHiTaskInstService extAxHiTaskInstService; - public AsyncAbortProcessInstanceHandler(ExtAxHiTaskInstService extAxHiTaskInstService) { + public AsyncAbortProcessInstanceJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService) { this.extAxHiTaskInstService = extAxHiTaskInstService; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivitySetAssigneeJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivitySetAssigneeJobHandler.java new file mode 100644 index 000000000..13b91524e --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivitySetAssigneeJobHandler.java @@ -0,0 +1,37 @@ +package cn.axzo.workflow.core.engine.job; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobHandler; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.variable.api.delegate.VariableScope; + +/** + * 异步处理业务节点设置审批人的处理器 + * + * @author wangli + * @since 2024-09-09 14:54 + */ +@Slf4j +public class AsyncActivitySetAssigneeJobHandler extends AbstractJobHandler implements JobHandler { + public static String TYPE = "async-activity-set-assignee"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + log.info("AsyncActivitySetAssigneeJobHandler executing..."); + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + BpmnActivitySetAssigneeDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnActivitySetAssigneeDTO.class); + processEngineConfiguration.getCommandExecutor().execute(new CustomBizSpecifyAssigneeToTaskCmd(dto.getTriggerId(), dto.getAssigners())); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java new file mode 100644 index 000000000..c59fe7897 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityTriggerJobHandler.java @@ -0,0 +1,37 @@ +package cn.axzo.workflow.core.engine.job; + +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; +import cn.axzo.workflow.core.engine.cmd.CustomActivityTriggerCmd; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobHandler; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.variable.api.delegate.VariableScope; + +/** + * 异步处理业务节点触发的处理器 + * + * @author wangli + * @since 2024-09-09 14:36 + */ +@Slf4j +public class AsyncActivityTriggerJobHandler extends AbstractJobHandler implements JobHandler { + public static final String TYPE = "async-activity-trigger"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + log.info("AsyncActivityTriggerJobHandler executing..."); + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + BpmnActivityTriggerDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnActivityTriggerDTO.class); + processEngineConfiguration.getCommandExecutor().execute(new CustomActivityTriggerCmd(dto)); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBpmnProcessActivityJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBpmnProcessActivityJobHandler.java deleted file mode 100644 index fffdbb6ba..000000000 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncBpmnProcessActivityJobHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.axzo.workflow.core.engine.job; - -import cn.axzo.workflow.core.service.BpmnProcessActivityService; -import lombok.extern.slf4j.Slf4j; -import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.job.service.JobHandler; -import org.flowable.job.service.impl.persistence.entity.JobEntity; -import org.flowable.variable.api.delegate.VariableScope; - -@Slf4j -public class AsyncBpmnProcessActivityJobHandler extends AbstractJobHandler implements JobHandler { - - public static final String TYPE = "async-bpmn-process-activity"; - - private final BpmnProcessActivityService activityService; - - public AsyncBpmnProcessActivityJobHandler(BpmnProcessActivityService activityService) { - this.activityService = activityService; - } - - @Override - public String getType() { - return TYPE; - } - - @Override - public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { - log(job); - activityService.executeAsyncJob(job); - } -} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java similarity index 89% rename from workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceHandler.java rename to workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java index 1557e3b60..6407d79ad 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCancelProcessInstanceJobHandler.java @@ -13,13 +13,13 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.variable.api.delegate.VariableScope; @Slf4j -public class AsyncCancelProcessInstanceHandler extends AbstractJobHandler implements JobHandler { +public class AsyncCancelProcessInstanceJobHandler extends AbstractJobHandler implements JobHandler { public static final String TYPE = "async-cancel-process"; private final ExtAxHiTaskInstService extAxHiTaskInstService; - public AsyncCancelProcessInstanceHandler(ExtAxHiTaskInstService extAxHiTaskInstService) { + public AsyncCancelProcessInstanceJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService) { this.extAxHiTaskInstService = extAxHiTaskInstService; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java index 24972e008..10113ed48 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.core.service; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import org.flowable.job.service.impl.persistence.entity.JobEntity; /** @@ -11,26 +12,14 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity; */ public interface BpmnProcessActivityService { - /** - * 执行异步任务 - * - * @param job 需要执行的任务 - */ - void executeAsyncJob(JobEntity job); - /** * 唤醒业务节点 * - * @param executionId 活动 ID + * @param dto */ - void trigger(String executionId); + void trigger(BpmnActivityTriggerDTO dto); + - /** - * 唤醒业务节点-异步 - * - * @param executionId 活动 ID - */ - void triggerAsync(String executionId); /** * 给指定实例的指定节点重设审批人 @@ -39,10 +28,4 @@ public interface BpmnProcessActivityService { */ void setAssignee(BpmnActivitySetAssigneeDTO dto); - /** - * 给指定实例的指定节点重设审批人 - * - * @param dto - */ - void setAssigneeAsync(BpmnActivitySetAssigneeDTO dto); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java index 9d27a8117..be0fb374b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java @@ -1,32 +1,29 @@ package cn.axzo.workflow.core.service.impl; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.engine.cmd.CustomAbortProcessInstanceCmd; +import cn.axzo.workflow.core.engine.cmd.CustomActivityTriggerAsyncCmd; +import cn.axzo.workflow.core.engine.cmd.CustomActivityTriggerCmd; +import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskAsyncCmd; import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd; -import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; -import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; -import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandExecutor; import org.flowable.engine.RuntimeService; import org.flowable.engine.runtime.Execution; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.job.service.JobService; -import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.spring.SpringProcessEngineConfiguration; -import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.util.Objects; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_TRIGGER_NOT_EXISTS; -import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_INSTANCE_IS_NOT_EXIST; @Service @@ -42,42 +39,15 @@ public class BpmnProcessActivityServiceImpl implements BpmnProcessActivityServic @Lazy private SpringProcessEngineConfiguration processEngineConfiguration; - private static final String JOB_TRIGGER_ASYNC_NAME = "asyncTrigger"; - private static final String JOB_ASSIGNEE_ASYNC_NAME = "asyncSetAssignee"; - @Override - public void executeAsyncJob(JobEntity job) { - if (job == null) { - log.warn("job is null"); - throw new NullPointerException("job is null"); + @Transactional(rollbackFor = Exception.class) + public void trigger(BpmnActivityTriggerDTO dto) { + CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); + if (Boolean.TRUE.equals(dto.getAsync())) { + commandExecutor.execute(new CustomActivityTriggerAsyncCmd(dto)); + } else { + commandExecutor.execute(new CustomActivityTriggerCmd(dto)); } - String type = job.getElementName(); - String customValues = job.getCustomValues(); - switch (type) { - case JOB_TRIGGER_ASYNC_NAME: - trigger(customValues); - break; - case JOB_ASSIGNEE_ASYNC_NAME: - BpmnActivitySetAssigneeDTO dto = JSONUtil.toBean(customValues, BpmnActivitySetAssigneeDTO.class); - setAssignee(dto); - break; - default: - throw new UnsupportedOperationException(String.format("不支持'%s'类型操作", type)); - } - } - - @Override - public void trigger(String executionId) { - Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult(); - if (Objects.isNull(execution)) { - throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, executionId); - } - runtimeService.trigger(executionId); - } - - @Override - public void triggerAsync(String executionId) { - validateAndStartAsyncJob(executionId, executionId, JOB_TRIGGER_ASYNC_NAME); } @Override @@ -91,43 +61,12 @@ public class BpmnProcessActivityServiceImpl implements BpmnProcessActivityServic commandExecutor.execute(new CustomAbortProcessInstanceCmd(execution.getProcessInstanceId(), null, "业务未指定审批人", extAxHiTaskInstService)); return; } - commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskCmd(dto.getTriggerId(), dto.getAssigners())); - } - @Override - public void setAssigneeAsync(BpmnActivitySetAssigneeDTO dto) { - //查询任务 - Task task = CustomBizSpecifyAssigneeToTaskCmd.getOperateTask(processEngineConfiguration.getTaskService(), dto.getTriggerId()); - //先校验 - CustomBizSpecifyAssigneeToTaskCmd.validate(processEngineConfiguration.getRuntimeService(), dto.getTriggerId(), task, dto.getAssigners()); - validateAndStartAsyncJob(dto.getTriggerId(), dto, JOB_ASSIGNEE_ASYNC_NAME); - } - - private void validateAndStartAsyncJob(String executionId, Object customValue, String actionName) { - processEngineConfiguration.getCommandExecutor().execute((Command) commandContext -> { - Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult(); - if (Objects.isNull(execution)) { - throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, executionId); - } - ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId()).singleResult(); - if (Objects.isNull(processInstance)) { - throw new WorkflowEngineException(PROCESS_INSTANCE_IS_NOT_EXIST, execution.getId()); - } - JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService(); - JobEntity job = jobService.createJob(); - // 这里的 executionId 可为 null - job.setExecutionId(executionId); - job.setProcessInstanceId(execution.getProcessInstanceId()); - job.setProcessDefinitionId(processInstance.getProcessDefinitionId()); - job.setElementId(AsyncBpmnProcessActivityJobHandler.TYPE); - job.setElementName(actionName); - job.setJobHandlerType(AsyncBpmnProcessActivityJobHandler.TYPE); - job.setTenantId(execution.getTenantId()); - job.setCustomValues(JSONUtil.toJsonStr(customValue)); - jobService.createAsyncJob(job, false); - jobService.scheduleAsyncJob(job); - return null; - }); + if(Boolean.TRUE.equals(dto.getAsync())) { + commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskAsyncCmd(dto)); + } else { + commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskCmd(dto.getTriggerId(), dto.getAssigners())); + } } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index 6d83c6c38..21df13adc 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -2,12 +2,14 @@ package cn.axzo.workflow.server.controller.web.bpmn; import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import cn.azxo.framework.common.model.CommonResponse; +import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; @@ -25,6 +27,7 @@ import java.util.List; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_HAS_REPEAT; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId; +import static cn.azxo.framework.common.model.CommonResponse.success; /** * 流程活动相关控制器 @@ -43,38 +46,34 @@ public class BpmnProcessActivityController implements ProcessActivityApi { private BpmnProcessActivityService bpmnProcessActivityService; /** - * 业务节点唤醒 - * - * @param triggerId 触发 ID,数据来源于事件 - * @return - */ - @Operation(summary = "业务节点唤醒") - @GetMapping("/v2/trigger") - @RepeatSubmit - public CommonResponse trigger(@RequestParam @NotBlank(message = "触发 ID 不能为空") String triggerId, - @RequestParam(required = false, defaultValue = "false") Boolean async) { - log.info("业务节点唤醒 trigger ===>>>参数:{}, {}", triggerId, async); - if (async != null && async) { - bpmnProcessActivityService.triggerAsync(triggerId); - } else { - bpmnProcessActivityService.trigger(triggerId); - } - return CommonResponse.success(true); - } - - /** - * old/trigger 地址是 1.3.3 版本以前的接口,在接入方未完全升级前,都需要保留 + * 业务节点唤醒 旧版本使用的接口 * * @param triggerId * @return */ @Operation(summary = "业务节点唤醒") - @GetMapping({"/trigger", "/old/trigger"}) + @GetMapping("/trigger") @Override @RepeatSubmit public CommonResponse trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId) { log.info("业务节点唤醒 trigger2 ===>>>参数:{}", triggerId); - return trigger(triggerId, true); + return trigger(new BpmnActivityTriggerDTO(triggerId, true)); + } + + /** + * 业务节点唤醒 + * + * @param dto + * @return + */ + @Operation(summary = "业务节点唤醒") + @PostMapping("/trigger") + @Override + @RepeatSubmit + public CommonResponse trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto) { + log.info("业务节点唤醒 trigger ===>>>参数:{}", JSON.toJSONString(dto)); + bpmnProcessActivityService.trigger(dto); + return success(true); } /** @@ -90,7 +89,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { @Override @RepeatSubmit public CommonResponse setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto) { - log.info("业务节点设置审批人 setAssignee ===>>>参数:{}", dto); + log.info("业务节点设置审批人 setAssignee ===>>>参数:{}", JSON.toJSONString(dto)); if (!dto.getServerSideDeduplication()) { List personIds = new ArrayList<>(); for (BpmnTaskDelegateAssigner assigner : dto.getAssigners()) { @@ -102,11 +101,7 @@ public class BpmnProcessActivityController implements ProcessActivityApi { } else { dto.setAssigners(removeDuplicateByPersonId(dto.getAssigners())); } - if (dto.getAsync() != null && dto.getAsync()) { - bpmnProcessActivityService.setAssigneeAsync(dto); - } else { - bpmnProcessActivityService.setAssignee(dto); - } - return CommonResponse.success(true); + bpmnProcessActivityService.setAssignee(dto); + return success(true); } } From 27a640048ac20dccffa165aad8b4430b6ed609a4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 16:13:28 +0800 Subject: [PATCH 034/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=A2=9E=E5=8A=A0=E5=AE=8C=E6=88=90=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomActivityTriggerCmd.java | 13 +++++++++---- .../impl/BpmnProcessInstanceServiceImpl.java | 14 +++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java index 687f17fef..918e0cfb7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomActivityTriggerCmd.java @@ -7,14 +7,16 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.engine.runtime.Execution; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_TRIGGER_NOT_EXISTS; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; /** * 自定义(同步)流转业务姐弟那的命令器实现 @@ -40,11 +42,14 @@ public class CustomActivityTriggerCmd extends AbstractCommand implements S public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); - RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - Execution execution = runtimeService.createExecutionQuery().executionId(dto.getTriggerId()).singleResult(); - if (Objects.isNull(execution)) { + + TaskEntity task = (TaskEntity) processEngineConfiguration.getTaskService() + .createTaskQuery().executionId(dto.getTriggerId()).singleResult(); + if (Objects.isNull(task)) { throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId()); } + addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已处理"); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); runtimeService.trigger(dto.getTriggerId()); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 2b1603062..c4b05732b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1255,10 +1255,22 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); if (processingTask.isPresent()) { + // 多实例的情况,需要合并节点 processingTask.ifPresent(i -> { - List assigners = new ArrayList<>(); + List assigners = new ArrayList<>(ListUtils.emptyIfNull(i.getForecastAssignees())); assigners.add(i.getAssigneeSnapshot()); assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))); + switch (i.getNodeMode()) { + case AND: + i.setOperationDesc(assigners.size() + "人会签,需要全部同意"); + break; + case OR: + i.setOperationDesc(assigners.size() + "人或签,仅一人同意即可"); + break; + default: + // 不修改操作描述 + break; + } i.setAssigneeSnapshot(null); i.setForecastAssignees(assigners); }); From f221b53c3d61611f558b2909514172b7828dea16 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 18:10:07 +0800 Subject: [PATCH 035/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=8D=95=E6=9D=A1=E5=88=86=E6=94=AF=E8=B7=AF?= =?UTF-8?q?=E7=BA=BF=E5=90=84=E7=A7=8D=E8=8A=82=E7=82=B9=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=94=9F=E6=88=90=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...askDelegateExpressionActivityBehavior.java | 2 + .../engine/cmd/helper/CustomTaskHelper.java | 112 +++++++++--------- .../entity/type/TaskEntityEventHandle.java | 4 +- .../impl/BpmnProcessInstanceServiceImpl.java | 20 +++- .../web/BasicPopulateAvatarController.java | 62 ++++++++++ .../bpmn/BpmnProcessActivityController.java | 17 ++- .../bpmn/BpmnProcessInstanceController.java | 12 +- .../web/bpmn/BpmnProcessTaskController.java | 31 +---- 8 files changed, 161 insertions(+), 99 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index 108939712..2b9c306df 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -62,6 +62,7 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service task.setPropagatedStageInstanceId(execution.getPropagatedStageInstanceId()); task.setName(serviceTask.getName()); TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false); + log.error("ServiceTask execute taskId: {}", task.getId()); // 添加 taskInst 扩展表数据 FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); @@ -81,6 +82,7 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service org.flowable.engine.TaskService taskService = processEngineConfiguration.getTaskService(); TaskEntity serviceTask = (TaskEntity) taskService.createTaskQuery().taskId(task.getId()) .taskDefinitionKey(execution.getCurrentActivityId()).singleResult(); + log.error("ServiceTask leave taskId: {}", serviceTask.getId()); if (Objects.nonNull(serviceTask)) { // 用于新版日志 serviceTask.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + serviceTask.getId(), APPROVED.getStatus()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index c506a981d..8f3503ac1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -80,13 +80,13 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); Map executionVariables = new HashMap<>(); executionVariables.put("assigneeName", newTaskAssignee.buildAssigneeId()); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); Execution subExecution = runtimeService.addMultiInstanceExecution(originTask.getTaskDefinitionKey(), - originTask.getProcessInstanceId(), executionVariables); + originTask.getProcessInstanceId(), executionVariables); setParentTaskId(originTask, subExecution); } @@ -96,19 +96,19 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); runtimeService.deleteMultiInstanceExecution(originTask.getExecutionId(), false); } private static void setParentTaskId(TaskEntity originTask, Execution subExecution) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() - .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) - .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); + .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) + .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream() - .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) - .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); + .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) + .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); } /** @@ -121,7 +121,7 @@ public class CustomTaskHelper { public static void validTask(HistoricTaskInstance historicTaskInstance, TaskEntity taskEntity, BpmnTaskDelegateAssigner originTaskAssigner, List nodeTypes) { if (Objects.nonNull(historicTaskInstance) && - (Objects.nonNull(historicTaskInstance.getEndTime()) || Objects.isNull(taskEntity))) { + (Objects.nonNull(historicTaskInstance.getEndTime()) || Objects.isNull(taskEntity))) { throw new WorkflowEngineException(TASK_HAS_BEEN_COMPLETE); } @@ -171,14 +171,14 @@ public class CustomTaskHelper { TaskEntity taskEntity, List targetAssigneeList) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); // 这个节点下所有审批人快照 String activityListSnapshot = - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); List taskAssignerListSnapshot = - runtimeService.getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class); + runtimeService.getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class); AtomicInteger existsCount = new AtomicInteger(); taskAssignerListSnapshot.forEach(i -> { targetAssigneeList.forEach(j -> { @@ -228,19 +228,19 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); Authentication.setAuthenticatedUserId(assigner.buildAssigneeId()); attachmentList.forEach(dto -> { Attachment attachment = taskService.createAttachment(dto.getType().getType(), taskId, processInstanceId, - dto.getName(), dto.getDescription(), dto.getUrl()); + dto.getName(), dto.getDescription(), dto.getUrl()); taskService.saveAttachment(attachment); }); Authentication.setAuthenticatedUserId(null); } public static void addComment(CommandContext commandContext, String taskId, String processInstanceId, - String type, String message) { + String type, String message) { TaskEntity task = new TaskEntityImpl(); task.setId(taskId); task.setProcessInstanceId(processInstanceId); @@ -256,7 +256,7 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); String userId = Authentication.getAuthenticatedUserId(); CommentEntity comment = processEngineConfiguration.getCommentEntityManager().create(); @@ -276,13 +276,12 @@ public class CustomTaskHelper { comment.setFullMessage(message); processEngineConfiguration.getCommentEntityManager().insert(comment); - - task.setTransientVariable(type, message); + task.setTransientVariableLocal(type, message); } public static Attachment addAttachment(CommandContext commandContext, Task task, AttachmentDTO attachmentDto) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); AttachmentEntity attachment = processEngineConfiguration.getAttachmentEntityManager().create(); attachment.setName(attachmentDto.getName()); attachment.setProcessInstanceId(task.getProcessInstanceId()); @@ -298,11 +297,11 @@ public class CustomTaskHelper { ExecutionEntity processInstance = null; if (task.getProcessInstanceId() != null) { processInstance = - processEngineConfiguration.getExecutionEntityManager().findById(task.getProcessInstanceId()); + processEngineConfiguration.getExecutionEntityManager().findById(task.getProcessInstanceId()); } processEngineConfiguration.getHistoryManager().createAttachmentComment((TaskEntity) task, processInstance, - attachmentDto.getName(), true); + attachmentDto.getName(), true); return attachment; } @@ -321,15 +320,15 @@ public class CustomTaskHelper { * @return */ public static Task createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService - , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, + , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, BpmnTaskDelegateAssigner assigner, String extTaskInstStatus, AddComment addComment) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); HistoricProcessInstance processInstance = - historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); IdGenerator idGenerator = processEngineConfiguration.getIdGenerator(); @@ -346,12 +345,12 @@ public class CustomTaskHelper { if (Objects.nonNull(assigner)) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() - .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() - .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); + .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() + .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream() - .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() - .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); + .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() + .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); } // 添加审批意见 @@ -360,7 +359,7 @@ public class CustomTaskHelper { addComment(commandContext, task, addComment); CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, task.getProcessInstanceId(), task.getId(), - task.getTaskDefinitionKey(), assigner, extTaskInstStatus); + task.getTaskDefinitionKey(), assigner, extTaskInstStatus); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), extTaskInstStatus); // 保存任务 @@ -389,7 +388,6 @@ public class CustomTaskHelper { if (StringUtils.hasLength(comment)) { Authentication.setAuthenticatedUserId(userId); addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); - task.setTransientVariable(COMMENT_TYPE_ADVICE + task.getId(), comment); Authentication.setAuthenticatedUserId(null); } } @@ -417,10 +415,10 @@ public class CustomTaskHelper { return delegateAssigners; } return new ArrayList<>(delegateAssigners.stream() - .filter(i -> StringUtils.hasText(i.getPersonId())) - .filter(i -> !Objects.equals(i.getPersonId(), "null")) - .collect(Collectors.toMap(BpmnTaskDelegateAssigner::getPersonId, Function.identity(), (s, t) -> s)) - .values()); + .filter(i -> StringUtils.hasText(i.getPersonId())) + .filter(i -> !Objects.equals(i.getPersonId(), "null")) + .collect(Collectors.toMap(BpmnTaskDelegateAssigner::getPersonId, Function.identity(), (s, t) -> s)) + .values()); } /** @@ -447,27 +445,27 @@ public class CustomTaskHelper { List result = new ArrayList<>(); List taskInstances = historyService.createHistoricTaskInstanceQuery() - .processInstanceId(processInstanceId) - .orderByHistoricTaskInstanceStartTime() - .desc().list(); + .processInstanceId(processInstanceId) + .orderByHistoricTaskInstanceStartTime() + .desc().list(); List vos = historicTaskInstanceConverter.toVosSkipSystemOperation(taskInstances, - serviceVersion); + serviceVersion); Map variableInstanceMap = - // 不能使用框架提供的历史变量 API 查询,有 BUG - historyService.createNativeHistoricVariableInstanceQuery() - .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") - .parameter("processInstanceId", processInstanceId) - .list().stream() - .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, - Function.identity(), (s, t) -> s)); + // 不能使用框架提供的历史变量 API 查询,有 BUG + historyService.createNativeHistoricVariableInstanceQuery() + .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") + .parameter("processInstanceId", processInstanceId) + .list().stream() + .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, + Function.identity(), (s, t) -> s)); vos.forEach(vo -> { HistoricVariableInstance assginerSnapshot = - variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), - null); + variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), + null); if (Objects.isNull(assginerSnapshot)) { assginerSnapshot = - variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); + variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); } if (Objects.nonNull(assginerSnapshot)) { BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(assginerSnapshot.getValue()); @@ -483,27 +481,27 @@ public class CustomTaskHelper { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); Process process = ProcessDefinitionUtil.getProcess(processDefinitionId); List taskDefinitionKeys = process.getFlowElements().stream() - .filter(i -> Objects.equals(BpmnMetaParserHelper.getNodeType(i).orElse(null), BpmnFlowNodeType.NODE_CARBON_COPY)) - .map(FlowElement::getId) - .collect(Collectors.toList()); + .filter(i -> Objects.equals(BpmnMetaParserHelper.getNodeType(i).orElse(null), BpmnFlowNodeType.NODE_CARBON_COPY)) + .map(FlowElement::getId) + .collect(Collectors.toList()); if (CollectionUtils.isEmpty(taskDefinitionKeys)) { return Collections.emptyList(); } List variableInstances = processEngineConfiguration.getHistoryService().createHistoricVariableInstanceQuery() - .variableNameLike(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT) - .processInstanceId(processInstanceId) - .list(); + .variableNameLike(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT) + .processInstanceId(processInstanceId) + .list(); if (CollectionUtils.isEmpty(variableInstances)) { return Collections.emptyList(); } List result = new ArrayList<>(); taskDefinitionKeys.forEach(j -> { variableInstances.stream() - .filter(i -> Objects.equals(i.getVariableName(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + j)) - .findFirst().ifPresent(i -> { - result.addAll((List) i.getValue()); - }); + .filter(i -> Objects.equals(i.getVariableName(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + j)) + .findFirst().ifPresent(i -> { + result.addAll((List) i.getValue()); + }); }); return result; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 65597e5eb..7cf46102f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -108,12 +108,12 @@ public class TaskEntityEventHandle implements EntityEventHandle { update.setStatus(APPROVED.getStatus()); } else { - Object advice = taskEntity.getTransientVariable(COMMENT_TYPE_ADVICE); + Object advice = taskEntity.getTransientVariableLocal(COMMENT_TYPE_ADVICE); if (Objects.nonNull(advice) && StringUtils.hasText(advice.toString())) { log.info("COMMENT_TYPE_ADVICE: {}", advice); update.setAdvice(advice.toString()); } - Object operationDesc = taskEntity.getTransientVariable(COMMENT_TYPE_OPERATION_DESC); + Object operationDesc = taskEntity.getTransientVariableLocal(COMMENT_TYPE_OPERATION_DESC); if (Objects.nonNull(operationDesc) && StringUtils.hasText(operationDesc.toString())) { log.info("COMMENT_TYPE_OPERATION_DESC: {}", operationDesc); update.setOperationDesc(Objects.nonNull(assignee) ? assignee.getAssignerName() + operationDesc : operationDesc.toString()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index c4b05732b..6dae6bbb1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1061,7 +1061,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)))) .tenantId(historicProcessInstance.getTenantId()) .agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false)) - .taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto.getEncrypt())) + .taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto)) .defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf())) .supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation()) .userAgreeSignature(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getUserAgreeSignature()) @@ -1199,17 +1199,17 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic private List genericTaskLogVos(String processInstanceId, List logs, List forecasting, - Boolean encrypt) { + BpmnProcessInstanceLogQueryDTO dto) { List tasks = new ArrayList<>(); Map> attachmentByTaskMap = taskService.getProcessInstanceAttachments(processInstanceId).stream() .collect(Collectors.groupingBy(Attachment::getTaskId)); // 已完成的和进行中的 - getHistoricTasks(logs, tasks, attachmentByTaskMap); + getHistoricTasks(logs, tasks, attachmentByTaskMap, dto.getVisitor()); // 未来节点 getFutureTasks(forecasting, tasks); // 处理是否加密 - handleEncrypt(encrypt, tasks); + handleEncrypt(dto.getEncrypt(), tasks); return tasks; } @@ -1249,7 +1249,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic }); } - private void getHistoricTasks(List logs, List tasks, Map> attachmentByTaskMap) { + private void getHistoricTasks(List logs, + List tasks, + Map> attachmentByTaskMap, + BpmnTaskDelegateAssigner visitor) { ListUtils.emptyIfNull(logs).forEach(e -> { Optional processingTask = tasks.stream().filter(i -> Objects.equals(PROCESSING, i.getResult())) .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); @@ -1258,7 +1261,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 多实例的情况,需要合并节点 processingTask.ifPresent(i -> { List assigners = new ArrayList<>(ListUtils.emptyIfNull(i.getForecastAssignees())); - assigners.add(i.getAssigneeSnapshot()); + if(CollectionUtils.isEmpty(assigners)) { + assigners.add(i.getAssigneeSnapshot()); + } assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))); switch (i.getNodeMode()) { case AND: @@ -1273,6 +1278,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } i.setAssigneeSnapshot(null); i.setForecastAssignees(assigners); + // 根据当前登录人重设聚合后的节点 taskId + assigners.stream().filter(user-> Objects.equals(user.getPersonId(), visitor.getPersonId())).findFirst() + .ifPresent(user-> i.setTaskId(e.getTaskId())); }); } else { tasks.add(BpmnTaskInstanceLogVO.builder() diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java new file mode 100644 index 000000000..fe22b2991 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java @@ -0,0 +1,62 @@ +package cn.axzo.workflow.server.controller.web; + +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.PersonProfileQueryReq; +import cn.axzo.karma.client.model.response.PersonProfileResp; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.server.common.util.RpcExternalUtil; +import com.google.common.collect.Lists; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 公共的获取 BpmnTask + * + * @author wangli + * @since 2024-09-09 16:51 + */ +public abstract class BasicPopulateAvatarController { + + @Resource + protected FlowSupportApi flowSupportApi; + + /** + * 为一个人填充头像 + * + * @param assigner + */ + protected final void populateUsersAvatar(BpmnTaskDelegateAssigner assigner) { + if (Objects.isNull(assigner)) { + return; + } + populateUsersAvatar(Lists.newArrayList(assigner)); + } + + /** + * 为一个集合的人填充头像 + * + * @param assigners + */ + protected final void populateUsersAvatar(List assigners) { + List personIds = assigners.stream().filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) + .map(BpmnTaskDelegateAssigner::getPersonId) + .map(Long::parseLong) + .distinct().collect(Collectors.toList()); + Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), + "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds).stream() + .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); + assigners.forEach(e -> { + long personId = Long.parseLong(Optional.ofNullable(e.getPersonId()).orElse("-1")); + if (personMap.containsKey(personId)) { + e.setAvatar(personMap.getOrDefault(personId, "")); + } + }); + } + +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index 21df13adc..87b927577 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -1,5 +1,8 @@ package cn.axzo.workflow.server.controller.web.bpmn; +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.PersonProfileQueryReq; +import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; @@ -8,10 +11,13 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; +import cn.axzo.workflow.server.common.util.RpcExternalUtil; +import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -24,6 +30,9 @@ import javax.annotation.Resource; import javax.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_HAS_REPEAT; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId; @@ -40,10 +49,12 @@ import static cn.azxo.framework.common.model.CommonResponse.success; @RestController @ErrorReporter @Validated -public class BpmnProcessActivityController implements ProcessActivityApi { +public class BpmnProcessActivityController extends BasicPopulateAvatarController implements ProcessActivityApi { @Resource private BpmnProcessActivityService bpmnProcessActivityService; + @Resource + private FlowSupportApi flowSupportApi; /** * 业务节点唤醒 旧版本使用的接口 @@ -101,6 +112,10 @@ public class BpmnProcessActivityController implements ProcessActivityApi { } else { dto.setAssigners(removeDuplicateByPersonId(dto.getAssigners())); } + + //填充头像 + populateUsersAvatar(dto.getAssigners()); + bpmnProcessActivityService.setAssignee(dto); return success(true); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index 6f50246cb..2b024a66e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -31,6 +31,7 @@ import cn.axzo.workflow.core.service.BpmnProcessInstanceService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import cn.axzo.workflow.server.common.util.RpcExternalUtil; +import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController; import cn.azxo.framework.common.model.CommonResponse; import cn.hutool.json.JSONUtil; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -70,7 +71,7 @@ import static cn.azxo.framework.common.model.CommonResponse.success; @RestController @ErrorReporter @Validated -public class BpmnProcessInstanceController implements ProcessInstanceApi { +public class BpmnProcessInstanceController extends BasicPopulateAvatarController implements ProcessInstanceApi { @Resource private BpmnProcessInstanceService bpmnProcessInstanceService; @@ -113,13 +114,8 @@ public class BpmnProcessInstanceController implements ProcessInstanceApi { @RepeatSubmit public CommonResponse createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto) { log.info("发起审核createProcessInstance===>>>参数:{}", JSONUtil.toJsonStr(dto)); - long personId = Long.parseLong(Optional.ofNullable(dto.getInitiator().getPersonId()).orElse("-1")); - Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), - "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() - .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); - if (personMap.containsKey(personId)) { - dto.getInitiator().setAvatar(personMap.getOrDefault(personId, "")); - } + // 填充头像 + populateUsersAvatar(dto.getInitiator()); return success(bpmnProcessInstanceService.createProcessInstance(dto)); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 257aaeb53..94e43fa20 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -29,6 +29,7 @@ import cn.axzo.workflow.core.service.BpmnProcessTaskService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; import cn.axzo.workflow.server.common.util.RpcExternalUtil; +import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; @@ -64,7 +65,7 @@ import static cn.azxo.framework.common.model.CommonResponse.success; @RestController @ErrorReporter @Validated -public class BpmnProcessTaskController implements ProcessTaskApi { +public class BpmnProcessTaskController extends BasicPopulateAvatarController implements ProcessTaskApi { @Resource private BpmnProcessTaskService bpmnProcessTaskService; @@ -189,15 +190,8 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @RepeatSubmit public CommonResponse transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto) { log.info("转交任务 transferTask===>>>参数:{}", JSON.toJSONString(dto)); - - long personId = Long.parseLong(Optional.ofNullable(dto.getTargetAssigner().getPersonId()).orElse("-1")); - Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personId(personId).build()), - "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personId).stream() - .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); - if (personMap.containsKey(personId)) { - dto.getTargetAssigner().setAvatar(personMap.getOrDefault(personId, "")); - } - + // 填充头像 + populateUsersAvatar(dto.getTargetAssigner()); bpmnProcessTaskService.transferTask(dto); return success(true); } @@ -234,21 +228,8 @@ public class BpmnProcessTaskController implements ProcessTaskApi { @RepeatSubmit public CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) { log.info("加签任务 countersignTask===>>>参数:{}", JSON.toJSONString(countersignDTO)); - - List personIds = countersignDTO.getTargetAssignerList().stream().filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) - .map(BpmnTaskDelegateAssigner::getPersonId) - .map(Long::parseLong) - .distinct().collect(Collectors.toList()); - Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), - "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds).stream() - .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); - countersignDTO.getTargetAssignerList().forEach(e -> { - long personId = Long.parseLong(Optional.ofNullable(e.getPersonId()).orElse("-1")); - if (personMap.containsKey(personId)) { - e.setAvatar(personMap.getOrDefault(personId, "")); - } - }); - + // 填充头像 + populateUsersAvatar(countersignDTO.getTargetAssignerList()); bpmnProcessTaskService.countersignTask(countersignDTO); return success(true); } From d6817d406215208f7f6f3dc4bf23949f0f2d1525 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 18:22:22 +0800 Subject: [PATCH 036/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a66b8e2f1..289391350 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,8 @@ target/ *.iws *.iml *.ipr +WorkflowCoreService.java +WorkflowManageServer.java ### NetBeans ### /nbproject/private/ From 477acbe98f8d2446556c86d26481ed0850c53356 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 18:22:45 +0800 Subject: [PATCH 037/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 289391350..8b86a6454 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ target/ *.iml *.ipr WorkflowCoreService.java -WorkflowManageServer.java +WorkflowManageService.java ### NetBeans ### /nbproject/private/ From a3a6ec51bd98560ca9c753ff435df6931a4615ce Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 18:26:27 +0800 Subject: [PATCH 038/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=A9=BA=E6=96=87=E4=BB=B6=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 327 +------- .../starter/api/WorkflowManageService.java | 717 +----------------- 2 files changed, 8 insertions(+), 1036 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 2b5bded14..92b09c7e4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,329 +1,10 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.axzo.workflow.common.util.ThreadUtil; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.azxo.framework.common.model.CommonResponse; -import io.swagger.v3.oas.annotations.Operation; -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 javax.validation.constraints.NotBlank; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PutMapping; -import javax.annotation.Nullable; -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.Map; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; -import org.springframework.cloud.openfeign.FeignClient; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import javax.validation.constraints.NotEmpty; - /** - * Workflow Engine Starter Core Service - *

- * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + * just for compiler + * + * @author wangli + * @since 2024-09-09 18:25 */ -@FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { - - /** - * 业务节点唤醒 - *

- * 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行 - */ - @GetMapping("/api/process/activity/trigger") - Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); - - /** - * 业务节点设置审批人, 不支持重复设置 - *

- * 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人 - *

- * 注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。 - * - * @param dto - * @return - */ - @PostMapping("/api/process/activity/assignee/set") - @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") - Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); - - /** - * 创建审批流程 - * - *

-     *   MQ 触发规则:
-     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
-     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
-     * 
- * - * @param dto {@link BpmnProcessInstanceCreateDTO} - */ - @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") - @PostMapping("/api/process/instance/create") - @InvokeMode(SYNC) - String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); - - /** - * 发起人主动撤回审核 - * - *
-     *   MQ 触发规则:
-     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
-     *     2. 当前流程实例会触发 process-instance-cancelled 事件
-     * 
- * - * @param dto {@link BpmnProcessInstanceCancelDTO} - * @return - */ - @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") - @DeleteMapping("/api/process/instance/cancel") - Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); - - /** - * 中止流程实例 - * - * @param dto - * @return - */ - @Operation(summary = "中止流程实例") - @DeleteMapping("/api/process/instance/abort") - Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); - - /** - * 批量中止流程实例 - * - * @param dtos - * @return - */ - @Operation(summary = "批量中止流程实例") - @DeleteMapping("/api/process/instance/batch/abort") - BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); - - /** - * 抄送流程实例(未实现) - * - * @param dto - * @return - */ - @Operation(summary = "抄送流程实例") - @PostMapping("/api/process/instance/carbon-copy") - @Deprecated - Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); - - /** - * 获得流程实例 - * - * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 - * @return 流程实例, 租户Id不必传 - */ - @Operation(summary = "获得流程实例") - @GetMapping("/api/process/instance/get") - @InvokeMode(SYNC) - BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); - - /** - * 获取指定流程实例的流程变量 - * - * @param processInstanceId - * @param tenantId - * @return - */ - @Operation(summary = "获取指定流程实例的流程变量") - @GetMapping("/api/process/instance/cooperation-org") - @InvokeMode(SYNC) - Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 获取指定流程的日志 - * - * @param dto - * @return - */ - @Operation(summary = "获取指定流程的日志") - @PostMapping("/api/process/instance/logs") - @InvokeMode(SYNC) - BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); - - /** - * 同意 - * - *
-     * MQ 触发规则:
-     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
-     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
-     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
-     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
-     * 
- */ - @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") - @PostMapping("/api/process/task/approve") - Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - /** - * 批量同意 - * - * @param dtos - * @return - */ - @Operation(summary = "批量同意") - @PostMapping("/api/process/task/batch/approve") - BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); - - /** - * 获取当前节点可退回节点选项列表 - * @param taskId 当前任务id - * @return 可以退回节点列表 - */ - @Operation(summary = "获取当前节点可退回节点选项列表") - @GetMapping("/api/process/task/back/optional/nodes") - List getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); - - /** - * 回退到指定节点 - * @param dto - * @return - */ - @Operation(summary = "回退") - @PostMapping("/api/process/task/back") - Boolean backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); - - /** - * 驳回 - * - *
-     * MQ 触发规则:
-     *   1. 当前审批任务会触发 process-task-deleted 事件
-     *   2. 当前流程实例会触发 process-instance-rejected 事件
-     * 
- */ - @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") - @PostMapping("/api/process/task/reject") - Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); - - /** - * 批量驳回 - * - * @param dtos 批量请求参数 - * @return - */ - @PostMapping("/api/process/task/batch/reject") - BatchOperationResultVO batchRejectTask(@Validated @RequestBody List dtos); - - /** - * 转交 - * - * @param dto - * @return - */ - @Operation(summary = "直接修改审批任务的审批人") - @PostMapping("/api/process/task/transfer") - Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); - - /** - * 批量转交 - * - * @param dtos - * @return - */ - @Operation(summary = "批量修改审批任务的审批人") - @PostMapping("/api/process/task/batch/transfer") - BatchOperationResultVO batchTransferTask(@Validated @RequestBody List dtos); - - /** - * 评论 - * - * @param dto 评论请求参数 - * @return - */ - @Operation(summary = "审批流程评论") - @PostMapping("/api/process/task/comment") - Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); - - /** - * 加签 - * - * @param dto 加签请求参数 - * @return - */ - @Operation(summary = "审批流程加签") - @PostMapping("/api/process/task/countersign") - Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); - - /** - * 暂停流程任务,并创建机器人节点,等待业务推动 - * - * @param dto - * @return 返回机器人节点任务 ID - */ - @Operation(summary = "创建机器人节点, 暂停流程任务") - @PostMapping("/api/process/task/robot/create") - String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); - - /** - * 完成机器人节点 - * - * @param dto - * @return - */ - @Operation(summary = "完成机器人节点, 继续流程任务") - @PostMapping("/api/process/task/robot/complete") - Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); - - /** - * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 - *
-     *   workflowCoreService.async().createProcessInstance();
-     * 
- */ - default WorkflowCoreService sync() { - ThreadUtil.set(SYNC); - return this; - } - - default WorkflowCoreService async() { - ThreadUtil.set(ASYNC); - return this; - } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index d3b3d564a..2d5ba5e8d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,719 +1,10 @@ package cn.axzo.workflow.starter.api; -import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; -import cn.axzo.workflow.common.util.ThreadUtil; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; -import cn.axzo.workflow.common.annotation.InvokeMode; -import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; -import cn.azxo.framework.common.model.CommonResponse; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import java.util.List; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; -import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; -import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; -import com.fasterxml.jackson.databind.node.ObjectNode; -import javax.annotation.Nullable; -import java.util.Map; -import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; -import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; -import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; -import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; -import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; -import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; -import cn.axzo.workflow.common.model.response.category.CategoryItemVO; -import org.springframework.web.bind.annotation.PathVariable; -import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; -import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; -import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; -import javax.validation.constraints.NotEmpty; -import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; -import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; -import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; - /** - * Workflow Engine Starter Management Service - *

- * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + * just for compiler + * + * @author wangli + * @since 2024-09-09 18:26 */ -@FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { - - /** - * 获取流程操作按钮列表 - * - * @return 流程操作按钮列表 - */ - @GetMapping("/api/process/config/button/list") - @InvokeMode(SYNC) - List getDefaultButtons(); - - /** - * 流程模型列表 - * - * @param dto - * @return - */ - @Operation(summary = "流程模型列表") - @GetMapping("/api/process/model/page") - @InvokeMode(SYNC) - BpmPageResult page(@Validated @RequestBody BpmnModelSearchDTO dto); - - /** - * 创建流程, - * return modelId的主键 - */ - @Operation(summary = "创建流程模型") - @PostMapping("/api/process/model/create") - @InvokeMode(SYNC) - String create(@Validated @RequestBody BpmnModelCreateDTO dto); - - /** - * 通过模型 ID 获取模型 - */ - @Operation(summary = "通过模型ID查询指定流程模型") - @GetMapping("/api/process/model/get") - @InvokeMode(SYNC) - BpmnModelDetailVO getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false) String tenantId); - - /** - * 通过模型 KEY 获取模型 - */ - @Operation(summary = "通过模型KEY查询指定流程模型") - @GetMapping("/api/process/model/getByKey") - @InvokeMode(SYNC) - BpmnModelDetailVO getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId); - - /** - * 校验是否能更新模型即其关联的流程定义内容 - *

- * 偏向业务的接口,flowable 引擎是站在流程定义维度进行激活和挂起 - * - * @return true 能更新,表明该模型关联的所有定义版本都是挂起状态 - */ - @Operation(summary = "获取指定模型的扩展属性") - @GetMapping("/api/process/model/ext") - @InvokeMode(SYNC) - BpmnModelExtVO getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId); - - /** - * 修改流程信息 - */ - @Operation(summary = "更新流程模型") - @PutMapping("/api/process/model/update") - @InvokeMode(SYNC) - String update(@RequestBody BpmnModelUpdateDTO dto); - - /** - * 通过模型 ID 部署模型 - * - * @return 部署完成的流程定义Id - */ - @Operation(summary = "通过模型 ID 部署流程模型") - @PostMapping("/api/process/model/deploy") - @InvokeMode(SYNC) - String deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String modelTenantId, @RequestParam(required = false) String operator); - - /** - * 通过模型 KEY 部署模型 - * - * @return 部署完成的流程定义Id - */ - @Operation(summary = "通过模型 KEY 部署流程模型") - @PostMapping("/api/process/model/deployByKey") - @InvokeMode(SYNC) - String deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId, @RequestParam(required = false) String operator); - - /** - * 通过模型 ID 取消部署流程模型 - * - * @param processModelId - * @param tenantId - * @param operator - * @return - */ - @Operation(summary = "通过模型 ID 取消部署流程模型") - @PostMapping("/api/process/model/undeploy") - @InvokeMode(SYNC) - Void unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId, @RequestParam(required = false) String operator); - - /** - * 通过模型 ID 删除模型 - */ - @Operation(summary = "删除指定模型 ID 的流程模型") - @DeleteMapping("/api/process/model/delete") - @InvokeMode(SYNC) - Void deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId); - - /** - * 通过模型 KEY 删除模型 - * - * @param processModelKey - * @param tenantId - * @return - */ - @Operation(summary = "删除指定模型 KEY 的流程模型") - @DeleteMapping("/api/process/model/deleteByKey") - @InvokeMode(SYNC) - Void deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey, @RequestParam(required = false, defaultValue = "") String tenantId); - - /** - * 通过模型 ID 修改模型状态 - * - * @param modelId - * @param status - * @param operator - * @return - */ - @Operation(summary = "修改模型状态") - @PostMapping("/api/process/model/changeStatus") - @InvokeMode(SYNC) - Void changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId, @NotNull(message = "状态不能为空") @RequestParam Integer status, @RequestParam(required = false) String operator); - - /** - * 查询流程模型使用的分类列表 - * - * @return - */ - @Operation(summary = "查询流程模型使用的分类列表") - @GetMapping("/api/process/model/category/ids") - @InvokeMode(SYNC) - List getModelCategoryList(); - - /** - * 查询模型的租户集合 - * - * @return - */ - @Operation(summary = "查询模型的租户集合") - @GetMapping("/api/process/model/tenant/ids") - @InvokeMode(SYNC) - List getModelTenantIds(); - - /** - * 创建审批流程并带上表单 - * - * @param dto - * @return - */ - @Operation(summary = "创建审批流程并带上表单") - @PostMapping("/api/process/instance/form/create") - @Manageable - @InvokeMode(SYNC) - String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); - - /** - * 查询所有的审批流 - * - * @return - */ - @Operation(summary = "查询所有的审批流") - @PostMapping("/api/process/instance/page/all") - @Manageable - @InvokeMode(SYNC) - BpmPageResult getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); - - /** - * 我发起的审批列表 - */ - @Operation(summary = "我发起的审批列表") - @PostMapping("/api/process/instance/page/my") - @Manageable - @InvokeMode(SYNC) - BpmPageResult getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); - - /** - * 更新流程定义的状态 - * - * @param processDefinitionId 流程定义的编号 - * @param status 1, "active"; 2, "suspended" - */ - @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") - @PutMapping("/api/process/instance/status/update") - @Manageable - @InvokeMode(SYNC) - Boolean updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); - - /** - * 获取审批流程实例的运行图 - * - * @param processInstanceId - * @param tenantId - * @return - */ - @Operation(summary = "获取审批流程实例的运行图") - @GetMapping("/api/process/instance/graphical") - @Manageable - @InvokeMode(SYNC) - ObjectNode processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 推断指定流程实例的所有节点执行顺序 - * - * @return - */ - @Operation(summary = "推断指定流程实例的所有节点执行顺序") - @GetMapping("/api/process/instance/node/forecasting") - @Manageable - @InvokeMode(SYNC) - List processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 推断指定流程实例的过滤掉部分节点执行顺序 - * - * @param allNode 如果为真时,相当于调用 {@link ProcessInstanceApi#processInstanceNodeForecast(String, String)} 方法,切会直接丢弃 nodeDefinitionKeys 参数 - * 如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点 - * @return - */ - @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") - @GetMapping("/api/process/instance/node/filter/forecasting") - @Manageable - @InvokeMode(SYNC) - List processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List nodeDefinitionKeys); - - /** - * 查询实例的租户集合 - * - * @return - */ - @Operation(summary = "查询实例的租户集合") - @GetMapping("/api/process/instance/tenant/ids") - @Manageable - @InvokeMode(SYNC) - List getTenantIds(); - - /** - * 校验指定流程实例下,是否存在指定的审批人 - * - * @return true 是在当前流程实例中,存在指定的审批人 - */ - @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") - @PostMapping("/api/process/instance/check/approver") - @Manageable - @InvokeMode(SYNC) - Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); - - /** - * 将死信队列中的任务转移到正常 JOB 队列中 - *

- * 入参是二选一:当只有 jobId 时,仅将指定的 JOB 转移到正常的队列中; - * 而传入的是具体的实例 ID,那么会将这个流程下的所有在死信队列中的任务都转移到正常的队列中 - * - * @param jobId 具体的 JOB ID - * @param procInstId 具体的实例 ID - * @return - */ - @GetMapping("/api/process/job/dead-letter/resume") - @Manageable - Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); - - /** - * 获取指定业务分类 - * - * @return - */ - @GetMapping("/api/process/category/get") - @InvokeMode(SYNC) - CategoryItemVO get(@RequestParam Long id); - - /** - * 获取指定业务分类集合 - * - * @param ids - * @return - */ - @GetMapping("/api/process/category/getByIds") - @InvokeMode(SYNC) - List getByIds(@RequestParam List ids); - - /** - * 获取指定业务分类集合 - * - * @param values - * @return - */ - @GetMapping("/api/process/category/getByValues") - @InvokeMode(SYNC) - List getByValues(@RequestParam List values); - - /** - * 新增业务分类 - * - * @return - */ - @PostMapping("/api/process/category/create") - @InvokeMode(SYNC) - CategoryItemVO create(@Validated @RequestBody CategoryCreateDTO req); - - /** - * 更新业务分类 - * - * @return - */ - @PutMapping("/api/process/category/update") - @InvokeMode(SYNC) - CategoryItemVO update(@Validated @RequestBody CategoryUpdateDTO dto); - - /** - * 删除指定业务分类 - * - * @param id - * @return - */ - @DeleteMapping("/api/process/category/delete") - @InvokeMode(SYNC) - Boolean delete(@RequestParam Long id); - - /** - * 更新指定分类状态 - * - * @param id - * @param state - * @return - */ - @PutMapping("/api/process/category/update/state") - @InvokeMode(SYNC) - Boolean updateState(@RequestParam Long id, @RequestParam Boolean state); - - /** - * 获取指定业务分类集合 - * - * @return - */ - @PostMapping("/api/process/category/list") - @InvokeMode(SYNC) - List list(@RequestBody CategorySearchDTO dto); - - /** - * 搜索业务分类 - * - * @return - */ - @PostMapping("/api/process/category/page/search") - @InvokeMode(SYNC) - BpmPageResult search(@RequestBody CategorySearchDTO dto); - - /** - * 业务分类创建黑白名单配置项 - * - * @param dto - * @return - */ - @PostMapping("/api/process/category/config/create") - @InvokeMode(SYNC) - Boolean createConfig(@RequestBody CategoryConfigCreateDTO dto); - - /** - * 删除指定分类的配置项数据 - * - * @param id - * @return - */ - @DeleteMapping("/api/process/category/config/delete/{id}") - @InvokeMode(SYNC) - Boolean deleteConfig(@PathVariable Long id); - - /** - * 业务分类黑白名单查询 - * - * @return - */ - @PostMapping("/api/process/category/config/page/search") - @InvokeMode(SYNC) - BpmPageResult configSearch(@RequestBody CategoryConfigSearchDTO dto); - - /** - * 更新业务分类的配置类型 - * - * @param id - * @param configType - * @return - */ - @PostMapping("/api/process/category/config/type/update") - @InvokeMode(SYNC) - Boolean updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType); - - /** - * 用于业务方判断指定的业务分类的黑白名单配置 - * - * @param tenantId 租户ID - * @param categoryCode 业务分类编码 - * @return true: 可以发起创建流程实例, false: 不可用 - */ - @GetMapping("/api/process/category/check/status") - @InvokeMode(SYNC) - Boolean checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode); - - /** - * 为指定流程新增变量 - */ - @PostMapping("/api/process/variable/create/{executionId}") - @InvokeMode(SYNC) - Void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); - - /** - * 仅更新流程已存在的变量 - * - * @param executionId - * @param restVariable - * @return - */ - @PostMapping("/api/process/variable/update/{executionId}") - @InvokeMode(SYNC) - Void updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); - - /** - * 批量删除流程变量 - */ - @DeleteMapping("/api/process/variable/delete/{executionId}") - @InvokeMode(SYNC) - Void deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); - - /** - * 催办 - * - * @param dto - * @return - */ - @Operation(summary = "审批流程催办") - @PostMapping("/api/process/task/remind") - @Manageable - @InvokeMode(SYNC) - Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); - - /** - * 添加附件 - * - * @param dto - * @return - */ - @Operation(summary = "添加附件") - @PostMapping("/api/process/task/attachment") - @Manageable - Void addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); - - /** - * 待审核列表 - */ - @Operation(summary = "待审核列表") - @GetMapping("/api/process/task/page/todo") - @Manageable - @InvokeMode(SYNC) - BpmPageResult getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); - - /** - * 已完成的审批列表 - */ - @Operation(summary = "已完成的审批列表") - @GetMapping("/api/process/task/page/done") - @Manageable - @InvokeMode(SYNC) - BpmPageResult getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); - - /** - * 获取指定流程实例的审批过程信息 - *

- * 同一层级结构 - */ - @Operation(summary = "获取指定流程实例的审批过程信息") - @GetMapping("/api/process/task/list/flat") - @Manageable - @InvokeMode(SYNC) - List getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 获取指定流程实例的审批过程信息 - *

- * 分组结构 - */ - @Operation(summary = "获取指定流程实例的审批过程信息") - @GetMapping("/api/process/task/list/group") - @Manageable - @InvokeMode(SYNC) - List getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); - - /** - * 获取实例正在审核的人列表 - */ - @Operation(summary = "获取实例正在审核的人列表") - @GetMapping("/api/process/task/active/list") - @Manageable - @InvokeMode(SYNC) - List getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); - - /** - * 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID - * - * @return - */ - @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") - @GetMapping("/api/process/task/find") - @Manageable - @InvokeMode(SYNC) - String findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - - /** - * 根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID - * - * @return - */ - @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") - @GetMapping("/api/process/task/batch/find") - @Manageable - @InvokeMode(SYNC) - Map findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); - - /** - * 获取活跃的流程定义分页 - */ - @GetMapping("/api/process/definition/page") - @InvokeMode(SYNC) - BpmPageResult getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto); - - /** - * 通过模型 ID 更新流程定义 - * - * @param dto - * @return - */ - @PutMapping("/api/process/definition/update") - @InvokeMode(SYNC) - Boolean updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto); - - /** - * 获得指定定义编号对应的流程定义内容 - * - * @param processDefinitionId 编号 - * @return 流程定义 - */ - @GetMapping("/api/process/definition/get") - @InvokeMode(SYNC) - BpmnProcessDefinitionVO getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId); - - /** - * 获得 deploymentId 对应的 ProcessDefinition - * - * @param deploymentId 部署编号 - * @return 流程定义 - */ - @GetMapping("/api/process/definition/getByDeploymentId") - @InvokeMode(SYNC) - BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(@NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId); - - /** - * 获得流程定义标识对应的激活的流程定义 - * - * @param key 流程定义的标识 - * @return 流程定义 - */ - @GetMapping("/api/process/definition/active/getByKey") - @InvokeMode(SYNC) - BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key); - - /** - * 挂起/激活流程, - * 激活:SuspensionState.ACTIVE.getStateCode() - * 挂起:SuspensionState.SUSPENDED.getStateCode() - * {@see SuspensionState} - */ - @PutMapping("/api/process/definition/state/update") - @InvokeMode(SYNC) - Boolean getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer state); - - /** - * 获取指定模型的定义 ID - * - * @return 流程定义ID - */ - @GetMapping("/api/process/definition/active/getByCategory") - @InvokeMode(SYNC) - String getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category); - - /** - * 获取指定模型激活的流程定义 JSON 模型 - * - * @return 流程定义ID - */ - @GetMapping("/api/process/definition/active/json/model") - @InvokeMode(SYNC) - BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category, @RequestParam(required = false) String tenantId); - - /** - * 删除流程部署及定义 - * - * @param deploymentId 流程定义部署 ID - * @param cascade 是否级联参数定义对应的流程实例及 job 等管理内容 - * @return - */ - @GetMapping("/api/process/definition/delete") - @InvokeMode(SYNC) - Void delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); - - /** - * 强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法 - *

-     *   workflowManageService.sync().getTenantIds();
-     * 
- */ - default WorkflowManageService sync() { - ThreadUtil.set(SYNC); - return this; - } - - /** - * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 - *
-     *   workflowManageService.async().getTenantIds();
-     * 
- */ - default WorkflowManageService async() { - ThreadUtil.set(ASYNC); - return this; - } } From 0b2226a66d68b1c7db358a274bb5dacbc3a5aa6f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 9 Sep 2024 20:50:19 +0800 Subject: [PATCH 039/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=20Starter=20=E7=9A=84=E5=BC=82=E5=B8=B8=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index 578f05d3a..f29893c33 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -113,6 +113,7 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { }); } catch (Exception e) { log.warn("monitor Broadcast DLQ error: {}", e.getMessage(), e); + log.warn("该异常信息是正常的,不影响服务启动!"); } } From e5ebb34dbff2f18bb7f7a38a7dc30e4c6b2716e2 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 14:45:24 +0800 Subject: [PATCH 040/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=94=9F=E6=88=90=20CoreService=20=E5=92=8C=20ManageService=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=9B=A0=E4=B8=BA=E5=8E=9F=E7=B1=BB=E4=B8=A2=E5=A4=B1?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=20import=20=E5=AF=BC=E8=87=B4=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/WorkflowEngineFeignClient.java | 22 +++++++++++++++++++ .../client/feign/bpmn/ProcessActivityApi.java | 2 ++ .../feign/bpmn/ProcessDefinitionApi.java | 2 ++ .../client/feign/bpmn/ProcessInstanceApi.java | 2 ++ .../client/feign/bpmn/ProcessJobApi.java | 7 ++---- .../client/feign/bpmn/ProcessModelApi.java | 2 ++ .../client/feign/bpmn/ProcessTaskApi.java | 2 ++ .../client/feign/bpmn/ProcessVariableApi.java | 2 ++ .../feign/manage/ProcessCategoryApi.java | 2 ++ .../client/feign/manage/ProcessConfigApi.java | 2 ++ .../api/CoreServiceCodeGeneration.java | 2 +- .../api/ManageServiceCodeGeneration.java | 2 +- 12 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/WorkflowEngineFeignClient.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/WorkflowEngineFeignClient.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/WorkflowEngineFeignClient.java new file mode 100644 index 000000000..f6dc5a700 --- /dev/null +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/annotation/WorkflowEngineFeignClient.java @@ -0,0 +1,22 @@ +package cn.axzo.workflow.client.annotation; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 用于开启原生 FeignClient + * + * @author wangli + * @since 2024-09-10 11:30 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface WorkflowEngineFeignClient { +} diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java index 83840e58b..c8e93323a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessActivityApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import cn.azxo.framework.common.model.CommonResponse; @@ -19,6 +20,7 @@ import javax.validation.constraints.NotBlank; * @since 2023/11/17 16:28 */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient public interface ProcessActivityApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java index 7a04b923a..ccdb2696a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessDefinitionApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -28,6 +29,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * @since 2023/9/21 16:25 */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient @Manageable public interface ProcessDefinitionApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java index aa14705d7..4b43d1b74 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessInstanceApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; @@ -45,6 +46,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * @since 2023/9/21 16:26 */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient public interface ProcessInstanceApi { /** * 创建审批流程 diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index 906bbc1f3..e38ae9caa 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -1,16 +1,13 @@ package cn.axzo.workflow.client.feign.bpmn; -import cn.axzo.workflow.client.config.CommonFeignConfiguration; -import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.common.annotation.Manageable; import cn.azxo.framework.common.model.CommonResponse; -import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; -import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; - //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient public interface ProcessJobApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java index 8fc7f7f00..d06e7c0ea 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessModelApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -33,6 +34,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * @since 2023/9/21 15:47 */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient @Manageable public interface ProcessModelApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index 0d9828443..f21b11463 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; @@ -44,6 +45,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * @since 2023/9/21 16:26 */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient public interface ProcessTaskApi { /** diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java index 2c219f88b..614216a7a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessVariableApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.bpmn; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -21,6 +22,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; * 流程变量api */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient @Manageable public interface ProcessVariableApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java index aa1d51447..7dea9ce08 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessCategoryApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.manage; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -36,6 +37,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient @Manageable public interface ProcessCategoryApi { diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java index 5f56d5d64..13bf5e8e0 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/ProcessConfigApi.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.client.feign.manage; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.client.config.CommonFeignConfiguration; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; @@ -22,6 +23,7 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; */ //@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class) +@WorkflowEngineFeignClient @Manageable public interface ProcessConfigApi { diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index ec975d1e7..c5058d286 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -170,7 +170,7 @@ public class CoreServiceCodeGeneration { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service\r\n

\r\n" + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); - classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") + classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index db51d4146..1df396b15 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -160,7 +160,7 @@ public class ManageServiceCodeGeneration { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service\r\n

\r\n" + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); - classOrInterfaceDeclaration.addAndGetAnnotation("FeignClient") + classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); From aed3f25f81412a406d5ea9e4294acccdb413c83b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 14:46:45 +0800 Subject: [PATCH 041/139] =?UTF-8?q?feat(REQ-2924)=20-=20Starter=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=A7=E5=88=B6=E6=97=A7=E7=89=88=E6=9C=AC?= =?UTF-8?q?=20Feign=20=E6=8E=A5=E5=8F=A3=20Bean=20=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E6=97=B6=E9=9C=80=E5=BC=BA=E5=88=B6=E4=BF=AE=E6=94=B9=E5=8E=9F?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterFeignClientConfiguration.java | 39 + ...orkflowEngineStarterAutoConfiguration.java | 4 +- .../WorkflowEngineStarterProperties.java | 12 + .../starter/api/WorkflowCoreService.java | 337 +++++++- .../starter/api/WorkflowManageService.java | 719 +++++++++++++++++- .../MetaFeignClientEnableSelector.java | 320 ++++++++ 6 files changed, 1422 insertions(+), 9 deletions(-) create mode 100644 workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java index 0c6b6e763..91d071282 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java @@ -1,10 +1,48 @@ package cn.axzo.workflow.starter; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.api.WorkflowManageService; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.BeanExpressionResolver; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.cloud.openfeign.FeignClientFactoryBean; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; /** * 根据参数动态实例化可用 Bean @@ -25,4 +63,5 @@ public class StarterFeignClientConfiguration { @EnableFeignClients(clients = WorkflowManageService.class) public static class WorkflowManageServiceClient { } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 232c50771..466f464d9 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -25,6 +25,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController; +import cn.axzo.workflow.starter.selector.MetaFeignClientEnableSelector; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; @@ -51,7 +52,7 @@ import java.util.List; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) -@Import({StarterFeignClientConfiguration.class, StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class}) +@Import({StarterFeignClientConfiguration.class, StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class, MetaFeignClientEnableSelector.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @@ -147,4 +148,5 @@ public class WorkflowEngineStarterAutoConfiguration { Environment environment) { return new WorkflowEngineStarterDefaultMQMonitor(mqAdminExtObjectProvider, broadcastDLQProcessorObjectProvider, rpcDLQProcessorObjectProvider, workflowEngineStarterProperties, environment); } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 584d75484..9d103a013 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -18,6 +18,10 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; */ @ConfigurationProperties(prefix = "workflow.engine.starter") public class WorkflowEngineStarterProperties { + /** + * + */ + private Boolean metaFeign = false; /** * 特殊用途,不建议接入方使用 */ @@ -84,6 +88,14 @@ public class WorkflowEngineStarterProperties { */ private Boolean alert = false; + public Boolean getMetaFeign() { + return metaFeign; + } + + public void setMetaFeign(Boolean metaFeign) { + this.metaFeign = metaFeign; + } + public Boolean getManageable() { return manageable; } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 92b09c7e4..9eb987904 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -1,10 +1,339 @@ package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; +import cn.azxo.framework.common.model.CommonResponse; +import io.swagger.v3.oas.annotations.Operation; +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 javax.validation.constraints.NotBlank; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PutMapping; +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import javax.validation.constraints.NotEmpty; + /** - * just for compiler - * - * @author wangli - * @since 2024-09-09 18:25 + * Workflow Engine Starter Core Service + *

+ * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ +@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { + + /** + * 业务节点唤醒, 该节点废弃,请换成 {@link ProcessActivityApi#trigger(cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO)} 接口 + *

+ * 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行 + */ + @Deprecated + @GetMapping("/api/process/activity/trigger") + Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId); + + /** + * 业务节点唤醒 + * + * @param dto + * @return + */ + @PostMapping("/api/process/activity/trigger") + Boolean trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto); + + /** + * 业务节点设置审批人, 不支持重复设置 + *

+ * 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人 + *

+ * 注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。 + * + * @param dto + * @return + */ + @PostMapping("/api/process/activity/assignee/set") + @Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人") + Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto); + + /** + * 创建审批流程 + * + *

+     *   MQ 触发规则:
+     *     1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
+     *     2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCreateDTO} + */ + @Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件") + @PostMapping("/api/process/instance/create") + @InvokeMode(SYNC) + String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto); + + /** + * 发起人主动撤回审核 + * + *
+     *   MQ 触发规则:
+     *     1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
+     *     2. 当前流程实例会触发 process-instance-cancelled 事件
+     * 
+ * + * @param dto {@link BpmnProcessInstanceCancelDTO} + * @return + */ + @Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件") + @DeleteMapping("/api/process/instance/cancel") + Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto); + + /** + * 中止流程实例 + * + * @param dto + * @return + */ + @Operation(summary = "中止流程实例") + @DeleteMapping("/api/process/instance/abort") + Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto); + + /** + * 批量中止流程实例 + * + * @param dtos + * @return + */ + @Operation(summary = "批量中止流程实例") + @DeleteMapping("/api/process/instance/batch/abort") + BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List dtos); + + /** + * 抄送流程实例(未实现) + * + * @param dto + * @return + */ + @Operation(summary = "抄送流程实例") + @PostMapping("/api/process/instance/carbon-copy") + @Deprecated + Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto); + + /** + * 获得流程实例 + * + * @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询 + * @return 流程实例, 租户Id不必传 + */ + @Operation(summary = "获得流程实例") + @GetMapping("/api/process/instance/get") + @InvokeMode(SYNC) + BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto); + + /** + * 获取指定流程实例的流程变量 + * + * @param processInstanceId + * @param tenantId + * @return + */ + @Operation(summary = "获取指定流程实例的流程变量") + @GetMapping("/api/process/instance/cooperation-org") + @InvokeMode(SYNC) + Map getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取指定流程的日志 + * + * @param dto + * @return + */ + @Operation(summary = "获取指定流程的日志") + @PostMapping("/api/process/instance/logs") + @InvokeMode(SYNC) + BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); + + /** + * 同意 + * + *
+     * MQ 触发规则:
+     *  1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,
+     *  如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)
+     *  2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件
+     *  2.2. 流程实例正常结束会触发 process-instance-completed 事件
+     * 
+ */ + @Operation(summary = "同意,MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件),2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件,2.2. 流程实例正常结束会触发 process-instance-completed 事件") + @PostMapping("/api/process/task/approve") + Boolean approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量同意 + * + * @param dtos + * @return + */ + @Operation(summary = "批量同意") + @PostMapping("/api/process/task/batch/approve") + BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); + + /** + * 获取当前节点可退回节点选项列表 + * @param taskId 当前任务id + * @return 可以退回节点列表 + */ + @Operation(summary = "获取当前节点可退回节点选项列表") + @GetMapping("/api/process/task/back/optional/nodes") + List getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); + + /** + * 回退到指定节点 + * @param dto + * @return + */ + @Operation(summary = "回退") + @PostMapping("/api/process/task/back") + Boolean backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); + + /** + * 驳回 + * + *
+     * MQ 触发规则:
+     *   1. 当前审批任务会触发 process-task-deleted 事件
+     *   2. 当前流程实例会触发 process-instance-rejected 事件
+     * 
+ */ + @Operation(summary = "驳回,MQ 触发规则:1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件") + @PostMapping("/api/process/task/reject") + Boolean rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto); + + /** + * 批量驳回 + * + * @param dtos 批量请求参数 + * @return + */ + @PostMapping("/api/process/task/batch/reject") + BatchOperationResultVO batchRejectTask(@Validated @RequestBody List dtos); + + /** + * 转交 + * + * @param dto + * @return + */ + @Operation(summary = "直接修改审批任务的审批人") + @PostMapping("/api/process/task/transfer") + Boolean transferTask(@Validated @RequestBody BpmnTaskTransferDTO dto); + + /** + * 批量转交 + * + * @param dtos + * @return + */ + @Operation(summary = "批量修改审批任务的审批人") + @PostMapping("/api/process/task/batch/transfer") + BatchOperationResultVO batchTransferTask(@Validated @RequestBody List dtos); + + /** + * 评论 + * + * @param dto 评论请求参数 + * @return + */ + @Operation(summary = "审批流程评论") + @PostMapping("/api/process/task/comment") + Boolean commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto); + + /** + * 加签 + * + * @param dto 加签请求参数 + * @return + */ + @Operation(summary = "审批流程加签") + @PostMapping("/api/process/task/countersign") + Boolean countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + + /** + * 暂停流程任务,并创建机器人节点,等待业务推动 + * + * @param dto + * @return 返回机器人节点任务 ID + */ + @Operation(summary = "创建机器人节点, 暂停流程任务") + @PostMapping("/api/process/task/robot/create") + String createRobotTask(@Validated @RequestBody BpmnRobotTaskCreateDTO dto); + + /** + * 完成机器人节点 + * + * @param dto + * @return + */ + @Operation(summary = "完成机器人节点, 继续流程任务") + @PostMapping("/api/process/task/robot/complete") + Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto); + + /** + * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + *
+     *   workflowCoreService.async().createProcessInstance();
+     * 
+ */ + default WorkflowCoreService sync() { + ThreadUtil.set(SYNC); + return this; + } + + default WorkflowCoreService async() { + ThreadUtil.set(ASYNC); + return this; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 2d5ba5e8d..b6c262f2a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -1,10 +1,721 @@ package cn.axzo.workflow.starter.api; +import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; +import cn.axzo.workflow.common.util.ThreadUtil; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; +import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; +import cn.axzo.workflow.client.config.CommonFeignConfiguration; +import cn.axzo.workflow.common.annotation.InvokeMode; +import cn.axzo.workflow.common.annotation.Manageable; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; +import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import java.util.List; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO; +import cn.axzo.workflow.common.model.response.BpmPageResult; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelExtVO; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO; +import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO; +import com.fasterxml.jackson.databind.node.ObjectNode; +import javax.annotation.Nullable; +import java.util.Map; +import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO; +import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; +import cn.axzo.workflow.common.model.request.category.CategoryUpdateDTO; +import cn.axzo.workflow.common.model.response.category.CategoryConfigItemVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; +import org.springframework.web.bind.annotation.PathVariable; +import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; +import javax.validation.constraints.NotEmpty; +import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; + /** - * just for compiler - * - * @author wangli - * @since 2024-09-09 18:26 + * Workflow Engine Starter Management Service + *

+ * 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 */ +@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { + + /** + * 获取流程操作按钮列表 + * + * @return 流程操作按钮列表 + */ + @GetMapping("/api/process/config/button/list") + @InvokeMode(SYNC) + List getDefaultButtons(); + + /** + * 流程模型列表 + * + * @param dto + * @return + */ + @Operation(summary = "流程模型列表") + @GetMapping("/api/process/model/page") + @InvokeMode(SYNC) + BpmPageResult page(@Validated @RequestBody BpmnModelSearchDTO dto); + + /** + * 创建流程, + * return modelId的主键 + */ + @Operation(summary = "创建流程模型") + @PostMapping("/api/process/model/create") + @InvokeMode(SYNC) + String create(@Validated @RequestBody BpmnModelCreateDTO dto); + + /** + * 通过模型 ID 获取模型 + */ + @Operation(summary = "通过模型ID查询指定流程模型") + @GetMapping("/api/process/model/get") + @InvokeMode(SYNC) + BpmnModelDetailVO getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false) String tenantId); + + /** + * 通过模型 KEY 获取模型 + */ + @Operation(summary = "通过模型KEY查询指定流程模型") + @GetMapping("/api/process/model/getByKey") + @InvokeMode(SYNC) + BpmnModelDetailVO getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId); + + /** + * 校验是否能更新模型即其关联的流程定义内容 + *

+ * 偏向业务的接口,flowable 引擎是站在流程定义维度进行激活和挂起 + * + * @return true 能更新,表明该模型关联的所有定义版本都是挂起状态 + */ + @Operation(summary = "获取指定模型的扩展属性") + @GetMapping("/api/process/model/ext") + @InvokeMode(SYNC) + BpmnModelExtVO getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId); + + /** + * 修改流程信息 + */ + @Operation(summary = "更新流程模型") + @PutMapping("/api/process/model/update") + @InvokeMode(SYNC) + String update(@RequestBody BpmnModelUpdateDTO dto); + + /** + * 通过模型 ID 部署模型 + * + * @return 部署完成的流程定义Id + */ + @Operation(summary = "通过模型 ID 部署流程模型") + @PostMapping("/api/process/model/deploy") + @InvokeMode(SYNC) + String deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String modelTenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 KEY 部署模型 + * + * @return 部署完成的流程定义Id + */ + @Operation(summary = "通过模型 KEY 部署流程模型") + @PostMapping("/api/process/model/deployByKey") + @InvokeMode(SYNC) + String deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey, @NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 ID 取消部署流程模型 + * + * @param processModelId + * @param tenantId + * @param operator + * @return + */ + @Operation(summary = "通过模型 ID 取消部署流程模型") + @PostMapping("/api/process/model/undeploy") + @InvokeMode(SYNC) + Void unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId, @RequestParam(required = false) String operator); + + /** + * 通过模型 ID 删除模型 + */ + @Operation(summary = "删除指定模型 ID 的流程模型") + @DeleteMapping("/api/process/model/delete") + @InvokeMode(SYNC) + Void deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId, @RequestParam(required = false, defaultValue = "") String tenantId); + + /** + * 通过模型 KEY 删除模型 + * + * @param processModelKey + * @param tenantId + * @return + */ + @Operation(summary = "删除指定模型 KEY 的流程模型") + @DeleteMapping("/api/process/model/deleteByKey") + @InvokeMode(SYNC) + Void deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey, @RequestParam(required = false, defaultValue = "") String tenantId); + + /** + * 通过模型 ID 修改模型状态 + * + * @param modelId + * @param status + * @param operator + * @return + */ + @Operation(summary = "修改模型状态") + @PostMapping("/api/process/model/changeStatus") + @InvokeMode(SYNC) + Void changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId, @NotNull(message = "状态不能为空") @RequestParam Integer status, @RequestParam(required = false) String operator); + + /** + * 查询流程模型使用的分类列表 + * + * @return + */ + @Operation(summary = "查询流程模型使用的分类列表") + @GetMapping("/api/process/model/category/ids") + @InvokeMode(SYNC) + List getModelCategoryList(); + + /** + * 查询模型的租户集合 + * + * @return + */ + @Operation(summary = "查询模型的租户集合") + @GetMapping("/api/process/model/tenant/ids") + @InvokeMode(SYNC) + List getModelTenantIds(); + + /** + * 创建审批流程并带上表单 + * + * @param dto + * @return + */ + @Operation(summary = "创建审批流程并带上表单") + @PostMapping("/api/process/instance/form/create") + @Manageable + @InvokeMode(SYNC) + String createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto); + + /** + * 查询所有的审批流 + * + * @return + */ + @Operation(summary = "查询所有的审批流") + @PostMapping("/api/process/instance/page/all") + @Manageable + @InvokeMode(SYNC) + BpmPageResult getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto); + + /** + * 我发起的审批列表 + */ + @Operation(summary = "我发起的审批列表") + @PostMapping("/api/process/instance/page/my") + @Manageable + @InvokeMode(SYNC) + BpmPageResult getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto); + + /** + * 更新流程定义的状态 + * + * @param processDefinitionId 流程定义的编号 + * @param status 1, "active"; 2, "suspended" + */ + @Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例") + @PutMapping("/api/process/instance/status/update") + @Manageable + @InvokeMode(SYNC) + Boolean updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status); + + /** + * 获取审批流程实例的运行图 + * + * @param processInstanceId + * @param tenantId + * @return + */ + @Operation(summary = "获取审批流程实例的运行图") + @GetMapping("/api/process/instance/graphical") + @Manageable + @InvokeMode(SYNC) + ObjectNode processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 推断指定流程实例的所有节点执行顺序 + * + * @return + */ + @Operation(summary = "推断指定流程实例的所有节点执行顺序") + @GetMapping("/api/process/instance/node/forecasting") + @Manageable + @InvokeMode(SYNC) + List processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 推断指定流程实例的过滤掉部分节点执行顺序 + * + * @param allNode 如果为真时,相当于调用 {@link ProcessInstanceApi#processInstanceNodeForecast(String, String)} 方法,切会直接丢弃 nodeDefinitionKeys 参数 + * 如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点 + * @return + */ + @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") + @GetMapping("/api/process/instance/node/filter/forecasting") + @Manageable + @InvokeMode(SYNC) + List processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId, @Nullable @RequestParam(required = false) String tenantId, @RequestParam(required = false, defaultValue = "false") Boolean allNode, @Nullable @RequestParam(required = false) List nodeDefinitionKeys); + + /** + * 查询实例的租户集合 + * + * @return + */ + @Operation(summary = "查询实例的租户集合") + @GetMapping("/api/process/instance/tenant/ids") + @Manageable + @InvokeMode(SYNC) + List getTenantIds(); + + /** + * 校验指定流程实例下,是否存在指定的审批人 + * + * @return true 是在当前流程实例中,存在指定的审批人 + */ + @Operation(summary = "校验指定流程实例下,是否存在指定的审批人") + @PostMapping("/api/process/instance/check/approver") + @Manageable + @InvokeMode(SYNC) + Boolean checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto); + + /** + * 将死信队列中的任务转移到正常 JOB 队列中 + *

+ * 入参是二选一:当只有 jobId 时,仅将指定的 JOB 转移到正常的队列中; + * 而传入的是具体的实例 ID,那么会将这个流程下的所有在死信队列中的任务都转移到正常的队列中 + * + * @param jobId 具体的 JOB ID + * @param procInstId 具体的实例 ID + * @return + */ + @GetMapping("/api/process/job/dead-letter/resume") + @Manageable + Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + + /** + * 获取指定业务分类 + * + * @return + */ + @GetMapping("/api/process/category/get") + @InvokeMode(SYNC) + CategoryItemVO get(@RequestParam Long id); + + /** + * 获取指定业务分类集合 + * + * @param ids + * @return + */ + @GetMapping("/api/process/category/getByIds") + @InvokeMode(SYNC) + List getByIds(@RequestParam List ids); + + /** + * 获取指定业务分类集合 + * + * @param values + * @return + */ + @GetMapping("/api/process/category/getByValues") + @InvokeMode(SYNC) + List getByValues(@RequestParam List values); + + /** + * 新增业务分类 + * + * @return + */ + @PostMapping("/api/process/category/create") + @InvokeMode(SYNC) + CategoryItemVO create(@Validated @RequestBody CategoryCreateDTO req); + + /** + * 更新业务分类 + * + * @return + */ + @PutMapping("/api/process/category/update") + @InvokeMode(SYNC) + CategoryItemVO update(@Validated @RequestBody CategoryUpdateDTO dto); + + /** + * 删除指定业务分类 + * + * @param id + * @return + */ + @DeleteMapping("/api/process/category/delete") + @InvokeMode(SYNC) + Boolean delete(@RequestParam Long id); + + /** + * 更新指定分类状态 + * + * @param id + * @param state + * @return + */ + @PutMapping("/api/process/category/update/state") + @InvokeMode(SYNC) + Boolean updateState(@RequestParam Long id, @RequestParam Boolean state); + + /** + * 获取指定业务分类集合 + * + * @return + */ + @PostMapping("/api/process/category/list") + @InvokeMode(SYNC) + List list(@RequestBody CategorySearchDTO dto); + + /** + * 搜索业务分类 + * + * @return + */ + @PostMapping("/api/process/category/page/search") + @InvokeMode(SYNC) + BpmPageResult search(@RequestBody CategorySearchDTO dto); + + /** + * 业务分类创建黑白名单配置项 + * + * @param dto + * @return + */ + @PostMapping("/api/process/category/config/create") + @InvokeMode(SYNC) + Boolean createConfig(@RequestBody CategoryConfigCreateDTO dto); + + /** + * 删除指定分类的配置项数据 + * + * @param id + * @return + */ + @DeleteMapping("/api/process/category/config/delete/{id}") + @InvokeMode(SYNC) + Boolean deleteConfig(@PathVariable Long id); + + /** + * 业务分类黑白名单查询 + * + * @return + */ + @PostMapping("/api/process/category/config/page/search") + @InvokeMode(SYNC) + BpmPageResult configSearch(@RequestBody CategoryConfigSearchDTO dto); + + /** + * 更新业务分类的配置类型 + * + * @param id + * @param configType + * @return + */ + @PostMapping("/api/process/category/config/type/update") + @InvokeMode(SYNC) + Boolean updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType); + + /** + * 用于业务方判断指定的业务分类的黑白名单配置 + * + * @param tenantId 租户ID + * @param categoryCode 业务分类编码 + * @return true: 可以发起创建流程实例, false: 不可用 + */ + @GetMapping("/api/process/category/check/status") + @InvokeMode(SYNC) + Boolean checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode); + + /** + * 为指定流程新增变量 + */ + @PostMapping("/api/process/variable/create/{executionId}") + @InvokeMode(SYNC) + Void createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); + + /** + * 仅更新流程已存在的变量 + * + * @param executionId + * @param restVariable + * @return + */ + @PostMapping("/api/process/variable/update/{executionId}") + @InvokeMode(SYNC) + Void updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId, @RequestBody @Validated RestBpmnProcessVariable restVariable); + + /** + * 批量删除流程变量 + */ + @DeleteMapping("/api/process/variable/delete/{executionId}") + @InvokeMode(SYNC) + Void deleteVariables(@PathVariable("executionId") String executionId, @RequestParam String variableNames, @RequestParam(value = "scope", required = false) String scope); + + /** + * 催办 + * + * @param dto + * @return + */ + @Operation(summary = "审批流程催办") + @PostMapping("/api/process/task/remind") + @Manageable + @InvokeMode(SYNC) + Boolean remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto); + + /** + * 添加附件 + * + * @param dto + * @return + */ + @Operation(summary = "添加附件") + @PostMapping("/api/process/task/attachment") + @Manageable + Void addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto); + + /** + * 待审核列表 + */ + @Operation(summary = "待审核列表") + @GetMapping("/api/process/task/page/todo") + @Manageable + @InvokeMode(SYNC) + BpmPageResult getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 已完成的审批列表 + */ + @Operation(summary = "已完成的审批列表") + @GetMapping("/api/process/task/page/done") + @Manageable + @InvokeMode(SYNC) + BpmPageResult getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 同一层级结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/flat") + @Manageable + @InvokeMode(SYNC) + List getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " + "不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取指定流程实例的审批过程信息 + *

+ * 分组结构 + */ + @Operation(summary = "获取指定流程实例的审批过程信息") + @GetMapping("/api/process/task/list/group") + @Manageable + @InvokeMode(SYNC) + List getTaskListGroupByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + + /** + * 获取实例正在审核的人列表 + */ + @Operation(summary = "获取实例正在审核的人列表") + @GetMapping("/api/process/task/active/list") + @Manageable + @InvokeMode(SYNC) + List getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @NotBlank(message = "租户不能为空") @RequestParam String tenantId); + + /** + * 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID + * + * @return + */ + @Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID") + @GetMapping("/api/process/task/find") + @Manageable + @InvokeMode(SYNC) + String findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + /** + * 根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID + * + * @return + */ + @Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID") + @GetMapping("/api/process/task/batch/find") + @Manageable + @InvokeMode(SYNC) + Map findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List processInstanceIds, @RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId); + + /** + * 获取活跃的流程定义分页 + */ + @GetMapping("/api/process/definition/page") + @InvokeMode(SYNC) + BpmPageResult getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto); + + /** + * 通过模型 ID 更新流程定义 + * + * @param dto + * @return + */ + @PutMapping("/api/process/definition/update") + @InvokeMode(SYNC) + Boolean updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto); + + /** + * 获得指定定义编号对应的流程定义内容 + * + * @param processDefinitionId 编号 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/get") + @InvokeMode(SYNC) + BpmnProcessDefinitionVO getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId); + + /** + * 获得 deploymentId 对应的 ProcessDefinition + * + * @param deploymentId 部署编号 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/getByDeploymentId") + @InvokeMode(SYNC) + BpmnProcessDefinitionVO getProcessDefinitionByDeploymentId(@NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId); + + /** + * 获得流程定义标识对应的激活的流程定义 + * + * @param key 流程定义的标识 + * @return 流程定义 + */ + @GetMapping("/api/process/definition/active/getByKey") + @InvokeMode(SYNC) + BpmnProcessDefinitionVO getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key); + + /** + * 挂起/激活流程, + * 激活:SuspensionState.ACTIVE.getStateCode() + * 挂起:SuspensionState.SUSPENDED.getStateCode() + * {@see SuspensionState} + */ + @PutMapping("/api/process/definition/state/update") + @InvokeMode(SYNC) + Boolean getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer state); + + /** + * 获取指定模型的定义 ID + * + * @return 流程定义ID + */ + @GetMapping("/api/process/definition/active/getByCategory") + @InvokeMode(SYNC) + String getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category); + + /** + * 获取指定模型激活的流程定义 JSON 模型 + * + * @return 流程定义ID + */ + @GetMapping("/api/process/definition/active/json/model") + @InvokeMode(SYNC) + BpmnModelUpdateDTO getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId, @NotBlank(message = "分类不能为空") @RequestParam(required = false) String category, @RequestParam(required = false) String tenantId); + + /** + * 删除流程部署及定义 + * + * @param deploymentId 流程定义部署 ID + * @param cascade 是否级联参数定义对应的流程实例及 job 等管理内容 + * @return + */ + @GetMapping("/api/process/definition/delete") + @InvokeMode(SYNC) + Void delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId, @RequestParam(required = false) Boolean cascade); + + /** + * 强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法 + *

+     *   workflowManageService.sync().getTenantIds();
+     * 
+ */ + default WorkflowManageService sync() { + ThreadUtil.set(SYNC); + return this; + } + + /** + * 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法 + *
+     *   workflowManageService.async().getTenantIds();
+     * 
+ */ + default WorkflowManageService async() { + ThreadUtil.set(ASYNC); + return this; + } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java new file mode 100644 index 000000000..13599b0fd --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java @@ -0,0 +1,320 @@ +package cn.axzo.workflow.starter.selector; + +import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.BeanExpressionResolver; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled; +import org.springframework.cloud.openfeign.FeignClientFactoryBean; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +/** + * 原生 FeignClient 的注册 + * + * @author wangli + * @since 2024-09-10 09:56 + */ +@Slf4j +public class MetaFeignClientEnableSelector implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { + + private ResourceLoader resourceLoader; + + private Environment environment; + + static void validateFallback(final Class clazz) { + Assert.isTrue(!clazz.isInterface(), "Fallback class must implement the interface annotated by @FeignClient"); + } + + static void validateFallbackFactory(final Class clazz) { + Assert.isTrue(!clazz.isInterface(), "Fallback factory must produce instances " + + "of fallback classes that implement the interface annotated by @FeignClient"); + } + + static String getName(String name) { + if (!StringUtils.hasText(name)) { + return ""; + } + + String host = null; + try { + String url; + if (!name.startsWith("http://") && !name.startsWith("https://")) { + url = "http://" + name; + } + else { + url = name; + } + host = new URI(url).getHost(); + + } + catch (URISyntaxException e) { + } + Assert.state(host != null, "Service id not legal hostname (" + name + ")"); + return name; + } + + static String getUrl(String url) { + if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) { + if (!url.contains("://")) { + url = "http://" + url; + } + try { + new URL(url); + } + catch (MalformedURLException e) { + throw new IllegalArgumentException(url + " is malformed", e); + } + } + return url; + } + + static String getPath(String path) { + if (StringUtils.hasText(path)) { + path = path.trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + } + return path; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + Boolean metaFeignEnabled = environment.getProperty("workflow.engine.starter.meta-feign", Boolean.class); + log.error("current meta-feign result: {}", metaFeignEnabled); + if(!Boolean.TRUE.equals(metaFeignEnabled)){ + return; + } + LinkedHashSet candidateComponents = new LinkedHashSet<>(); + ClassPathScanningCandidateComponentProvider scanner = getScanner(); + scanner.setResourceLoader(this.resourceLoader); + scanner.addIncludeFilter(new AnnotationTypeFilter(WorkflowEngineFeignClient.class)); + candidateComponents.addAll(scanner.findCandidateComponents("cn.axzo.workflow.client.feign")); + + for (BeanDefinition candidateComponent : candidateComponents) { + if (candidateComponent instanceof AnnotatedBeanDefinition) { + // verify annotated class is an interface + AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; + AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); + Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); + + Map attributes = new HashMap<>(); + attributes.put("configuration", new Class[]{}); + attributes.put("contextId", ""); + attributes.put("decode404", false); + attributes.put("fallback", void.class); + attributes.put("fallbackFactory", void.class); + attributes.put("name", "workflow-engine"); + attributes.put("path", ""); + attributes.put("primary", true); + attributes.put("qualifier", ""); + attributes.put("qualifiers", new String[]{}); + String workflowEngineUrl = environment.getProperty("axzo.service.workflow-engine", String.class); + if(!StringUtils.hasText(workflowEngineUrl)) { + workflowEngineUrl = "http://workflow-engine:8080"; + } + attributes.put("url", workflowEngineUrl); + attributes.put("value", "workflow-engine"); + + registerFeignClient(registry, annotationMetadata, attributes); + } + } + } + + private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, + Map attributes) { + String className = annotationMetadata.getClassName(); + Class clazz = ClassUtils.resolveClassName(className, null); + ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory + ? (ConfigurableBeanFactory) registry : null; + String contextId = getContextId(beanFactory, attributes); + String name = getName(attributes); + FeignClientFactoryBean factoryBean = new FeignClientFactoryBean(); + factoryBean.setBeanFactory(beanFactory); + factoryBean.setName(name); + factoryBean.setContextId(contextId); + factoryBean.setType(clazz); + BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { + factoryBean.setUrl(getUrl(beanFactory, attributes)); + factoryBean.setPath(getPath(beanFactory, attributes)); + factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404")))); + Object fallback = attributes.get("fallback"); + if (fallback != null) { + factoryBean.setFallback(fallback instanceof Class ? (Class) fallback + : ClassUtils.resolveClassName(fallback.toString(), null)); + } + Object fallbackFactory = attributes.get("fallbackFactory"); + if (fallbackFactory != null) { + factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class) fallbackFactory + : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); + } + return factoryBean.getObject(); + }); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + definition.setLazyInit(true); + validate(attributes); + + AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); + beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className); + beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean); + + // has a default, won't be null + boolean primary = (Boolean) attributes.get("primary"); + + beanDefinition.setPrimary(primary); + + String[] qualifiers = getQualifiers(attributes); + if (ObjectUtils.isEmpty(qualifiers)) { + qualifiers = new String[] { contextId + "FeignClient" }; + } + + BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers); + BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); + } + + protected ClassPathScanningCandidateComponentProvider getScanner() { + return new ClassPathScanningCandidateComponentProvider(false, this.environment) { + @Override + protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { + boolean isCandidate = false; + if (beanDefinition.getMetadata().isIndependent()) { + if (!beanDefinition.getMetadata().isAnnotation()) { + isCandidate = true; + } + } + return isCandidate; + } + }; + } + + private void validate(Map attributes) { + AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes); + // This blows up if an aliased property is overspecified + // FIXME annotation.getAliasedString("name", FeignClient.class, null); + validateFallback(annotation.getClass("fallback")); + validateFallbackFactory(annotation.getClass("fallbackFactory")); + } + + private String getContextId(ConfigurableBeanFactory beanFactory, Map attributes) { + String contextId = (String) attributes.get("contextId"); + if (!StringUtils.hasText(contextId)) { + return getName(attributes); + } + + contextId = resolve(beanFactory, contextId); + return getName(contextId); + } + + private String getUrl(ConfigurableBeanFactory beanFactory, Map attributes) { + String url = resolve(beanFactory, (String) attributes.get("url")); + return getUrl(url); + } + + private String getPath(ConfigurableBeanFactory beanFactory, Map attributes) { + String path = resolve(beanFactory, (String) attributes.get("path")); + return getPath(path); + } + + /* for testing */ String getName(Map attributes) { + return getName(null, attributes); + } + + private String getQualifier(Map client) { + if (client == null) { + return null; + } + String qualifier = (String) client.get("qualifier"); + if (StringUtils.hasText(qualifier)) { + return qualifier; + } + return null; + } + + private String[] getQualifiers(Map client) { + if (client == null) { + return null; + } + List qualifierList = new ArrayList<>(Arrays.asList((String[]) client.get("qualifiers"))); + qualifierList.removeIf(qualifier -> !StringUtils.hasText(qualifier)); + if (qualifierList.isEmpty() && getQualifier(client) != null) { + qualifierList = Collections.singletonList(getQualifier(client)); + } + return !qualifierList.isEmpty() ? qualifierList.toArray(new String[0]) : null; + } + + String getName(ConfigurableBeanFactory beanFactory, Map attributes) { + String name = (String) attributes.get("serviceId"); + if (!StringUtils.hasText(name)) { + name = (String) attributes.get("name"); + } + if (!StringUtils.hasText(name)) { + name = (String) attributes.get("value"); + } + name = resolve(beanFactory, name); + return getName(name); + } + + private String resolve(ConfigurableBeanFactory beanFactory, String value) { + if (StringUtils.hasText(value)) { + if (beanFactory == null) { + return this.environment.resolvePlaceholders(value); + } + BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver(); + String resolved = beanFactory.resolveEmbeddedValue(value); + if (resolver == null) { + return resolved; + } + return String.valueOf(resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null))); + } + return value; + } + +} From 48d2765575d16c154681f1013bd4210e4b5231e1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 14:47:14 +0800 Subject: [PATCH 042/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=E7=9A=84=E5=86=85=E9=83=A8?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=8F=AF=E8=83=BD=E4=BA=A7=E7=94=9F=E7=9A=84?= =?UTF-8?q?=20NPE=20=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 6dae6bbb1..ba5fc3137 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1086,7 +1086,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic authorizedButtons.addAll(logVO.getDefaultButtonConf().getCarbonCopy()); } - if (Objects.equals(PROCESSING, logVO.getResult())) { + if (Objects.equals(PROCESSING, logVO.getResult()) && Objects.nonNull(visitor)) { String ge130Assignee = getGe130Assignee(visitor); String le130Assignee = getLe130Assignee(visitor); @@ -1214,7 +1214,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } private static void handleEncrypt(Boolean encrypt, List tasks) { - if (!encrypt) { + if (Boolean.FALSE.equals(encrypt)) { return; } tasks.forEach(i -> { From c24da62252bf77529b8c7d9d63a0434c1e62cd4d Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 10 Sep 2024 15:45:21 +0800 Subject: [PATCH 043/139] =?UTF-8?q?REQ-2924-=E6=97=A5=E5=BF=97=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E6=8E=92=E9=99=A4=E5=88=A0=E9=99=A4=E7=9A=84?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/BpmnProcessTaskServiceImpl.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 0f90c1ca1..ac3080ea7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -125,6 +125,7 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus; @@ -399,8 +400,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { .builder() .processInstanceId(task.getProcessInstanceId()) .processDefinitionId(task.getProcessDefinitionId()) - .processActivityId(flowElement.getId()) - .processActivityName(flowElement.getName()) + .processActivityId(flowElement.getId()) + .processActivityName(flowElement.getName()) .processNodeDesc(flowElement.getName()) .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) .ordinal(index.incrementAndGet()) @@ -486,8 +487,13 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { .collect(Collectors.toMap(ExtAxHiTaskInst::getTaskId, Function.identity(), (s, t) -> s)); BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId()); + List resultList = new ArrayList<>(); for (BpmnHistoricTaskInstanceVO vo : vos) { ExtAxHiTaskInst taskInst = extTaskInstMap.getOrDefault(vo.getTaskId(), new ExtAxHiTaskInst()); + if (Objects.equals(taskInst.getStatus(), DELETED.getStatus())) { + continue; + } + resultList.add(vo); vo.setResult(valueOfStatus(taskInst.getStatus())); List taskComments = commentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList()); @@ -539,7 +545,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { BpmnMetaParserHelper.getApprovalMethod(bpmnModel.getFlowElement(vo.getTaskDefinitionKey())) .ifPresent(vo::setApprovalMethod); } - return vos; + return resultList; } /** From 3d213a9cab322e78a4948612a39ca3a2e1b85949 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 16:00:04 +0800 Subject: [PATCH 044/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E2=80=9C=E9=80=80=E5=9B=9E=E2=80=9D=E7=9A=84=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java | 6 +++--- .../java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java | 4 ++-- .../common/enums/BpmnProcessInstanceResultEnum.java | 2 +- .../common/model/request/bpmn/task/BpmnOptionalNodeDTO.java | 2 +- .../engine/listener/entity/type/TaskEntityEventHandle.java | 2 +- .../workflow/core/repository/entity/ExtAxProcessLog.java | 2 +- .../axzo/workflow/core/service/BpmnProcessTaskService.java | 2 +- .../controller/web/bpmn/BpmnProcessTaskController.java | 6 +++--- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index f21b11463..e311d8c1a 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -74,11 +74,11 @@ public interface ProcessTaskApi { CommonResponse batchApproveTask(@Validated @RequestBody List dtos); /** - * 获取当前节点可退回节点选项列表 + * 获取当前节点可回退节点选项列表 * @param taskId 当前任务id - * @return 可以退回节点列表 + * @return 可以回退节点列表 */ - @Operation(summary = "获取当前节点可退回节点选项列表") + @Operation(summary = "获取当前节点可回退节点选项列表") @GetMapping("/api/process/task/back/optional/nodes") CommonResponse> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java index e7c72e8fd..2daf65036 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java @@ -33,9 +33,9 @@ public enum BpmnButtonEnum { */ BPMN_COMMENT(6, "BPMN_COMMENT", "评论"), /** - * 退回按钮 + * 回退按钮 */ - BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "退回"), + BPMN_ROLLBACK(7, "BPMN_ROLLBACK", "回退"), /** * 抄送按钮 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java index a69939c39..150ecbc35 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java @@ -6,7 +6,7 @@ public enum BpmnProcessInstanceResultEnum { PROCESSING("PROCESSING", "审批中"), APPROVED("APPROVED", "已通过"), REJECTED("REJECTED", "已驳回"), - BACKED("BACKED", "已退回"), + BACKED("BACKED", "已回退"), CANCELLED("CANCELLED", "已撤回"), ABORTED("ABORTED", "已中止"), TRANSFER("TRANSFER", "已转交"), diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java index 459bfb13e..935f5d201 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnOptionalNodeDTO.java @@ -7,7 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; /** - * 退回到指定节点,可选节点模型 + * 回退到指定节点,可选节点模型 */ @AllArgsConstructor @NoArgsConstructor diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index 7cf46102f..f83db2ff5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -53,7 +53,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeTyp /** * 同意、评论、加签、转交、驳回、撤回、中止、抄送 *

- * 退回 + * 回退 * * @author wangli * @since 2024-09-06 00:02 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java index c78bdfe7e..4c5476f90 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java @@ -103,7 +103,7 @@ public class ExtAxProcessLog extends BaseEntity { @TableField(typeHandler = ButtonConfTypeHandler.class) private BpmnButtonConf buttonConf; /** - * 任务状态:审批中/通过/驳回/转交/加签/退回 + * 任务状态:审批中/通过/驳回/转交/加签/回退 */ private String status; /** diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java index 346b2fd31..7e1d18f6f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java @@ -55,7 +55,7 @@ public interface BpmnProcessTaskService { BatchOperationResultVO batchApproveTask(List taskAuditDTOS); /** - * 退回到指定节点,可以退回节点选项 + * 回退到指定节点,可以回退节点选项 * @param taskId 任务id */ List getBackOptionalNodes(String taskId); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 94e43fa20..89be07059 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -130,11 +130,11 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp } /** - * 获取当前节点可退回节点选项列表 + * 获取当前节点可回退节点选项列表 * @param taskId 当前任务id - * @return 可选退回节点列表 + * @return 可选回退节点列表 */ - @Operation(summary = "获取当前节点可退回节点选项列表") + @Operation(summary = "获取当前节点可回退节点选项列表") @GetMapping("/back/optional/nodes") @Override @RepeatSubmit From 26fc14cce92dc3a4fd299322c0bf4a80dde6b3da Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 16:01:41 +0800 Subject: [PATCH 045/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20Starter=20=E6=94=AF=E6=8C=81=E4=B8=8D=E9=85=8D=E7=BD=AE=20Ro?= =?UTF-8?q?cket=20=E4=BD=BF=E7=94=A8=EF=BC=8C=E6=89=80=E6=9C=89=E7=9A=84?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E8=A1=8C=E4=B8=BA=E9=83=BD=E5=B0=86=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E4=BF=AE=E6=AD=A3=E4=B8=BA=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterBroadcastMQConfiguration.java | 16 ++--- .../StarterFeignClientConfiguration.java | 3 + .../StarterRPCInvokeMQConfiguration.java | 2 + ...orkflowEngineStarterAutoConfiguration.java | 2 +- .../feign/ext/ComplexInvokeClient.java | 61 ++++++++++--------- ...rkflowEngineStarterFeignConfiguration.java | 3 +- 6 files changed, 50 insertions(+), 37 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 9ac804265..7a1848191 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -44,6 +45,7 @@ import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_E * @since 2024/6/5 17:39 */ @Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public class StarterBroadcastMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterBroadcastMQConfiguration.class); public static final String BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME = "broadcastEventHandlerRepository"; @@ -84,10 +86,10 @@ public class StarterBroadcastMQConfiguration { @Component @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", - consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", - consumeMode = ConsumeMode.ORDERLY, - maxReconsumeTimes = 0, - nameServer = "${rocketmq.name-server}" + consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", + consumeMode = ConsumeMode.ORDERLY, + maxReconsumeTimes = 0, + nameServer = "${rocketmq.name-server}" ) public static class WorkflowEngineBroadcastConsumer extends BaseListener implements RocketMQListener, InitializingBean { private final Logger log = LoggerFactory.getLogger(WorkflowEngineBroadcastConsumer.class); @@ -116,9 +118,9 @@ public class StarterBroadcastMQConfiguration { @Override public void afterPropertiesSet() { this.filters = ImmutableList.of( - new InnerFilterMQOwnerShip(starterProperties, applicationName), - new InnerFilterDefinitionKey(starterProperties), - new InnerFilterExtension(businessFilterProvider)); + new InnerFilterMQOwnerShip(starterProperties, applicationName), + new InnerFilterDefinitionKey(starterProperties), + new InnerFilterExtension(businessFilterProvider)); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java index 91d071282..663778004 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java @@ -14,6 +14,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignClientFactoryBean; @@ -54,12 +55,14 @@ import java.util.Map; public class StarterFeignClientConfiguration { @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(FeignClientFactoryBean.class) @EnableFeignClients(clients = WorkflowCoreService.class) public static class WorkflowCoreServiceClient { } @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "manageable", havingValue = "true") + @ConditionalOnClass(FeignClientFactoryBean.class) @EnableFeignClients(clients = WorkflowManageService.class) public static class WorkflowManageServiceClient { } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index aa47f3f3d..5b9b39094 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -49,6 +50,7 @@ import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public class StarterRPCInvokeMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterRPCInvokeMQConfiguration.class); public static final String WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME = "workflowEngineStarterEventProducer"; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 466f464d9..01a19b309 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -52,7 +52,7 @@ import java.util.List; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) -@Import({StarterFeignClientConfiguration.class, StarterBroadcastMQConfiguration.class, StarterRPCInvokeMQConfiguration.class, MetaFeignClientEnableSelector.class}) +@Import({StarterFeignClientConfiguration.class, MetaFeignClientEnableSelector.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 017237e0e..2e3f733a6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -42,13 +42,14 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static cn.axzo.workflow.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; -import static cn.axzo.workflow.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -63,14 +64,14 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; - private final RpcInvokeEventProducer eventProducer; + private final Optional optEventProducer; private final Client feignClient; public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, - EventProducer eventProducer, + Optional optEventProducer, Client feignClient) { this.starterProperties = starterProperties; - this.eventProducer = (RpcInvokeEventProducer) eventProducer; + this.optEventProducer = optEventProducer; //(RpcInvokeEventProducer) eventProducer; this.feignClient = feignClient; } @@ -78,40 +79,44 @@ public class ComplexInvokeClient implements Client { public Response execute(Request request, Request.Options options) throws IOException { log.debug("ComplexInvokeClient execute... Url: {}", request.url()); RpcInvokeModeEnum currentInvokeModeEnum = getInvokeMode(request); - Map> headers = request.headers(); - headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); - log.debug("[{}] invoke url: {}", currentInvokeModeEnum, request.url()); if (Objects.equals(SYNC, currentInvokeModeEnum)) { return feignClient.execute(request, options); } - asyncInvoke(request); - - return Response.builder() - .status(HttpStatus.OK.value()) - .reason(HttpStatus.OK.getReasonPhrase()) - .headers(headers) - .request(request) - .body(body) - .build(); + return asyncInvoke(request, options); } /** * 发送 RPC 调用动作的 MQ 事件 * * @param request + * @param options */ - private void asyncInvoke(Request request) { - WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); - MethodMetadata metadata = request.requestTemplate().methodMetadata(); - event.setClassName(metadata.targetType().getName()); - event.setMethodName(metadata.method().getName()); + private Response asyncInvoke(Request request, Request.Options options) throws IOException { + if (!optEventProducer.isPresent()) { + return feignClient.execute(request, options); + } + optEventProducer.ifPresent(eventProducer -> { + WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); + MethodMetadata metadata = request.requestTemplate().methodMetadata(); + event.setClassName(metadata.targetType().getName()); + event.setMethodName(metadata.method().getName()); - List args = new ArrayList<>(); - event.setParameters(args); - buildArgs(request, metadata, args); - log.debug("[async-invoke] sourceEvent: {}", JSON.toJSONString(event)); - eventProducer.send(WORKFLOW_ENGINE_STARTER, event); + List args = new ArrayList<>(); + event.setParameters(args); + buildArgs(request, metadata, args); + log.debug("[async-invoke] sourceEvent: {}", JSON.toJSONString(event)); + ((RpcInvokeEventProducer) eventProducer).send(WORKFLOW_ENGINE_STARTER, event); + }); + Map> headers = request.headers(); + headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); + return Response.builder() + .status(HttpStatus.OK.value()) + .reason(HttpStatus.OK.getReasonPhrase()) + .headers(headers) + .request(request) + .body(body) + .build(); } @SneakyThrows @@ -204,7 +209,7 @@ public class ComplexInvokeClient implements Client { private RpcInvokeModeEnum getInvokeMode(Request request) { Collection invokeModel = request.headers().getOrDefault(STARTER_INVOKE_MODE, - Collections.singletonList(starterProperties.getInvokeMode().name())); + Collections.singletonList(starterProperties.getInvokeMode().name())); if (CollectionUtils.isEmpty(invokeModel)) { return starterProperties.getInvokeMode(); } else if (invokeModel.size() > 1) { @@ -215,7 +220,7 @@ public class ComplexInvokeClient implements Client { static Response.Body body = new Response.Body() { final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), "Send MQ Success", null)) - .getBytes(UTF_8)); + .getBytes(UTF_8)); @Override public Integer length() { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 19a406cb3..5d610f981 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Collections; import java.util.Objects; +import java.util.Optional; //import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; @@ -58,7 +59,7 @@ public class WorkflowEngineStarterFeignConfiguration { public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, Client feignClient) { - return new ComplexInvokeClient(starterProperties, eventProducer, feignClient); + return new ComplexInvokeClient(starterProperties, Optional.ofNullable(eventProducer), feignClient); } @Bean From eb461cf05cb31888ad00c407d227ff9db10218d3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 17:45:12 +0800 Subject: [PATCH 046/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 8 ++++--- .../starter/api/WorkflowManageService.java | 2 ++ .../api/CoreServiceCodeGeneration.java | 22 +++++++++---------- .../api/ManageServiceCodeGeneration.java | 21 +++++++++--------- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 9eb987904..6ca079346 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -63,6 +63,8 @@ import javax.validation.constraints.NotEmpty; * Workflow Engine Starter Core Service *

* 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + *

+ * Auto generation by workflow engine, It cannot be manually modified */ @org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { @@ -222,11 +224,11 @@ public interface WorkflowCoreService { BatchOperationResultVO batchApproveTask(@Validated @RequestBody List dtos); /** - * 获取当前节点可退回节点选项列表 + * 获取当前节点可回退节点选项列表 * @param taskId 当前任务id - * @return 可以退回节点列表 + * @return 可以回退节点列表 */ - @Operation(summary = "获取当前节点可退回节点选项列表") + @Operation(summary = "获取当前节点可回退节点选项列表") @GetMapping("/api/process/task/back/optional/nodes") List getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index b6c262f2a..3424cc527 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -83,6 +83,8 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinition * Workflow Engine Starter Management Service *

* 该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口 + *

+ * Auto generation by workflow engine, It cannot be manually modified */ @org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index c5058d286..87d32bd36 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -8,7 +8,6 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.BodyDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.ast.expr.ClassExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; @@ -88,15 +87,15 @@ public class CoreServiceCodeGeneration { private static void addDefaultMethods(ClassOrInterfaceDeclaration interfaceDeclaration) { MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + - "

\r\n" +
-                "  workflowCoreService.sync().createProcessInstance();\r\n" +
-                "
"); + "
\r\n" +
+            "  workflowCoreService.sync().createProcessInstance();\r\n" +
+            "
"); MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); sync.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + - "
\r\n" +
-                "  workflowCoreService.async().createProcessInstance();\r\n" +
-                "
"); + "
\r\n" +
+            "  workflowCoreService.async().createProcessInstance();\r\n" +
+            "
"); } private static MethodDeclaration createDefaultMethod(String methodName, ClassOrInterfaceDeclaration interfaceDeclaration) { @@ -169,11 +168,12 @@ public class CoreServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Core Service\r\n

\r\n" + - "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口\r\n

\r\n" + + "Auto generation by workflow engine, It cannot be manually modified"); classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") - .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) - .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); + .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index 1df396b15..7d200072d 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -66,15 +66,15 @@ public class ManageServiceCodeGeneration { private static void addDefaultMethods(ClassOrInterfaceDeclaration interfaceDeclaration) { MethodDeclaration sync = createDefaultMethod("sync", interfaceDeclaration); sync.setJavadocComment("强制使用‘同步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + - "

\r\n" +
-                "  workflowManageService.sync().getTenantIds();\r\n" +
-                "
"); + "
\r\n" +
+            "  workflowManageService.sync().getTenantIds();\r\n" +
+            "
"); MethodDeclaration async = createDefaultMethod("async", interfaceDeclaration); async.setJavadocComment("强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法\r\n" + - "
\r\n" +
-                "  workflowManageService.async().getTenantIds();\r\n" +
-                "
"); + "
\r\n" +
+            "  workflowManageService.async().getTenantIds();\r\n" +
+            "
"); } private static MethodDeclaration createDefaultMethod(String methodName, ClassOrInterfaceDeclaration interfaceDeclaration) { @@ -159,11 +159,12 @@ public class ManageServiceCodeGeneration { private static ClassOrInterfaceDeclaration setCommon(CompilationUnit cu, String newClassName) { ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cu.addInterface(newClassName).setPublic(true); classOrInterfaceDeclaration.setJavadocComment("Workflow Engine Starter Management Service\r\n

\r\n" + - "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口"); + "该类是根据 API 动态生成,不同版本可能会开放新的接口,或回收一些旧接口\r\n

\r\n" + + "Auto generation by workflow engine, It cannot be manually modified"); classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") - .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) - .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); + .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) + .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); cu.addImport("cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC", true, false); From 9d1b477aaa74056a5e23144470f21127460f4589 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 10 Sep 2024 17:50:57 +0800 Subject: [PATCH 047/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20starterProperties=20=E5=B1=9E=E6=80=A7=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=8E=A7=E5=88=B6=E6=98=AF=E5=90=A6=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=8E=9F=E5=A7=8B=E7=9A=84=20FeignClient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/WorkflowEngineStarterProperties.java | 6 +++++- .../src/main/resources/META-INF/application.yml.demo | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java index 9d103a013..cbe1ff22e 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterProperties.java @@ -19,9 +19,13 @@ import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC; @ConfigurationProperties(prefix = "workflow.engine.starter") public class WorkflowEngineStarterProperties { /** - * + * 是否开启原始 ProcessInstanceApi、ProcessTaskApi 等类似的 FeignClient,具体可用的 API 参考 cn.axzo.workflow.client.feign 包 + *

+ * 默认 false,优先 starter 提供的 coreService、manageServer。 + * 为 true 时,会为当前应用注册原始 xxxApi FeignClient */ private Boolean metaFeign = false; + /** * 特殊用途,不建议接入方使用 */ diff --git a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo index 9e64ea2a5..0af4c06d5 100644 --- a/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo +++ b/workflow-engine-spring-boot-starter/src/main/resources/META-INF/application.yml.demo @@ -1,6 +1,7 @@ workflow: engine: starter: + meta-feign: false # 是否开启原始 ProcessInstanceApi、ProcessTaskApi 等类似的 FeignClient,默认 false,优先 starter 提供的 coreService、manageServer。为 true 时,会为当前应用注册原始 xxxApi FeignClient invoke-mode: async # 调用 workflowCoreService 中方法的方式,可选值:sync、async join-container-group: false # 本地开发机启动时,是否将 MQ 消费者加入到集群中,默认不加入,并默认生成 GID_${spring.application.name}_workflow_engine_${spring.profiles.active}_debugging_consumer 的消费者组,该参数只对非容器环境生效 manageable: false # 是否可管理,默认 false, 开启后 Spring 容器中将多一个 WorkflowManageService 的 Bean,可调用受限访问接口 From e082b9d0cc03c2ae4f1384a586e40f691daa5ef6 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 10:53:16 +0800 Subject: [PATCH 048/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=20/error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RequestHeaderContextInterceptor.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index cfc316e8e..5db983a43 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -47,11 +47,11 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (Objects.equals(HEADER_HTTP_CLIENT_VALUE, request.getHeader(HEADER_HTTP_CLIENT))) { String headerClientVersion = request.getHeader(HEADER_API_VERSION) - .replaceAll("-SNAPSHOT", "") - .replaceAll("-RELEASE", ""); + .replaceAll("-SNAPSHOT", "") + .replaceAll("-RELEASE", ""); serviceVersion = serviceVersion - .replaceAll("-SNAPSHOT", "") - .replaceAll("-RELEASE", ""); + .replaceAll("-SNAPSHOT", "") + .replaceAll("-RELEASE", ""); DefaultArtifactVersion minimumSupportedVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130); DefaultArtifactVersion clientVersion = new DefaultArtifactVersion(headerClientVersion); DefaultArtifactVersion serverVersion = new DefaultArtifactVersion(serviceVersion); @@ -69,7 +69,8 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { } // 仅 feignApi 才需要检查版本 if (!request.getRequestURI().contains("/web/") && !request.getRequestURI().contains("checkDeath") - && !StringUtils.hasText(request.getHeader(HEADER_HTTP_CLIENT))) { + && !request.getRequestURI().contains("/error") + && !StringUtils.hasText(request.getHeader(HEADER_HTTP_CLIENT))) { String serverName = request.getHeader(HEADER_SERVER_NAME); printHeader(request); log.error(MICRO_SERVER_NEED_REBUILD.getMessage(), serverName); @@ -105,7 +106,7 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { } ExtAxProperty property = extAxProperty.get(); if (Objects.equals(property.getValue(), clientVersion.toString()) - && Objects.equals(property.getManageable().toString(), manageableStatus)) { + && Objects.equals(property.getManageable().toString(), manageableStatus)) { return; } property.setName(requestApplicationName); From ff5a579a2ccd6c920dabf0d56c3772ac8293247b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 11:21:45 +0800 Subject: [PATCH 049/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=20DLQ=20=E7=9B=91=E6=8E=A7=E6=97=A5=E5=BF=97=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java index f29893c33..e3d9d2c27 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/monitor/WorkflowEngineStarterDefaultMQMonitor.java @@ -112,7 +112,6 @@ public class WorkflowEngineStarterDefaultMQMonitor implements SmartLifecycle { } }); } catch (Exception e) { - log.warn("monitor Broadcast DLQ error: {}", e.getMessage(), e); log.warn("该异常信息是正常的,不影响服务启动!"); } } From 638a8178e2ddd3f77ec3462036d27bebd3239832 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 14:00:32 +0800 Subject: [PATCH 050/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E9=95=BF=E6=97=B6=E9=97=B4=E5=8D=A1=E4=BD=8F?= =?UTF-8?q?=E7=9A=84=E5=91=8A=E8=AD=A6=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/TermNodePausingDTO.java | 26 ++++++++ .../core/conf/FlowableConfiguration.java | 2 + .../core/engine/cmd/AbstractCommand.java | 2 +- .../cmd/CustomTermNodePausingAlertCmd.java | 28 +++++++++ .../job/AsyncTermNodeAlterJobHandler.java | 28 +++++++++ ...BpmnActivityEventListener_lo_Listener.java | 63 +++++++++++++++++++ ...ocketMqBpmActivityEvent_100_Listener.java} | 5 +- 7 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTermNodePausingAlertCmd.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java rename workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/{RocketMqBpmActivityEventListener.java => RocketMqBpmActivityEvent_100_Listener.java} (97%) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java new file mode 100644 index 000000000..c76d2cb64 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java @@ -0,0 +1,26 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 卡住节点的查询条件模型 + * + * @author wangli + * @since 2024-09-11 13:57 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class TermNodePausingDTO { + + private String processInstanceId; + + private String activityId; + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 6abda0f35..0224420e7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -14,6 +14,7 @@ import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceJobHandler; import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler; import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler; import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler; +import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler; import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler; import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncJobLogClearTraceExceptionHandler; import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncRunnableExceptionExceptionHandler; @@ -93,6 +94,7 @@ public class FlowableConfiguration { configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); + configuration.addCustomJobHandler(new AsyncTermNodeAlterJobHandler()); // 异步任务异常重试时间间隔 configuration.setDefaultFailedJobWaitTime(30); configuration.setAsyncFailedJobWaitTime(30); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java index 3406671d5..05cbd504f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/AbstractCommand.java @@ -8,7 +8,7 @@ import org.flowable.common.engine.impl.interceptor.CommandContext; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.ENGINE_EXEC_EXCEPTION; /** - * TODO + * 抽象的命令,用于将在 Command 中执行的逻辑所抛出的非 WorkflowEngineException 的异常都包装为 WorkflowEngineException * * @author wangli * @since 2024/7/1 13:59 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTermNodePausingAlertCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTermNodePausingAlertCmd.java new file mode 100644 index 000000000..3b6a2262a --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTermNodePausingAlertCmd.java @@ -0,0 +1,28 @@ +package cn.axzo.workflow.core.engine.cmd; + +import org.flowable.bpmn.model.TimerEventDefinition; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.io.Serializable; + +/** + * 自定义的节点长时间卡住的告警 + * + * @author wangli + * @since 2024-09-11 13:44 + */ +public class CustomTermNodePausingAlertCmd extends AbstractCommand implements Serializable { + @Override + public String paramToJsonString() { + return ""; + } + + @Override + public Void executeInternal(CommandContext commandContext) { + + + return null; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java new file mode 100644 index 000000000..ed746dbcf --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java @@ -0,0 +1,28 @@ +package cn.axzo.workflow.core.engine.job; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.job.service.JobHandler; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.variable.api.delegate.VariableScope; + +/** + * 检查指定节点是否长时间卡住,如果卡住则进行钉钉告警 + * + * @author wangli + * @since 2024-09-11 13:50 + */ +@Slf4j +public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements JobHandler { + public static final String TYPE = "term-node-alter-cycle"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java new file mode 100644 index 000000000..cd4a2dfc3 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -0,0 +1,63 @@ +package cn.axzo.workflow.core.listener.impl; + +import cn.axzo.workflow.common.model.dto.TermNodePausingDTO; +import cn.axzo.workflow.core.common.context.ActivityOperationContext; +import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler; +import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; +import cn.axzo.workflow.core.listener.BpmnActivityEventListener; +import com.alibaba.fastjson.JSON; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.TimerEventDefinition; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.jobexecutor.TimerEventHandler; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.TimerUtil; +import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; +import org.springframework.context.annotation.Scope; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +/** + * Core 包内置的活动事件处理,可共用与 Jar 包集成和微服务集成 + *

+ * 该监听主要是监听启动“无人”的业务节点超时告警功能 + * + * @author wangli + * @since 2024-09-11 11:44 + */ +@Slf4j +@Component +@Scope("prototype") +@AllArgsConstructor +public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnEventListener implements BpmnActivityEventListener, Ordered { + @Override + public int getOrder() { + return Integer.MIN_VALUE; + } + + /** + * 节点已启动 + *

+ * 创建一个周期性监控业务节点执行状态的任务 + * + * @param execution + */ + @Override + public void onStart(DelegateExecution execution) { + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + + TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); +// timerEventDefinition.setTimeDate(newEndTime); + + TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, execution.getCurrentFlowElement(), + true, (ExecutionEntity) execution, AsyncTermNodeAlterJobHandler.TYPE, TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), + timerEventDefinition.getEndDate(), timerEventDefinition.getCalendarName())); + if (timerJob != null) { + timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId()))); + CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); + } + } +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEvent_100_Listener.java similarity index 97% rename from workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java rename to workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEvent_100_Listener.java index b9bc8cd16..46dbd9045 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/activity/RocketMqBpmActivityEvent_100_Listener.java @@ -18,7 +18,6 @@ import org.flowable.bpmn.model.Process; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.DelegateExecution; -import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; @@ -56,7 +55,7 @@ import static cn.axzo.workflow.common.enums.ProcessActivityEventEnum.PROCESS_ACT @Slf4j @Component @Scope("prototype") -public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener implements BpmnActivityEventListener, Ordered { +public class RocketMqBpmActivityEvent_100_Listener extends AbstractBpmnEventListener implements BpmnActivityEventListener, Ordered { @Resource private RuntimeService runtimeService; @Resource @@ -199,7 +198,7 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener< @Override public int getOrder() { - return Integer.MIN_VALUE; + return Integer.MIN_VALUE + 100; } } From d452ffa99557bd8404e274593c7f8f1a4bea048f Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 15:14:50 +0800 Subject: [PATCH 051/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9A=84=E6=8E=A5=E5=8F=A3=E7=9A=84=20feignC?= =?UTF-8?q?lient=20placeholder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java | 2 +- .../axzo/workflow/support/api/ManageServiceCodeGeneration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java index 87d32bd36..685bd5110 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/CoreServiceCodeGeneration.java @@ -172,7 +172,7 @@ public class CoreServiceCodeGeneration { "Auto generation by workflow engine, It cannot be manually modified"); classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-core")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); diff --git a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java index 7d200072d..88223f134 100644 --- a/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java +++ b/workflow-engine-support/src/main/java/cn/axzo/workflow/support/api/ManageServiceCodeGeneration.java @@ -163,7 +163,7 @@ public class ManageServiceCodeGeneration { "Auto generation by workflow engine, It cannot be manually modified"); classOrInterfaceDeclaration.addAndGetAnnotation("org.springframework.cloud.openfeign.FeignClient") .addPair("name", new StringLiteralExpr("workflow-engine-starter-manage")) - .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine.starter:http://workflow-engine:8080}")) + .addPair("url", new StringLiteralExpr("${axzo.service.workflow-engine:http://workflow-engine:8080}")) .addPair("configuration", new ClassExpr(new ClassOrInterfaceType("WorkflowEngineStarterFeignConfiguration"))); cu.addImport("cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration", false, false); cu.addImport("cn.axzo.workflow.common.util.ThreadUtil", false, false); From 6fe9470cea3d8285f606493df7b579bdf33bbb9c Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 11 Sep 2024 16:10:54 +0800 Subject: [PATCH 052/139] =?UTF-8?q?REQ-2924-=E6=B7=BB=E5=8A=A0=E6=A0=B9?= =?UTF-8?q?=E6=8D=AEtype=E8=8E=B7=E5=8F=96=E6=9E=9A=E4=B8=BE=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/enums/BpmnFlowNodeType.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeType.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeType.java index 1dc7eb85d..1856447f6 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeType.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnFlowNodeType.java @@ -1,6 +1,8 @@ package cn.axzo.workflow.common.enums; +import org.springframework.util.StringUtils; + import java.util.Arrays; import java.util.Objects; @@ -51,6 +53,19 @@ public enum BpmnFlowNodeType { this.desc = desc; } + public static BpmnFlowNodeType getByType(String type) { + if (!StringUtils.hasText(type)) { + return null; + } + BpmnFlowNodeType[] values = BpmnFlowNodeType.values(); + for (BpmnFlowNodeType value : values) { + if (value.getType().equals(type)) { + return value; + } + } + return null; + } + public static BpmnFlowNodeType valueOfType(String type) { return Arrays.stream(BpmnFlowNodeType.values()) .filter(i -> Objects.equals(i.getType(), type)) From 5ccd66c6d5c27b278cf3911da62c3922b10f26a7 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 11 Sep 2024 17:55:19 +0800 Subject: [PATCH 053/139] =?UTF-8?q?REQ-2924-=E8=8E=B7=E5=8F=96=E9=80=80?= =?UTF-8?q?=E5=9B=9E=E8=8A=82=E7=82=B9=E5=88=97=E8=A1=A8=EF=BC=8C=E5=80=92?= =?UTF-8?q?=E5=BA=8F=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/service/impl/BpmnProcessTaskServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index ac3080ea7..896bcbc0f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -411,6 +411,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessActivityName() + "(上一级)"); } + resultList.sort((o1, o2) -> o2.getOrdinal() - o1.getOrdinal()); return resultList; } From 7a898d0f5bdcb0a41326c7b575279d5aad29f5ea Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 20:38:37 +0800 Subject: [PATCH 054/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/TermNodePausingDTO.java | 5 ++ .../core/conf/SupportRefreshProperties.java | 19 +++++ .../job/AsyncTermNodeAlterJobHandler.java | 19 +++++ ...BpmnActivityEventListener_lo_Listener.java | 79 ++++++++++++++++--- 4 files changed, 112 insertions(+), 10 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java index c76d2cb64..345053959 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java @@ -23,4 +23,9 @@ public class TermNodePausingDTO { private String activityId; + /** + * 重试次数 + */ + private Integer retries; + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index 36bceb854..e8bff4380 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; /** * 支持动态刷新配置属性 @@ -28,4 +29,22 @@ public class SupportRefreshProperties { @Value("${workflow.apiLog.filterApiType:}") private String filterApiType; + + /** + * 业务节点暂停告警的次数 + */ + @Value("${workflow.alter.retries:3}") + private Integer retries; + + /** + * 业务节点暂停告警次数间的间隔 + */ + @Value("${workflow.alter.interval:10}") + private Integer interval; + + /** + * 业务节点暂停告警次数间隔的时间单位 + */ + @Value("${workflow.alter.intervalUnit:minutes}") + private TimeUnit intervalUnit; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java index ed746dbcf..3b264bebc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java @@ -1,11 +1,18 @@ package cn.axzo.workflow.core.engine.job; +import cn.axzo.workflow.common.model.dto.TermNodePausingDTO; +import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.api.Job; import org.flowable.job.service.JobHandler; import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.variable.api.delegate.VariableScope; +import java.util.Objects; + /** * 检查指定节点是否长时间卡住,如果卡住则进行钉钉告警 * @@ -23,6 +30,18 @@ public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements @Override public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + log.warn("AsyncActivityLeaveJobHandler exec start..."); + TermNodePausingDTO dto = JSON.parseObject(job.getCustomValues(), TermNodePausingDTO.class); + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); + Job timerJob = processEngineConfiguration.getManagementService() + .createTimerJobQuery().elementId(dto.getActivityId()) + .processInstanceId(dto.getProcessInstanceId()).singleResult(); + + if (Objects.equals(timerJob.getRetries(), dto.getRetries())) { + return; + } + + // 发送钉钉 } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java index cd4a2dfc3..8dd6cdf46 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -1,25 +1,35 @@ package cn.axzo.workflow.core.listener.impl; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.dto.TermNodePausingDTO; import cn.axzo.workflow.core.common.context.ActivityOperationContext; +import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler; import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; import cn.axzo.workflow.core.listener.BpmnActivityEventListener; import com.alibaba.fastjson.JSON; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.TimerEventDefinition; +import org.flowable.engine.ManagementService; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.jobexecutor.TimerEventHandler; import org.flowable.engine.impl.persistence.entity.ExecutionEntity; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.engine.impl.util.TimerUtil; +import org.flowable.job.api.Job; import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; import org.springframework.context.annotation.Scope; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; +import java.util.Objects; + /** * Core 包内置的活动事件处理,可共用与 Jar 包集成和微服务集成 *

@@ -33,6 +43,8 @@ import org.springframework.stereotype.Component; @Scope("prototype") @AllArgsConstructor public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnEventListener implements BpmnActivityEventListener, Ordered { + private final SupportRefreshProperties refreshProperties; + @Override public int getOrder() { return Integer.MIN_VALUE; @@ -47,17 +59,64 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE */ @Override public void onStart(DelegateExecution execution) { + BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(execution.getCurrentActivityId()); + BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(e -> { + if (Objects.equals(BpmnFlowNodeType.NODE_BUSINESS, e)) { + BpmnMetaParserHelper.getApprovalMethod(flowElement).ifPresent(method -> { + switch (method) { + case nobody: + case bizSpecify: + TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); + String timeUnit = "M"; + switch (refreshProperties.getIntervalUnit()) { + case SECONDS: + timeUnit = "S"; + break; + case HOURS: + timeUnit = "H"; + break; + case DAYS: + timeUnit = "D"; + break; + default: + // MINUTES + timeUnit = "M"; + break; + } + timerEventDefinition.setTimeCycle("R" + refreshProperties.getInterval() + "/PT" + refreshProperties.getInterval() + timeUnit); + + TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, execution.getCurrentFlowElement(), + false, (ExecutionEntity) execution, AsyncTermNodeAlterJobHandler.TYPE, + TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), null, timerEventDefinition.getCalendarName())); + if (timerJob != null) { + timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), refreshProperties.getRetries()))); + CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); + } + break; + default: + break; + } + }); + } + }); + } + + /** + * 节点已取消 + * + * @param execution + */ + @Override + public void onEnd(DelegateExecution execution) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); - - TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); -// timerEventDefinition.setTimeDate(newEndTime); - - TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, execution.getCurrentFlowElement(), - true, (ExecutionEntity) execution, AsyncTermNodeAlterJobHandler.TYPE, TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), - timerEventDefinition.getEndDate(), timerEventDefinition.getCalendarName())); - if (timerJob != null) { - timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId()))); - CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); + ManagementService managementService = processEngineConfiguration.getManagementService(); + Job timerJob = managementService.createTimerJobQuery() + .elementId(execution.getCurrentActivityId()) + .processInstanceId(execution.getProcessInstanceId()) + .singleResult(); + if (Objects.nonNull(timerJob)) { + CommandContextUtil.getTimerJobService().deleteTimerJob((TimerJobEntity) timerJob); } } } From bacec8a72e15ccf01e94866eedd95864e657663b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 11 Sep 2024 20:47:18 +0800 Subject: [PATCH 055/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=9C=A8=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E8=AE=BE=E7=BD=AE=E4=BA=86=E5=AE=A1=E6=89=B9=E4=BA=BA?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E9=87=8D=E6=96=B0=E5=8F=96=E6=B6=88=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomBizSpecifyAssigneeToTaskCmd.java | 36 ++++++++++++++----- ...BpmnActivityEventListener_lo_Listener.java | 3 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java index f1dd7acbc..e6b891e63 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java @@ -6,11 +6,14 @@ import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import com.alibaba.fastjson.JSON; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.HistoryService; +import org.flowable.engine.ManagementService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.api.Job; +import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; import org.flowable.task.api.Task; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.util.CollectionUtils; @@ -59,8 +62,8 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand public static Task getOperateTask(TaskService taskService, String executionId) { return taskService.createTaskQuery().executionId(executionId) - .taskAssignee(NO_ASSIGNEE) - .singleResult(); + .taskAssignee(NO_ASSIGNEE) + .singleResult(); } /** @@ -79,7 +82,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand @Override public Boolean execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); TaskEntity task = (TaskEntity) getOperateTask(taskService, executionId); //校验 @@ -91,12 +94,29 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand addAssignee(commandContext, taskService, task); + clearAlterTimeJob(commandContext, task); + return true; } + /** + * 清空告警的任务 + * + * @param commandContext + * @param task + */ + private void clearAlterTimeJob(CommandContext commandContext, TaskEntity task) { + ManagementService managementService = CommandContextUtil.getProcessEngineConfiguration(commandContext).getManagementService(); + Job timerJob = managementService.createTimerJobQuery().elementId(task.getTaskDefinitionKey()).processInstanceId(task.getProcessInstanceId()).singleResult(); + if (Objects.nonNull(timerJob)) { + CommandContextUtil.getTimerJobService().deleteTimerJob((TimerJobEntity) timerJob); + } + + } + public static void validProcessInstance(CommandContext commandContext, Task task) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); if (Objects.isNull(processInstance)) { @@ -110,11 +130,11 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand private void changeAssigneeSnapshot(CommandContext commandContext, Task task) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); List originAssingeeList = runtimeService.getVariable(task.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class); for (BpmnTaskDelegateAssigner assigner : originAssingeeList) { if (Objects.equals(assigner.buildAssigneeId(), NO_ASSIGNEE)) { @@ -124,8 +144,8 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand } originAssingeeList.addAll(addedAssigners); runtimeService.setVariable(task.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), - originAssingeeList); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), + originAssingeeList); } private void addAssignee(CommandContext commandContext, TaskService taskService, Task task) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java index 8dd6cdf46..50dc371f0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -67,8 +67,9 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE switch (method) { case nobody: case bizSpecify: + // FIXME 业务指定审批人,需要在业务设置了人后,清除定时 TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); - String timeUnit = "M"; + String timeUnit; switch (refreshProperties.getIntervalUnit()) { case SECONDS: timeUnit = "S"; From f5ac06fc753005807d42f3db3baede096160afb8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 13:37:57 +0800 Subject: [PATCH 056/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E6=8E=A7=E5=88=B6=E6=98=AF=E5=90=A6=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E9=92=88=E5=AF=B9=E4=B8=9A=E5=8A=A1=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/conf/SupportRefreshProperties.java | 11 +++++------ ...InternalBpmnActivityEventListener_lo_Listener.java | 9 ++++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index e8bff4380..df2fc358b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -1,13 +1,10 @@ package cn.axzo.workflow.core.conf; -import com.google.common.collect.Lists; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -30,21 +27,23 @@ public class SupportRefreshProperties { @Value("${workflow.apiLog.filterApiType:}") private String filterApiType; + @Value("${workflow.alter.enable:false}") + private Boolean alterEnable = false; /** * 业务节点暂停告警的次数 */ @Value("${workflow.alter.retries:3}") - private Integer retries; + private Integer alterRetries; /** * 业务节点暂停告警次数间的间隔 */ @Value("${workflow.alter.interval:10}") - private Integer interval; + private Integer alterInterval; /** * 业务节点暂停告警次数间隔的时间单位 */ @Value("${workflow.alter.intervalUnit:minutes}") - private TimeUnit intervalUnit; + private TimeUnit alterIntervalUnit; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java index 50dc371f0..ce56e3f16 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -59,6 +59,9 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE */ @Override public void onStart(DelegateExecution execution) { + if(!Boolean.TRUE.equals(refreshProperties.getAlterEnable())) { + return; + } BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId()); FlowElement flowElement = bpmnModel.getFlowElement(execution.getCurrentActivityId()); BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(e -> { @@ -70,7 +73,7 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE // FIXME 业务指定审批人,需要在业务设置了人后,清除定时 TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); String timeUnit; - switch (refreshProperties.getIntervalUnit()) { + switch (refreshProperties.getAlterIntervalUnit()) { case SECONDS: timeUnit = "S"; break; @@ -85,13 +88,13 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE timeUnit = "M"; break; } - timerEventDefinition.setTimeCycle("R" + refreshProperties.getInterval() + "/PT" + refreshProperties.getInterval() + timeUnit); + timerEventDefinition.setTimeCycle("R" + refreshProperties.getAlterInterval() + "/PT" + refreshProperties.getAlterInterval() + timeUnit); TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, execution.getCurrentFlowElement(), false, (ExecutionEntity) execution, AsyncTermNodeAlterJobHandler.TYPE, TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), null, timerEventDefinition.getCalendarName())); if (timerJob != null) { - timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), refreshProperties.getRetries()))); + timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), refreshProperties.getAlterRetries()))); CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); } break; From 7b791f71717da627b9609a1b189776a81166bb3f Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 14:42:53 +0800 Subject: [PATCH 057/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E9=80=80?= =?UTF-8?q?=E5=9B=9E=E6=8C=87=E5=AE=9A=E6=A0=A1=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/code/BpmnTaskRespCode.java | 1 + .../core/common/utils/BpmnModelUtils.java | 91 ++++++++++++++ .../engine/cmd/CustomBackTaskAsyncCmd.java | 39 ++++-- .../core/engine/cmd/CustomBackTaskCmd.java | 40 ++++--- .../engine/cmd/helper/CustomTaskHelper.java | 111 +++++++++--------- 5 files changed, 198 insertions(+), 84 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnModelUtils.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java index 663f31544..ff4fec3a7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java @@ -38,6 +38,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"), ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT("022", String.format("人员数量超过限制,节点审批人限制数量为: %d!", APPROVAL_ASSIGNER_LIMIT_NUMBER)), BACK_TARGET_ACTIVITY_NOT_EXISTS("023", "回退到指定节点【{}】失败!"), + BACK_NODE_CANNOT_REACHABLE("024", "退回节点【{}】不可达,不允许退回"), ; private final String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnModelUtils.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnModelUtils.java new file mode 100644 index 000000000..80ace39f9 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnModelUtils.java @@ -0,0 +1,91 @@ +package cn.axzo.workflow.core.common.utils; + +import org.flowable.bpmn.model.EventSubProcess; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowElementsContainer; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.SubProcess; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class BpmnModelUtils { + + /** + * 节点是否可达 + * @param process + * @param sourceElement + * @param targetElement + * @return + */ + public static boolean isReachable(org.flowable.bpmn.model.Process process, FlowNode sourceElement, FlowNode targetElement) { + return isReachable(process, sourceElement, targetElement, new HashSet<>()); + } + + public static boolean isReachable(org.flowable.bpmn.model.Process process, FlowNode sourceElement, FlowNode targetElement, Set visitedElements) { + // Special case: start events in an event subprocess might exist as an execution and are most likely be able to + // reach the target + // when the target is in the event subprocess, but should be ignored as they are not 'real' runtime executions + // (but rather waiting for trigger) + if (sourceElement instanceof StartEvent && isInEventSubprocess(sourceElement)) { + return false; + } + // No outgoing seq flow: could be the end of eg . the process or an embedded subprocess + if (sourceElement.getOutgoingFlows().isEmpty()) { + visitedElements.add(sourceElement.getId()); + FlowElementsContainer parentElement = process.findParent(sourceElement); + if (parentElement instanceof SubProcess) { + sourceElement = (SubProcess) parentElement; + // 子流程的结束节点,若目标节点在该子流程中,说明无法到达,返回false + if (((SubProcess) sourceElement).getFlowElement(targetElement.getId()) != null) { + return false; + } + } else { + return false; + } + } + if (sourceElement.getId().equals(targetElement.getId())) { + return true; + } + // To avoid infinite looping, we must capture every node we visit + // and check before going further in the graph if we have already + // visited the node. + visitedElements.add(sourceElement.getId()); + // 当前节点能够到达子流程,且目标节点在子流程中,说明可以到达,返回true + if (sourceElement instanceof SubProcess && ((SubProcess) sourceElement).getFlowElement(targetElement.getId()) != null) { + return true; + } + List sequenceFlows = sourceElement.getOutgoingFlows(); + if (sequenceFlows != null && !sequenceFlows.isEmpty()) { + for (SequenceFlow sequenceFlow : sequenceFlows) { + String targetRef = sequenceFlow.getTargetRef(); + FlowNode sequenceFlowTarget = (FlowNode) process.getFlowElement(targetRef, true); + if (sequenceFlowTarget != null && !visitedElements.contains(sequenceFlowTarget.getId())) { + boolean reachable = isReachable(process, sequenceFlowTarget, targetElement, visitedElements); + if (reachable) { + return true; + } + } + } + } + return false; + } + + protected static boolean isInEventSubprocess(FlowNode flowNode) { + FlowElementsContainer flowElementsContainer = flowNode.getParentContainer(); + while (flowElementsContainer != null) { + if (flowElementsContainer instanceof EventSubProcess) { + return true; + } + if (flowElementsContainer instanceof FlowElement) { + flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer(); + } else { + flowElementsContainer = null; + } + } + return false; + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java index 0dbfda785..be5ecb500 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java @@ -1,34 +1,39 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; -import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.common.utils.BpmnModelUtils; import cn.axzo.workflow.core.engine.job.AsyncBackTaskJobHandler; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.interceptor.CommandContext; -import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.job.service.JobService; import org.flowable.job.service.impl.persistence.entity.JobEntity; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.TaskService; import org.flowable.task.service.impl.persistence.entity.TaskEntity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.Objects; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_TARGET_ACTIVITY_NOT_EXISTS; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; +@Slf4j public class CustomBackTaskAsyncCmd extends AbstractCommand implements Serializable { private static final long serialVersionUID = 1773108485033787095L; - private static final Logger log = LoggerFactory.getLogger(CustomBackTaskAsyncCmd.class); - private final BpmnTaskBackAuditDTO dto; public CustomBackTaskAsyncCmd(BpmnTaskBackAuditDTO dto) { @@ -41,17 +46,25 @@ public class CustomBackTaskAsyncCmd extends AbstractCommand implements S CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); - TaskService taskService = processEngineConfiguration.getTaskService(); + TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); - Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); - if (Objects.isNull(task)) { - log.info("任务不存在: {}", dto.getTaskId()); - } - validTask(historicTaskInstance, (TaskEntity) task, dto.getApprover(), null); + TaskEntity taskEntity = taskService.getTask(dto.getTaskId()); + validTask(historicTaskInstance, taskEntity, dto.getApprover(), dto.getNodeTypes()); - return startAsync(processEngineConfiguration, task); + Process process = ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId()); + FlowElement targetFlowElement = process.getFlowElement(dto.getToActivityId(), true); + if (Objects.isNull(targetFlowElement)) { + throw new WorkflowEngineException(BACK_TARGET_ACTIVITY_NOT_EXISTS, dto.getToActivityId()); + } + FlowElement sourceFlowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true); + // 退回节点到当前节点不可达到,不允许退回 + if (!BpmnModelUtils.isReachable(process, (FlowNode) sourceFlowElement, (FlowNode) targetFlowElement)) { + throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); + } + + return startAsync(processEngineConfiguration, taskEntity); } private String startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 3cb67d09b..53881df93 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -2,18 +2,21 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import cn.axzo.workflow.core.common.utils.BpmnModelUtils; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; -import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.flowable.task.service.TaskService; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import java.io.Serializable; @@ -26,6 +29,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_TARGET_ACTIVITY_NOT_EXISTS; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; @@ -40,14 +44,14 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ private final BpmnTaskBackAuditDTO dto; - private static String operationDesc = "回退至"; + private static final String OPERATION_DESC = "回退至"; @Override public String paramToJsonString() { Map params = new HashMap<>(); params.put("taskId", dto.getTaskId()); params.put("advice", dto.getAdvice()); - params.put("operationDesc", operationDesc); + params.put("operationDesc", OPERATION_DESC); params.put("attachmentList", JSON.toJSONString(dto.getAttachmentList())); params.put("approver", JSON.toJSONString(dto.getApprover())); params.put("nodeTypes", JSON.toJSONString(dto.getNodeTypes())); @@ -61,36 +65,40 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); - TaskService taskService = processEngineConfiguration.getTaskService(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); - TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult(); + TaskEntity task = taskService.getTask(dto.getTaskId()); validTask(historicTaskInstance, task, dto.getApprover(), dto.getNodeTypes()); - BpmnModel bpmnModel = processEngineConfiguration.getRepositoryService().getBpmnModel(historicTaskInstance.getProcessDefinitionId()); - FlowElement flowElement = bpmnModel.getFlowElement(dto.getToActivityId()); - if (Objects.isNull(flowElement)) { + Process process = ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId()); + FlowElement targetFlowElement = process.getFlowElement(dto.getToActivityId(), true); + if (Objects.isNull(targetFlowElement)) { throw new WorkflowEngineException(BACK_TARGET_ACTIVITY_NOT_EXISTS, dto.getToActivityId()); } - + FlowElement sourceFlowElement = process.getFlowElement(task.getTaskDefinitionKey(), true); + // 退回节点到当前节点不可达到,不允许退回 + if (!BpmnModelUtils.isReachable(process, (FlowNode) sourceFlowElement, (FlowNode) targetFlowElement)) { + throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); + } batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); - addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc + flowElement.getName()); + addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, OPERATION_DESC + targetFlowElement.getName()); Authentication.setAuthenticatedUserId(null); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); runtimeService.createChangeActivityStateBuilder() - .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) - .changeState(); + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) + .changeState(); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index 8f3503ac1..9a182aa80 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -63,6 +63,7 @@ import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ASSIGNER_NUMBER import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_TYPE_MISMATCH; import static org.flowable.task.api.Task.DEFAULT_PRIORITY; /** @@ -80,13 +81,13 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); Map executionVariables = new HashMap<>(); executionVariables.put("assigneeName", newTaskAssignee.buildAssigneeId()); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); Execution subExecution = runtimeService.addMultiInstanceExecution(originTask.getTaskDefinitionKey(), - originTask.getProcessInstanceId(), executionVariables); + originTask.getProcessInstanceId(), executionVariables); setParentTaskId(originTask, subExecution); } @@ -96,19 +97,19 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); runtimeService.deleteMultiInstanceExecution(originTask.getExecutionId(), false); } private static void setParentTaskId(TaskEntity originTask, Execution subExecution) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() - .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) - .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); + .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) + .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream() - .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) - .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); + .filter(i -> Objects.equals(i.getExecutionId(), subExecution.getId())) + .findAny().ifPresent(i -> i.setParentTaskId(originTask.getId())); } /** @@ -121,7 +122,7 @@ public class CustomTaskHelper { public static void validTask(HistoricTaskInstance historicTaskInstance, TaskEntity taskEntity, BpmnTaskDelegateAssigner originTaskAssigner, List nodeTypes) { if (Objects.nonNull(historicTaskInstance) && - (Objects.nonNull(historicTaskInstance.getEndTime()) || Objects.isNull(taskEntity))) { + (Objects.nonNull(historicTaskInstance.getEndTime()) || Objects.isNull(taskEntity))) { throw new WorkflowEngineException(TASK_HAS_BEEN_COMPLETE); } @@ -154,7 +155,7 @@ public class CustomTaskHelper { //不包含对应的任务 if (!nodeTypes.contains(nodeType)) { // log.warn(TASK_TYPE_MISMATCH.getMessage(), nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(","))); - throw new WorkflowEngineException(ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT, nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(","))); + throw new WorkflowEngineException(TASK_TYPE_MISMATCH, nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(","))); } } } @@ -171,14 +172,14 @@ public class CustomTaskHelper { TaskEntity taskEntity, List targetAssigneeList) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); // 这个节点下所有审批人快照 String activityListSnapshot = - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); List taskAssignerListSnapshot = - runtimeService.getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class); + runtimeService.getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class); AtomicInteger existsCount = new AtomicInteger(); taskAssignerListSnapshot.forEach(i -> { targetAssigneeList.forEach(j -> { @@ -228,12 +229,12 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); Authentication.setAuthenticatedUserId(assigner.buildAssigneeId()); attachmentList.forEach(dto -> { Attachment attachment = taskService.createAttachment(dto.getType().getType(), taskId, processInstanceId, - dto.getName(), dto.getDescription(), dto.getUrl()); + dto.getName(), dto.getDescription(), dto.getUrl()); taskService.saveAttachment(attachment); }); Authentication.setAuthenticatedUserId(null); @@ -256,7 +257,7 @@ public class CustomTaskHelper { return; } ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); String userId = Authentication.getAuthenticatedUserId(); CommentEntity comment = processEngineConfiguration.getCommentEntityManager().create(); @@ -281,7 +282,7 @@ public class CustomTaskHelper { public static Attachment addAttachment(CommandContext commandContext, Task task, AttachmentDTO attachmentDto) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); AttachmentEntity attachment = processEngineConfiguration.getAttachmentEntityManager().create(); attachment.setName(attachmentDto.getName()); attachment.setProcessInstanceId(task.getProcessInstanceId()); @@ -297,11 +298,11 @@ public class CustomTaskHelper { ExecutionEntity processInstance = null; if (task.getProcessInstanceId() != null) { processInstance = - processEngineConfiguration.getExecutionEntityManager().findById(task.getProcessInstanceId()); + processEngineConfiguration.getExecutionEntityManager().findById(task.getProcessInstanceId()); } processEngineConfiguration.getHistoryManager().createAttachmentComment((TaskEntity) task, processInstance, - attachmentDto.getName(), true); + attachmentDto.getName(), true); return attachment; } @@ -320,15 +321,15 @@ public class CustomTaskHelper { * @return */ public static Task createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService - , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, + , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, BpmnTaskDelegateAssigner assigner, String extTaskInstStatus, AddComment addComment) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); HistoricProcessInstance processInstance = - historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); IdGenerator idGenerator = processEngineConfiguration.getIdGenerator(); @@ -345,12 +346,12 @@ public class CustomTaskHelper { if (Objects.nonNull(assigner)) { CommandContextUtil.getEntityCache().findInCache(TaskEntity.class).stream() - .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() - .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); + .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() + .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream() - .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() - .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); + .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() + .ifPresent(i -> i.setAssignee(assigner.buildAssigneeId())); } // 添加审批意见 @@ -359,7 +360,7 @@ public class CustomTaskHelper { addComment(commandContext, task, addComment); CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, task.getProcessInstanceId(), task.getId(), - task.getTaskDefinitionKey(), assigner, extTaskInstStatus); + task.getTaskDefinitionKey(), assigner, extTaskInstStatus); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), extTaskInstStatus); // 保存任务 @@ -378,7 +379,7 @@ public class CustomTaskHelper { public static Task completeVirtualTask(CommandContext commandContext, Task task) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); TaskService taskService = processEngineConfiguration.getTaskService(); taskService.complete(task.getId()); return task; @@ -415,10 +416,10 @@ public class CustomTaskHelper { return delegateAssigners; } return new ArrayList<>(delegateAssigners.stream() - .filter(i -> StringUtils.hasText(i.getPersonId())) - .filter(i -> !Objects.equals(i.getPersonId(), "null")) - .collect(Collectors.toMap(BpmnTaskDelegateAssigner::getPersonId, Function.identity(), (s, t) -> s)) - .values()); + .filter(i -> StringUtils.hasText(i.getPersonId())) + .filter(i -> !Objects.equals(i.getPersonId(), "null")) + .collect(Collectors.toMap(BpmnTaskDelegateAssigner::getPersonId, Function.identity(), (s, t) -> s)) + .values()); } /** @@ -445,27 +446,27 @@ public class CustomTaskHelper { List result = new ArrayList<>(); List taskInstances = historyService.createHistoricTaskInstanceQuery() - .processInstanceId(processInstanceId) - .orderByHistoricTaskInstanceStartTime() - .desc().list(); + .processInstanceId(processInstanceId) + .orderByHistoricTaskInstanceStartTime() + .desc().list(); List vos = historicTaskInstanceConverter.toVosSkipSystemOperation(taskInstances, - serviceVersion); + serviceVersion); Map variableInstanceMap = - // 不能使用框架提供的历史变量 API 查询,有 BUG - historyService.createNativeHistoricVariableInstanceQuery() - .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") - .parameter("processInstanceId", processInstanceId) - .list().stream() - .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, - Function.identity(), (s, t) -> s)); + // 不能使用框架提供的历史变量 API 查询,有 BUG + historyService.createNativeHistoricVariableInstanceQuery() + .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") + .parameter("processInstanceId", processInstanceId) + .list().stream() + .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, + Function.identity(), (s, t) -> s)); vos.forEach(vo -> { HistoricVariableInstance assginerSnapshot = - variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), - null); + variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), + null); if (Objects.isNull(assginerSnapshot)) { assginerSnapshot = - variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); + variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); } if (Objects.nonNull(assginerSnapshot)) { BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(assginerSnapshot.getValue()); @@ -481,27 +482,27 @@ public class CustomTaskHelper { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); Process process = ProcessDefinitionUtil.getProcess(processDefinitionId); List taskDefinitionKeys = process.getFlowElements().stream() - .filter(i -> Objects.equals(BpmnMetaParserHelper.getNodeType(i).orElse(null), BpmnFlowNodeType.NODE_CARBON_COPY)) - .map(FlowElement::getId) - .collect(Collectors.toList()); + .filter(i -> Objects.equals(BpmnMetaParserHelper.getNodeType(i).orElse(null), BpmnFlowNodeType.NODE_CARBON_COPY)) + .map(FlowElement::getId) + .collect(Collectors.toList()); if (CollectionUtils.isEmpty(taskDefinitionKeys)) { return Collections.emptyList(); } List variableInstances = processEngineConfiguration.getHistoryService().createHistoricVariableInstanceQuery() - .variableNameLike(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT) - .processInstanceId(processInstanceId) - .list(); + .variableNameLike(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT) + .processInstanceId(processInstanceId) + .list(); if (CollectionUtils.isEmpty(variableInstances)) { return Collections.emptyList(); } List result = new ArrayList<>(); taskDefinitionKeys.forEach(j -> { variableInstances.stream() - .filter(i -> Objects.equals(i.getVariableName(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + j)) - .findFirst().ifPresent(i -> { - result.addAll((List) i.getValue()); - }); + .filter(i -> Objects.equals(i.getVariableName(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + j)) + .findFirst().ifPresent(i -> { + result.addAll((List) i.getValue()); + }); }); return result; } From f20ba76d4913df12a2f9e30a8876362546c68f17 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 14:48:03 +0800 Subject: [PATCH 058/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=89=80=E6=9C=89=20Assignee=20=E7=9A=84=E4=BA=BA=E5=90=8D?= =?UTF-8?q?=E5=92=8C=E5=A4=B4=E5=83=8F=EF=BC=8C=E7=A1=AE=E4=BF=9D=E4=B8=80?= =?UTF-8?q?=E5=AE=9A=E6=9C=89=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/SupportRefreshProperties.java | 12 ++++++ .../job/AsyncTermNodeAlterJobHandler.java | 2 +- .../EngineExecutionStartListener.java | 21 ++++------- .../AbstractBpmnTaskAssigneeSelector.java | 37 ++++++++++++------- .../web/BasicPopulateAvatarController.java | 23 +++++------- .../VersionUpgradeInitializer.java | 2 +- 6 files changed, 56 insertions(+), 41 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index df2fc358b..d915b8e7b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -27,6 +28,17 @@ public class SupportRefreshProperties { @Value("${workflow.apiLog.filterApiType:}") private String filterApiType; + @Value("${workflow.api.timeout:10}") + private Long apiTimeout; + @Value("${workflow.mock:false}") + private Boolean mock; + @Value("${workflow.assignee.global:true}") + private Boolean global; + @Value("${workflow.assignee.category:''}") + private String category; + @Value("#{${workflow.assignee.map:{}}}") + private Map assigneeMap; + @Value("${workflow.alter.enable:false}") private Boolean alterEnable = false; /** diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java index 3b264bebc..330a70d4f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java @@ -37,7 +37,7 @@ public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements .createTimerJobQuery().elementId(dto.getActivityId()) .processInstanceId(dto.getProcessInstanceId()).singleResult(); - if (Objects.equals(timerJob.getRetries(), dto.getRetries())) { + if (Objects.isNull(timerJob) || Objects.equals(timerJob.getRetries(), dto.getRetries())) { return; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java index b1a66b45b..7990cf413 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector; import cn.axzo.workflow.core.deletage.BpmnTaskCalculateDTO; import cn.axzo.workflow.core.deletage.BpmnTaskDelegate; @@ -74,16 +75,9 @@ public class EngineExecutionStartListener implements ExecutionListener { @Resource @Lazy private List selectors; - @Value("${workflow.api.timeout:10}") - private Long apiTimeout; - @Value("${workflow.mock:false}") - private Boolean mock; - @Value("${workflow.assignee.global:true}") - private Boolean global; - @Value("${workflow.assignee.category:''}") - private String category; - @Value("#{${workflow.assignee.map:{}}}") - private Map assigneeMap; + @Resource + private SupportRefreshProperties refreshProperties; + @Override public void notify(DelegateExecution execution) { @@ -235,6 +229,10 @@ public class EngineExecutionStartListener implements ExecutionListener { * \"personId\":\"89508\",\"assignee\":\"2000560\",\"assigneeType\":\"3\"}]' * }" */ + Boolean mock = refreshProperties.getMock(); + Boolean global = refreshProperties.getGlobal(); + String category = refreshProperties.getCategory(); + Map assigneeMap = refreshProperties.getAssigneeMap(); if ((mock && global) || (mock && !global && Objects.equals(category, execution.getProcessDefinitionId().split(":")[0]))) { log.info("当前系统 Nacos 配置中开启了 mock: {}, 将使用 mock 方式查找审批人", mock); @@ -308,7 +306,4 @@ public class EngineExecutionStartListener implements ExecutionListener { }); } - public Long getApiTimeout() { - return apiTimeout; - } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index af15e04bc..1889fe585 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -9,6 +9,7 @@ import cn.axzo.workflow.common.enums.CarbonCopyObjectType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeProcessor; @@ -38,6 +39,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -57,8 +59,9 @@ import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_US public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssigneeSelector, ApplicationContextAware { @Resource protected FlowSupportApi flowSupportApi; + @Resource + protected SupportRefreshProperties refreshProperties; private ApplicationContext applicationContext; - private EngineExecutionStartListener executionStartListener; @Override public List select(FlowElement flowElement, DelegateExecution execution, @@ -96,7 +99,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign } } try { - return populateAvatar(invokeService(flowElement, execution, scopeDto)); + return populateNameAndAvatar(invokeService(flowElement, execution, scopeDto), flowSupportApi, refreshProperties, applicationContext); } catch (Throwable t) { if (throwException) { if (!(t instanceof WorkflowEngineException)) { @@ -115,9 +118,14 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return Collections.emptyList(); } - protected final T parseApiResult(Supplier> supplier, String operatorDesc, - String extInfo, Object... param) { + String extInfo, Object... param) { + return parseApiResult(supplier, operatorDesc, extInfo, refreshProperties, applicationContext, param); + } + + public static T parseApiResult(Supplier> supplier, String operatorDesc, + String extInfo, SupportRefreshProperties refreshProperties, + ApplicationContext context, Object... param) { StopWatch stopWatch = new StopWatch(operatorDesc); log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); stopWatch.start(); @@ -127,8 +135,8 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign "API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's", JSONUtil.toJsonStr(result)); try { - if (stopWatch.getTotalTimeSeconds() > executionStartListener.getApiTimeout()) { - DingTalkUtils.sendDingTalkForSlowUrl(applicationContext.getEnvironment() + if (stopWatch.getTotalTimeSeconds() > refreshProperties.getApiTimeout()) { + DingTalkUtils.sendDingTalkForSlowUrl(context.getEnvironment() .getProperty("spring.profiles.active"), stopWatch.getTotalTimeSeconds(), extInfo, @@ -183,22 +191,26 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign } } - private List populateAvatar(List assigners) { + public static List populateNameAndAvatar(List assigners, + FlowSupportApi flowSupportApi, + SupportRefreshProperties refreshProperties, + ApplicationContext context) { if (CollectionUtils.isEmpty(assigners)) { return assigners; } List personIds = assigners.stream() - .filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) +// .filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) .map(BpmnTaskDelegateAssigner::getPersonId) .map(Long::parseLong) .distinct().collect(Collectors.toList()); - Map personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), - "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds) - .stream().collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl, (s, t) -> s)); + Map personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), + "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds) + .stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s)); assigners.forEach(assigner -> { long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1")); if (personProfileMap.containsKey(personId)) { - assigner.setAvatar(personProfileMap.getOrDefault(personId, "")); + assigner.setAvatar(personProfileMap.getOrDefault(personId, new PersonProfileResp()).getAvatarUrl()); + assigner.setAssignerName(personProfileMap.getOrDefault(personId, new PersonProfileResp()).getRealName()); } }); return assigners; @@ -207,7 +219,6 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.applicationContext = context; - executionStartListener = applicationContext.getBean(EngineExecutionStartListener.class); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java index fe22b2991..380679a83 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/BasicPopulateAvatarController.java @@ -4,8 +4,11 @@ import cn.axzo.karma.client.feign.FlowSupportApi; import cn.axzo.karma.client.model.request.PersonProfileQueryReq; import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.server.common.util.RpcExternalUtil; +import cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector; import com.google.common.collect.Lists; +import org.springframework.context.ApplicationContext; import org.springframework.util.StringUtils; import javax.annotation.Resource; @@ -15,6 +18,8 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.populateNameAndAvatar; + /** * 公共的获取 BpmnTask * @@ -25,6 +30,10 @@ public abstract class BasicPopulateAvatarController { @Resource protected FlowSupportApi flowSupportApi; + @Resource + private SupportRefreshProperties refreshProperties; + @Resource + private ApplicationContext applicationContext; /** * 为一个人填充头像 @@ -44,19 +53,7 @@ public abstract class BasicPopulateAvatarController { * @param assigners */ protected final void populateUsersAvatar(List assigners) { - List personIds = assigners.stream().filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) - .map(BpmnTaskDelegateAssigner::getPersonId) - .map(Long::parseLong) - .distinct().collect(Collectors.toList()); - Map personMap = RpcExternalUtil.rpcApiResultProcessor(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), - "查询档案信息", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", personIds).stream() - .collect(Collectors.toMap(PersonProfileResp::getId, PersonProfileResp::getAvatarUrl)); - assigners.forEach(e -> { - long personId = Long.parseLong(Optional.ofNullable(e.getPersonId()).orElse("-1")); - if (personMap.containsKey(personId)) { - e.setAvatar(personMap.getOrDefault(personId, "")); - } - }); + populateNameAndAvatar(assigners, flowSupportApi, refreshProperties, applicationContext); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/VersionUpgradeInitializer.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/VersionUpgradeInitializer.java index 3100fa923..e8bcc5a18 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/VersionUpgradeInitializer.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/VersionUpgradeInitializer.java @@ -72,8 +72,8 @@ public class VersionUpgradeInitializer implements ApplicationRunner { .map(DefaultArtifactVersion::new) .sorted() .forEach(upgradeVersion -> { - log.info("数据库升级版本比较: upgradeVersion: {}, inDbVersion:{} ", upgradeVersion, dbVersion); if (upgradeVersion.compareTo(dbVersion) > 0) { + log.info("数据库升级版本比较: upgradeVersion: {}, inDbVersion:{} ", upgradeVersion, dbVersion); newVersions.add(upgradeVersion); String fileName = FILE_PREFIX + upgradeVersion + ".sql"; try { From c565a8c4e23e69f70ca1e16b32409503dab81c7f Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 15:57:54 +0800 Subject: [PATCH 059/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=8F=AF=E8=BE=BE=E8=B7=AF=E5=BE=84=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java | 2 +- .../cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java | 2 +- .../cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java index be5ecb500..d43b60a7e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java @@ -60,7 +60,7 @@ public class CustomBackTaskAsyncCmd extends AbstractCommand implements S } FlowElement sourceFlowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true); // 退回节点到当前节点不可达到,不允许退回 - if (!BpmnModelUtils.isReachable(process, (FlowNode) sourceFlowElement, (FlowNode) targetFlowElement)) { + if (!BpmnModelUtils.isReachable(process, (FlowNode) targetFlowElement, (FlowNode) sourceFlowElement)) { throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index 53881df93..a3d113c81 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -82,7 +82,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ } FlowElement sourceFlowElement = process.getFlowElement(task.getTaskDefinitionKey(), true); // 退回节点到当前节点不可达到,不允许退回 - if (!BpmnModelUtils.isReachable(process, (FlowNode) sourceFlowElement, (FlowNode) targetFlowElement)) { + if (!BpmnModelUtils.isReachable(process, (FlowNode) targetFlowElement, (FlowNode) sourceFlowElement)) { throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); } batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java index 18e70a31c..1e70e2247 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java @@ -15,7 +15,7 @@ import org.slf4j.LoggerFactory; * @since 2024/5/21 09:46 */ public class CustomCommandContext extends CommandContext { - private static final Logger LOGGER = LoggerFactory.getLogger(CommandContext.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CustomCommandContext.class); public CustomCommandContext(Command command) { super(command); From 3c36040c29cde3ce227b72b2b3c86932cc15a60c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 16:00:20 +0800 Subject: [PATCH 060/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E9=87=8D=E8=AF=95=E5=A4=B1=E8=B4=A5=E5=90=8E=E7=9A=84=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/common/code/FlowableEngineRespCode.java | 2 +- .../core/engine/interceptor/CustomRetryInterceptor.java | 6 +++++- .../workflow/server/common/aspectj/ErrorReportAspect.java | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java index 7fbdc0886..319e88a95 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/FlowableEngineRespCode.java @@ -19,7 +19,7 @@ public enum FlowableEngineRespCode implements IModuleRespCode { ENGINE_USER_TASK_PARAM_ERROR("004", "构建后的查询审批人入参为空. 任务节点【nodeId:{}】, 该节点选择的\"审批人所在范围\"是:【{}】,请检查 cooperationOrg 参数"), ENGINE_NOTICE_CUSTOM_FLOW_ELEMENT_ERROR("005", "查询通知目标用户前参数发生异常,未获取到 WorkspaceType"), ENGINE_ASYNC_COMMAND_EXECUTION_ERROR("006", "引擎出现 SQL 相关异常, 异常信息:【{}】"), - ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃"), + ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃, 错误信息:{}"), ; private final String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java index c4a634bad..1c5d4e989 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/interceptor/CustomRetryInterceptor.java @@ -10,6 +10,8 @@ import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandConfig; import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import java.util.Objects; + import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP; /** @@ -29,6 +31,7 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { public T execute(CommandConfig config, Command command, CommandExecutor commandExecutor) { long waitTime = waitTimeInMs; int failedAttempts = 0; + Throwable lastException = null; do { if (failedAttempts > 0) { log.warn("Waiting for {}ms before retrying the command.", waitTime); @@ -47,12 +50,13 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor { } catch (PersistenceException e) { log.warn("Caught persistence exception: {}", e.getMessage(), e); + lastException = e; } failedAttempts++; } while (failedAttempts <= numOfRetries); - throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries)); + throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries), lastException.getMessage()); } protected void waitBeforeRetry(long waitTime) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java index d21404b0c..9c10446ab 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java @@ -21,8 +21,10 @@ import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.util.StopWatch; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.request.ServletWebRequest; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -135,6 +137,7 @@ public class ErrorReportAspect implements Ordered { if (workflowProperties.getFilterSendDingTalk().contains(operation.summary())) { filterSendDingTalk = false; } + ServletWebRequest request= (ServletWebRequest) RequestContextHolder.getRequestAttributes(); envConfig.type().executeAction(profile, operation.summary(), filterSendDingTalk, joinPoint.getArgs(), joinPoint.getSignature().toShortString(), e, workflowProperties.getFilterOperations().contains(operation.summary())); From 498c6536ae0de88233d4a6a8e43c6edc587f1343 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 16:12:04 +0800 Subject: [PATCH 061/139] =?UTF-8?q?REQ-2924-=E5=A2=9E=E5=8A=A0=E9=80=80?= =?UTF-8?q?=E5=9B=9E=E8=8A=82=E7=82=B9=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessTaskServiceImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 896bcbc0f..4d8666e0f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -132,6 +132,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueO import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_TASK_NOT_EXISTS; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.FIND_TASK_BY_PERSON_ID_ERROR; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS; import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet; @@ -335,6 +336,14 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Override @Transactional(rollbackFor = Exception.class) public void backTask(BpmnTaskBackAuditDTO dto) { + List backOptionalNodes = getBackOptionalNodes(dto.getTaskId()); + if (CollectionUtils.isEmpty(backOptionalNodes)) { + throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); + } + List activityList = backOptionalNodes.stream().map(BpmnOptionalNodeDTO::getProcessActivityId).collect(Collectors.toList()); + if (!activityList.contains(dto.getToActivityId())) { + throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); + } CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); if (Boolean.TRUE.equals(dto.getAsync())) { commandExecutor.execute(new CustomBackTaskAsyncCmd(dto)); From 67674c5989d2d49db8c788e49dac10f3b6192a2b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 16:36:43 +0800 Subject: [PATCH 062/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=E8=A1=A8=E7=9A=84=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E5=85=9C=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/sql/upgrade_to_1.4.2.sql | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index e7d619d3a..4e31c7f9a 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -2,27 +2,27 @@ create table `workflow-engine`.ext_ax_process_log ( id bigint auto_increment comment '主键' primary key, - process_instance_id varchar(64) default '' not null comment '流程实例 ID', - tenant_id bigint not null comment '实例归属租户', - activity_id varchar(64) default '' not null comment '节点 ID', - activity_name varchar(255) default '' not null comment '节点名称', - approval_method varchar(32) default '' not null comment '审批方式:配置审批人/业务指定/业务触发(不含人)', - node_type varchar(32) default '' not null comment '节点类型:审批节点/业务节点/评论节点/抄送节点', - node_mode varchar(32) default '' not null comment '节点模式:会签/或签', - task_id varchar(64) default '' not null comment '任务 ID', - advice varchar(4000) default '' not null comment '操作建议', - operation_desc varchar(4000) default '' not null comment '操作描述', - assignee_full json null comment '审批人(JSON)', - assignee_id bigint default 0 not null comment '审批人标识(axzo=personId)', - assignee_tenant_id varchar(255) default '' not null comment '审批人归属租户', - assignee_name varchar(255) default '' not null comment '审批人姓名', - assignee_ou_id bigint default 0 not null comment '审批人归属单位', + process_instance_id varchar(64) default '' not null comment '流程实例 ID', + tenant_id varchar(64) default '' not null comment '实例归属租户', + activity_id varchar(64) default '' not null comment '节点 ID', + activity_name varchar(255) default '' not null comment '节点名称', + approval_method varchar(32) default '' not null comment '审批方式:配置审批人/业务指定/业务触发(不含人)', + node_type varchar(32) default '' not null comment '节点类型:审批节点/业务节点/评论节点/抄送节点', + node_mode varchar(32) default '' not null comment '节点模式:会签/或签', + task_id varchar(64) default '' not null comment '任务 ID', + advice varchar(4000) default '' not null comment '操作建议', + operation_desc varchar(4000) default '' not null comment '操作描述', + assignee_full json null comment '审批人(JSON)', + assignee_id bigint default 0 not null comment '审批人标识(axzo=personId)', + assignee_tenant_id varchar(255) default '' not null comment '审批人归属租户', + assignee_name varchar(255) default '' not null comment '审批人姓名', + assignee_ou_id bigint default 0 not null comment '审批人归属单位', start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', end_time datetime(3) null comment '任务结束时间', - button_conf json null comment '按钮配置', - status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', - extra json null comment '扩展字段', - create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', - update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete bigint default 0 not null comment '是否删除' + button_conf json null comment '按钮配置', + status varchar(16) default '' not null comment '任务状态:审批中/通过/驳回/转交/加签', + extra json null comment '扩展字段', + create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间', + update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete bigint default 0 not null comment '是否删除' ) comment '审批日志持久化'; From 252a8e278f31d1de044081c268ca4889f50fc925 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 16:39:33 +0800 Subject: [PATCH 063/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=E8=A1=A8=E7=9A=84=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E5=85=9C=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/bpmn/process/BpmnProcessInstanceCreateDTO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java index b948cb521..1dd607cb9 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java @@ -43,9 +43,9 @@ public class BpmnProcessInstanceCreateDTO { * 发起流程实例归属租户 ID *

* 为空时,默认是编辑公共流程模型, 如果是代运营创建,则必填 + *

建议都传值,在安心筑中对应工作台 ID

*/ @ApiModelProperty(value = "发起的审批是属于哪个租户") -// @NotBlank(message = "审批实例归属租户 ID 不能为空") private String tenantId; /** From 9f11bd21abfc30a744bb785efd3afe28f1800920 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 17:11:43 +0800 Subject: [PATCH 064/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/aspectj/ErrorReportAspect.java | 34 +++++++++++++------ .../AbstractBpmnTaskAssigneeSelector.java | 2 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java index 9c10446ab..9dfcba629 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java @@ -20,11 +20,10 @@ import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.context.request.ServletWebRequest; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -85,13 +84,13 @@ public class ErrorReportAspect implements Ordered { if (!signature.toShortString().contains("ExtAxApiLogServiceImpl")) { String type = getType(joinPoint); ApiLogEvent event = new ApiLogEvent(MDC.get(CTX_LOG_ID_MDC), - signature.toShortString(), - Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_SERVER_NAME), - Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_API_VERSION), - Objects.equals(type, "Controller") ? joinPoint.getArgs() : null, - Objects.equals(type, "Controller") ? result : null, - watch.getTotalTimeSeconds(), - type); + signature.toShortString(), + Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_SERVER_NAME), + Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_API_VERSION), + Objects.equals(type, "Controller") ? joinPoint.getArgs() : null, + Objects.equals(type, "Controller") ? result : null, + watch.getTotalTimeSeconds(), + type); applicationEventPublisher.publishEvent(event); } @@ -137,14 +136,27 @@ public class ErrorReportAspect implements Ordered { if (workflowProperties.getFilterSendDingTalk().contains(operation.summary())) { filterSendDingTalk = false; } - ServletWebRequest request= (ServletWebRequest) RequestContextHolder.getRequestAttributes(); + + log.error("request header server name: {}", getHeader()); envConfig.type().executeAction(profile, operation.summary(), filterSendDingTalk, joinPoint.getArgs(), joinPoint.getSignature().toShortString(), e, - workflowProperties.getFilterOperations().contains(operation.summary())); + workflowProperties.getFilterOperations().contains(operation.summary())); } } } + private String getHeader() { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (Objects.isNull(attributes)) { + return ""; + } + + HttpServletRequest request = attributes.getRequest(); + // 获取指定请求头的值 + String headerValue = request.getHeader(HEADER_SERVER_NAME); + return StringUtils.hasText(headerValue) ? headerValue : ""; + } + private HttpServletRequest getOriginRequest() { try { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 1889fe585..978be677b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -199,8 +199,8 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return assigners; } List personIds = assigners.stream() -// .filter(e -> !StringUtils.hasText(e.getAvatar()) && StringUtils.hasText(e.getPersonId())) .map(BpmnTaskDelegateAssigner::getPersonId) + .filter(StringUtils::hasText) .map(Long::parseLong) .distinct().collect(Collectors.toList()); Map personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), From eb809a6157cef6852d98f4001f9e46bb015f1c64 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 17:42:24 +0800 Subject: [PATCH 065/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/AbstractBpmnTaskAssigneeSelector.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 978be677b..2a6045c7c 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -209,8 +209,12 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign assigners.forEach(assigner -> { long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1")); if (personProfileMap.containsKey(personId)) { + log.warn("查询到的人员信息:{}", JSON.toJSONString(personProfileMap.getOrDefault(personId, null))); assigner.setAvatar(personProfileMap.getOrDefault(personId, new PersonProfileResp()).getAvatarUrl()); assigner.setAssignerName(personProfileMap.getOrDefault(personId, new PersonProfileResp()).getRealName()); + + } else { + log.warn("未找到对应 person:{} 的数据", personId); } }); return assigners; From c2cb856bde5d2975d276f8e67d84b271ef2228b0 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 18:12:06 +0800 Subject: [PATCH 066/139] =?UTF-8?q?REQ-2924-=E5=A2=9E=E5=8A=A0=E9=92=89?= =?UTF-8?q?=E9=92=89=E6=8F=90=E9=86=92=E5=BC=82=E5=B8=B8=E5=A0=86=E6=A0=88?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessJobApi.java | 8 +++++ .../core/service/BpmnProcessJobService.java | 2 ++ .../impl/BpmnProcessJobServiceImp.java | 18 ++++++++++ .../server/common/util/DingTalkUtils.java | 35 ++++++++++++++++++- .../web/bpmn/BpmnProcessJobController.java | 11 +++++- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index e38ae9caa..b04822150 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -24,4 +24,12 @@ public interface ProcessJobApi { @Manageable CommonResponse executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + + /** + * 查询死信消息数据 + * @param procInstId 流程实例id + * @return + */ + @GetMapping("/dead-letter/info") + String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java index d3b8db1f9..869357a84 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java @@ -5,4 +5,6 @@ public interface BpmnProcessJobService { void executeDeadLetterJobActionByJobId(String jobId); void executeDeadLetterJobActionByProcInstId(String processInstanceId); + + String getDeadLetterJobExceptionStacktrace(String processInstId); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java index c320b7a73..cc072148c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java @@ -8,6 +8,7 @@ import org.flowable.engine.ManagementService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.job.api.Job; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.List; @@ -39,6 +40,23 @@ public class BpmnProcessJobServiceImp implements BpmnProcessJobService { } } + @Override + public String getDeadLetterJobExceptionStacktrace(String processInstId) { + List jobs = managementService.createDeadLetterJobQuery().processInstanceId(processInstId).list(); + if (CollectionUtils.isEmpty(jobs)) { + return ""; + } + StringBuilder builder = new StringBuilder(); + jobs.forEach(job -> { + String deadLetterJobExceptionStacktrace = managementService.getDeadLetterJobExceptionStacktrace(job.getId()); + if (StringUtils.hasText(deadLetterJobExceptionStacktrace)) { + builder.append(deadLetterJobExceptionStacktrace); + builder.append("\n"); + } + }); + return builder.toString(); + } + protected Job getDeadLetterJobById(String jobId) { Job job = managementService.createDeadLetterJobQuery().jobId(jobId).singleResult(); if (job == null) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index 99282c0fe..419fee612 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.server.common.util; +import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; @@ -7,7 +8,10 @@ import com.dingtalk.api.request.OapiRobotSendRequest; import com.dingtalk.api.response.OapiRobotSendResponse; import lombok.SneakyThrows; import org.slf4j.MDC; +import org.springframework.util.StringUtils; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; @@ -23,6 +27,16 @@ public class DingTalkUtils { private static final String dingtalk_robot_webhook = "https://oapi.dingtalk" + ".com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; + private static final Map ENV_URL_MAPPING = new HashMap<>(); + + static { + ENV_URL_MAPPING.put("dev", "https://dev-app.axzo.cn"); + ENV_URL_MAPPING.put("test", "https://test-api.axzo.cn"); + ENV_URL_MAPPING.put("pre", "https://pre-api.axzo.cn"); + ENV_URL_MAPPING.put("live", "https://live-api.axzo.cn"); + ENV_URL_MAPPING.put("default", "https://api.axzo.cn"); + } + @SneakyThrows public static void sendDingTalk(String profile, String title, Object req, Throwable throwable) { OapiRobotSendRequest request = new OapiRobotSendRequest(); @@ -33,11 +47,30 @@ public class DingTalkUtils { "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : throwable.getCause().getMessage()) + " \n\n" + - "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n"); + "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + + "> ##### stackUrl: " + getDeadLetterStacktrace(profile, req) + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } + private static String getDeadLetterStacktrace(String profile, Object req) { + try { + String urlPrefix = ENV_URL_MAPPING.get(profile); + if (!StringUtils.hasText(urlPrefix)) { + urlPrefix = ENV_URL_MAPPING.get("default"); + } + JSONObject entries = JSONUtil.parseObj(req); + String processInstanceId = entries.getStr("processInstanceId"); + if (!StringUtils.hasText(processInstanceId)) { + return ""; + } + return urlPrefix + "/web/v1/api/process/job/dead-letter/exception/stacktrace?procInstId=" + processInstanceId; + } catch (Exception e) { + return "构造查询错误堆栈地址异常:" + e.getMessage(); + } + + } + @SneakyThrows public static void sendDingTalkForSlowUrl(String profile, Double time, String apiUrl, Object requestParam, Object responseBody) { OapiRobotSendRequest request = new OapiRobotSendRequest(); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java index 666101425..88294a487 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java @@ -5,8 +5,8 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.service.BpmnProcessJobService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.azxo.framework.common.model.CommonResponse; -import com.alibaba.nacos.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -45,4 +45,13 @@ public class BpmnProcessJobController implements ProcessJobApi { } return success(); } + + @Override + @GetMapping("/dead-letter/exception/stacktrace") + public String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId) { + if (StringUtils.isBlank(procInstId)) { + return ""; + } + return bpmnProcessJobService.getDeadLetterJobExceptionStacktrace(procInstId); + } } From faa9409b4a370dd19b2cea301a5cde3ff006be1d Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 18:42:24 +0800 Subject: [PATCH 067/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E9=92=89?= =?UTF-8?q?=E9=92=89=E6=89=93=E5=8D=B0=E5=A0=86=E6=A0=88=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/client/feign/bpmn/ProcessJobApi.java | 10 +++++++++- .../workflow/core/service/BpmnProcessJobService.java | 2 ++ .../core/service/impl/BpmnProcessJobServiceImp.java | 8 ++++++++ .../workflow/server/common/util/DingTalkUtils.java | 6 +++--- .../controller/web/bpmn/BpmnProcessJobController.java | 9 +++++++++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index b04822150..732913fdd 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -30,6 +30,14 @@ public interface ProcessJobApi { * @param procInstId 流程实例id * @return */ - @GetMapping("/dead-letter/info") + @GetMapping("/dead-letter/exception/stacktrace") String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); + + /** + * 查询死信消息数据 + * @param jobId 死信job的id + * @return + */ + @GetMapping("/dead-letter/exception/stacktrace/byId") + String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java index 869357a84..1bad2f2cd 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessJobService.java @@ -7,4 +7,6 @@ public interface BpmnProcessJobService { void executeDeadLetterJobActionByProcInstId(String processInstanceId); String getDeadLetterJobExceptionStacktrace(String processInstId); + + String getDeadLetterJobExceptionStacktraceByJobId(String jobId); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java index cc072148c..c336f5f9a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessJobServiceImp.java @@ -57,6 +57,14 @@ public class BpmnProcessJobServiceImp implements BpmnProcessJobService { return builder.toString(); } + @Override + public String getDeadLetterJobExceptionStacktraceByJobId(String jobId) { + if (!StringUtils.hasText(jobId)) { + return ""; + } + return managementService.getDeadLetterJobExceptionStacktrace(jobId); + } + protected Job getDeadLetterJobById(String jobId) { Job job = managementService.createDeadLetterJobQuery().jobId(jobId).singleResult(); if (job == null) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index 419fee612..0233bfcea 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -60,11 +60,11 @@ public class DingTalkUtils { urlPrefix = ENV_URL_MAPPING.get("default"); } JSONObject entries = JSONUtil.parseObj(req); - String processInstanceId = entries.getStr("processInstanceId"); - if (!StringUtils.hasText(processInstanceId)) { + String jobId = entries.getStr("id"); + if (!StringUtils.hasText(jobId)) { return ""; } - return urlPrefix + "/web/v1/api/process/job/dead-letter/exception/stacktrace?procInstId=" + processInstanceId; + return urlPrefix + "/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; } catch (Exception e) { return "构造查询错误堆栈地址异常:" + e.getMessage(); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java index 88294a487..dd056d70a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java @@ -54,4 +54,13 @@ public class BpmnProcessJobController implements ProcessJobApi { } return bpmnProcessJobService.getDeadLetterJobExceptionStacktrace(procInstId); } + + @Override + @GetMapping("/dead-letter/exception/stacktrace/byId") + public String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId) { + if (StringUtils.isBlank(jobId)) { + return ""; + } + return bpmnProcessJobService.getDeadLetterJobExceptionStacktrace(jobId); + } } From 7c9e9f387e929b0affe466b49a134d2eb387ba1e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 12 Sep 2024 19:03:12 +0800 Subject: [PATCH 068/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomApproveTaskCmd.java | 2 +- .../core/engine/cmd/CustomCommentTaskCmd.java | 2 +- .../cmd/CustomCountersignUserTaskCmd.java | 18 ++++++------- .../engine/cmd/CustomRejectionTaskCmd.java | 3 ++- .../entity/type/TaskEntityEventHandle.java | 15 +++++------ .../common/aspectj/ErrorReportAspect.java | 2 +- .../web/bpmn/BpmnProcessTaskController.java | 27 ++++++++++++------- 7 files changed, 39 insertions(+), 30 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index fe3aca1e0..13e26a173 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -139,7 +139,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER, nextApprover); } - ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); executeSynchronous(task, taskService, runtimeService); return null; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java index c712829b0..020348eb5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java @@ -129,7 +129,7 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria taskService.saveTask(task); // 设置快照信息 - task.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), operator.toJson()); + task.setTransientVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), operator.toJson()); // 完成临时节点 taskService.complete(task.getId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java index 7f190bc6b..577e5af01 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java @@ -81,20 +81,20 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult(); TaskService taskService = processEngineConfiguration.getTaskService(); - Task task = taskService.createTaskQuery().taskId(originTaskId).singleResult(); + TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult(); - validTask(historicTaskInstance, (TaskEntity) task, originTaskAssignee, null); + validTask(historicTaskInstance, task, originTaskAssignee, null); - validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), (TaskEntity) task, targetTaskAssigneeList); + validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), task, targetTaskAssigneeList); List taskDelegateAssigners = - validTaskAssignerDuplicated(commandContext, (TaskEntity) task, targetTaskAssigneeList); + validTaskAssignerDuplicated(commandContext, task, targetTaskAssigneeList); resolveOriginTask(commandContext, extAxHiTaskInstService, taskService, task); @@ -110,7 +110,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen break; default: // share_counterSign - shareCountSign(commandContext, (TaskEntity) task, taskDelegateAssigners); + shareCountSign(commandContext, task, taskDelegateAssigners); break; } @@ -127,11 +127,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private void shareCountSign(CommandContext commandContext, TaskEntity taskEntity, List taskDelegateAssigners) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); // 这个节点下所有审批人快照 String activityListSnapshot = - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(); taskDelegateAssigners.addAll(targetTaskAssigneeList); runtimeService.setVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, taskDelegateAssigners); log.info("正在进行加签任务:{},待加签人合并列表:{}", taskEntity.getId(), JSONUtil.toJsonStr(taskDelegateAssigners)); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 9dc1225a3..7d73db2b6 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -31,6 +31,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_N import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_DELETE_REASON; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask; @@ -101,7 +102,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser validTask(historicTaskInstance, task, approver, nodeTypes); - task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), REJECTED.getStatus()); + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), DELETED.getStatus()); Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), task.getTaskDefinitionKey(), advice, Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus(), diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index f83db2ff5..bed2cf0bd 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -76,15 +76,15 @@ public class TaskEntityEventHandle implements EntityEventHandle { @Override public void onActivated(TaskEntity taskEntity) { - log.error("onActivated"); + log.debug("onActivated"); } public void onSuspended(TaskEntity taskEntity) { - log.error("onSuspended"); + log.debug("onSuspended"); } public void onDeleted(TaskEntity taskEntity) { - log.error("onDeleted"); + log.debug("onDeleted"); ExtAxProcessLog queryLog = new ExtAxProcessLog(); queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); queryLog.setTaskId(taskEntity.getId()); @@ -93,7 +93,6 @@ public class TaskEntityEventHandle implements EntityEventHandle { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); -// BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(runtimeService.getVariable(taskEntity.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.toObjectCompatible(taskEntity.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + taskEntity.getId())); if (Objects.nonNull(assignee) && !Objects.equals(NO_ASSIGNEE, assignee.buildAssigneeId())) { update.setAssigneeFull(Lists.newArrayList(assignee)); @@ -125,7 +124,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); - if (StringUtils.hasText(completionType)) { + if (StringUtils.hasText(completionType) && !Objects.equals(DELETED.getStatus(), completionType)) { log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType); update.setStatus(completionType); } else { @@ -164,7 +163,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { } public void onUpdated(TaskEntity taskEntity) { - log.error("onUpdated"); + log.debug("onUpdated"); if (Objects.equals(HIDDEN_ASSIGNEE_ID, taskEntity.getAssignee())) { ExtAxProcessLog queryLog = new ExtAxProcessLog(); queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); @@ -187,7 +186,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { } public void onInitialized(TaskEntity taskEntity) { - log.error("onInitialized"); + log.debug("onInitialized"); BpmnMetaParserHelper.getButtonConfig(ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId()), taskEntity.getTaskDefinitionKey()) .ifPresent(buttons -> { ExtAxProcessLog queryLog = new ExtAxProcessLog(); @@ -201,7 +200,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { } public void onCreate(TaskEntity taskEntity) { - log.error("onCreate"); + log.debug("onCreate"); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); // 记录发起人 boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java index 9dfcba629..dbebfcaae 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java @@ -137,7 +137,7 @@ public class ErrorReportAspect implements Ordered { filterSendDingTalk = false; } - log.error("request header server name: {}", getHeader()); + log.warn("request header server name: {}", getHeader()); envConfig.type().executeAction(profile, operation.summary(), filterSendDingTalk, joinPoint.getArgs(), joinPoint.getSignature().toShortString(), e, workflowProperties.getFilterOperations().contains(operation.summary())); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 89be07059..17fecb552 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -69,8 +69,6 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @Resource private BpmnProcessTaskService bpmnProcessTaskService; - @Resource - private FlowSupportApi flowSupportApi; /** * 待审核列表 @@ -113,6 +111,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp tempAttachments.add(signature); dto.setAttachmentList(tempAttachments); } + populateUsersAvatar(dto.getApprover()); bpmnProcessTaskService.approveTask(dto); return success(true); } @@ -126,6 +125,8 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @RepeatSubmit public CommonResponse batchApproveTask(@Validated @RequestBody List dtos) { log.info("批量同意 approveTaskList===>>>参数:{}", JSON.toJSONString(dtos)); + List assigners = dtos.stream().map(BpmnTaskAuditDTO::getApprover).collect(Collectors.toList()); + populateUsersAvatar(assigners); return success(bpmnProcessTaskService.batchApproveTask(dtos)); } @@ -152,6 +153,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @Override public CommonResponse backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto) { log.info("回退 backTask===>>>参数:{}", JSON.toJSONString(dto)); + populateUsersAvatar(dto.getApprover()); bpmnProcessTaskService.backTask(dto); return success(true); } @@ -165,6 +167,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @RepeatSubmit public CommonResponse rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto) { log.info("驳回 rejectTask===>>>参数:{}", JSON.toJSONString(dto)); + populateUsersAvatar(dto.getApprover()); bpmnProcessTaskService.rejectTask(dto); return success(true); } @@ -178,6 +181,8 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @RepeatSubmit public CommonResponse batchRejectTask(@Validated @RequestBody List dtos) { log.info("批量驳回 batchRejectTask===>>>参数:{}", JSON.toJSONString(dtos)); + List assigners = dtos.stream().map(BpmnTaskAuditDTO::getApprover).collect(Collectors.toList()); + populateUsersAvatar(assigners); return success(bpmnProcessTaskService.batchRejectTask(dtos)); } @@ -202,6 +207,8 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @RepeatSubmit public CommonResponse batchTransferTask(@Validated @RequestBody List dtos) { log.info("批量转交任务 batchTransferTask===>>>参数:{}", JSON.toJSONString(dtos)); + List assigners = dtos.stream().map(BpmnTaskTransferDTO::getOriginAssigner).collect(Collectors.toList()); + populateUsersAvatar(assigners); return success(bpmnProcessTaskService.batchTransferTask(dtos)); } @@ -212,9 +219,10 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @PostMapping("/comment") @Override @RepeatSubmit - public CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO commentDTO) { - log.info("评论流程实例 commentTask===>>>参数:{}", commentDTO); - bpmnProcessTaskService.commentTask(commentDTO); + public CommonResponse commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto) { + log.info("评论流程实例 commentTask===>>>参数:{}", JSON.toJSONString(dto)); + populateUsersAvatar(dto.getOperator()); + bpmnProcessTaskService.commentTask(dto); return success(true); } @@ -226,11 +234,12 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @Override @PostMapping("/countersign") @RepeatSubmit - public CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) { - log.info("加签任务 countersignTask===>>>参数:{}", JSON.toJSONString(countersignDTO)); + public CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto) { + log.info("加签任务 countersignTask===>>>参数:{}", JSON.toJSONString(dto)); // 填充头像 - populateUsersAvatar(countersignDTO.getTargetAssignerList()); - bpmnProcessTaskService.countersignTask(countersignDTO); + populateUsersAvatar(dto.getOriginAssigner()); + populateUsersAvatar(dto.getTargetAssignerList()); + bpmnProcessTaskService.countersignTask(dto); return success(true); } From 0ddbaad2441ddff350233668adaccce4fe94c77e Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 19:03:19 +0800 Subject: [PATCH 069/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E9=92=89?= =?UTF-8?q?=E9=92=89=E6=8F=90=E7=A4=BA=E6=9F=A5=E8=AF=A2=E5=A0=86=E6=A0=88?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/workflow/server/common/util/DingTalkUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index 0233bfcea..a9d8f907d 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -64,7 +64,7 @@ public class DingTalkUtils { if (!StringUtils.hasText(jobId)) { return ""; } - return urlPrefix + "/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; + return urlPrefix + "/workflow-engine/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; } catch (Exception e) { return "构造查询错误堆栈地址异常:" + e.getMessage(); } From 801b2f0f5a17c1df8eb924b2e783b405286b1acf Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 12 Sep 2024 19:10:51 +0800 Subject: [PATCH 070/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E9=92=89?= =?UTF-8?q?=E9=92=89=E6=8F=90=E7=A4=BA=E6=9F=A5=E8=AF=A2=E5=A0=86=E6=A0=88?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/axzo/workflow/server/common/util/DingTalkUtils.java | 2 +- .../server/controller/web/bpmn/BpmnProcessJobController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index a9d8f907d..19a908903 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -48,7 +48,7 @@ public class DingTalkUtils { "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : throwable.getCause().getMessage()) + " \n\n" + "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + - "> ##### stackUrl: " + getDeadLetterStacktrace(profile, req) + " \n"); + "> ##### 查看异常明细: " + getDeadLetterStacktrace(profile, req) + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java index dd056d70a..5cf38b0f6 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessJobController.java @@ -61,6 +61,6 @@ public class BpmnProcessJobController implements ProcessJobApi { if (StringUtils.isBlank(jobId)) { return ""; } - return bpmnProcessJobService.getDeadLetterJobExceptionStacktrace(jobId); + return bpmnProcessJobService.getDeadLetterJobExceptionStacktraceByJobId(jobId); } } From 0c7c70eb43b2f691188ea18cfe6188ad0428cd7c Mon Sep 17 00:00:00 2001 From: wangli Date: Thu, 12 Sep 2024 21:04:22 +0800 Subject: [PATCH 071/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=97=A5=E5=BF=97=EF=BC=8C=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E4=B8=AD=E7=9A=84=E4=BA=BA=E5=90=8D=E5=92=8C?= =?UTF-8?q?=E5=A4=B4=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/bpmn/BpmnProcessInstanceController.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index 2b024a66e..ade90a7d7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -1,8 +1,6 @@ package cn.axzo.workflow.server.controller.web.bpmn; import cn.axzo.karma.client.feign.FlowSupportApi; -import cn.axzo.karma.client.model.request.PersonProfileQueryReq; -import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.oss.http.api.ServerFileServiceApi; import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest; import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse; @@ -58,7 +56,6 @@ import javax.validation.constraints.NotNull; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.stream.Collectors; import static cn.azxo.framework.common.model.CommonResponse.success; @@ -146,6 +143,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @RepeatSubmit public CommonResponse cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto) { log.info("撤回审核cancelProcessInstant===>>>参数:{}", JSONUtil.toJsonStr(dto)); + populateUsersAvatar(dto.getInitiator()); return success(bpmnProcessInstanceService.cancelProcessInstance(dto)); } @@ -192,6 +190,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @Override public CommonResponse carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto) { log.info("抄送流程实例carbonCopyProcessInstance===>>>参数:{}", JSONUtil.toJsonStr(dto)); + populateUsersAvatar(dto.getCopyAssigners()); return success(bpmnProcessInstanceService.carbonCopyProcessInstance(dto)); } From 73275141b4ab532c2839193e45e41535026b56b7 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 13 Sep 2024 11:39:17 +0800 Subject: [PATCH 072/139] =?UTF-8?q?REQ-2924-=E9=92=89=E9=92=89=E6=9E=84?= =?UTF-8?q?=E9=80=A0=E5=A0=86=E6=A0=88=E4=BF=A1=E6=81=AF=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=86=8D=E9=92=89=E9=92=89=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/server/common/util/DingTalkUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index 19a908903..a044031bf 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -7,6 +7,7 @@ import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiRobotSendRequest; import com.dingtalk.api.response.OapiRobotSendResponse; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; import org.springframework.util.StringUtils; @@ -22,6 +23,7 @@ import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; * @author wangli * @since 2024/1/12 14:34 */ +@Slf4j public class DingTalkUtils { private static final String dingtalk_robot_webhook = "https://oapi.dingtalk" + @@ -66,7 +68,8 @@ public class DingTalkUtils { } return urlPrefix + "/workflow-engine/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; } catch (Exception e) { - return "构造查询错误堆栈地址异常:" + e.getMessage(); + log.warn("构造查询错误堆栈地址异常", e); + return ""; } } From 336bfb47ffde20c8a1822ee3f8bcc88bcf20da69 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 13 Sep 2024 14:02:33 +0800 Subject: [PATCH 073/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E9=80=80?= =?UTF-8?q?=E5=9B=9E=E8=8A=82=E7=82=B9=E6=98=BE=E7=A4=BA=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/service/impl/BpmnProcessTaskServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 4d8666e0f..a7cce4657 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -418,7 +418,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(resultList)) { BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); - bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessActivityName() + "(上一级)"); + bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessActivityName() + "(上一步)"); } resultList.sort((o1, o2) -> o2.getOrdinal() - o1.getOrdinal()); return resultList; From 35b0fe5e40179714928ac65be77abfd0370bf5b0 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 13 Sep 2024 15:22:55 +0800 Subject: [PATCH 074/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E6=B7=BB=E5=8A=A0=E9=99=84=E4=BB=B6=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomCommentTaskCmd.java | 17 ++++++++--------- .../src/main/resources/sql/upgrade_to_1.4.2.sql | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java index 020348eb5..793db2453 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java @@ -112,15 +112,6 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria .filter(i -> Objects.equals(i.getId(), task.getId())).findAny() .ifPresent(i -> i.setAssignee(operator.buildAssigneeId())); - // 新增评论 - Authentication.setAuthenticatedUserId(operator.buildAssigneeId()); - addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); - addComment(commandContext, task, COMMENT_TYPE_COMMENT_EXT, JSONUtil.toJsonStr(commentExt)); - Authentication.setAuthenticatedUserId(null); - - // 处理附件 - batchAddAttachment(commandContext, processInstanceId, task.getId(), attachmentList, operator); - createExtTaskInst(extAxHiTaskInstService, processInstanceId, task.getId(), task.getTaskDefinitionKey(), operator, COMMENTED.getStatus()); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), COMMENTED.getStatus()); @@ -128,6 +119,14 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria // 保存临时节点 taskService.saveTask(task); + // 新增评论 + Authentication.setAuthenticatedUserId(operator.buildAssigneeId()); + addComment(commandContext, task, COMMENT_TYPE_ADVICE, comment); + addComment(commandContext, task, COMMENT_TYPE_COMMENT_EXT, JSONUtil.toJsonStr(commentExt)); + Authentication.setAuthenticatedUserId(null); + // 处理附件 + batchAddAttachment(commandContext, processInstanceId, task.getId(), attachmentList, operator); + // 设置快照信息 task.setTransientVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), operator.toJson()); diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index 4e31c7f9a..68126ece0 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -16,7 +16,7 @@ create table `workflow-engine`.ext_ax_process_log assignee_id bigint default 0 not null comment '审批人标识(axzo=personId)', assignee_tenant_id varchar(255) default '' not null comment '审批人归属租户', assignee_name varchar(255) default '' not null comment '审批人姓名', - assignee_ou_id bigint default 0 not null comment '审批人归属单位', + assignee_ou_id varchar(64) default '' not null comment '审批人归属单位', start_time datetime(3) default CURRENT_TIMESTAMP(3) not null comment '任务开始时间', end_time datetime(3) null comment '任务结束时间', button_conf json null comment '按钮配置', From 26e4c29e4122e48e67b5707ba86e1d273a50562d Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 13 Sep 2024 16:23:50 +0800 Subject: [PATCH 075/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=80=80=E5=9B=9E=E8=8A=82=E7=82=B9=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessTaskServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index a7cce4657..72ea20e13 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -365,7 +365,11 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { //流程为空,已经结束,返回空 throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); } - List hisList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + List hisList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .orderByHistoricActivityInstanceStartTime() + .asc() + .list(); List activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId); if (CollectionUtils.isEmpty(activeActivityIds)) { return Collections.emptyList(); From 41a9baebaf5c56f0ec8dc35c8608ca32b24494ae Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 13 Sep 2024 17:33:23 +0800 Subject: [PATCH 076/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E8=8A=82=E7=82=B9=E5=8D=A1=E4=BD=8F=E7=9A=84?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 1 + .../workflow/common/model/dto/AlterDTO.java | 25 ++++++ .../common/model/dto/TermNodePausingDTO.java | 5 +- .../core/conf/FlowableConfiguration.java | 5 +- .../core/conf/SupportRefreshProperties.java | 22 ++++-- .../job/AsyncTermNodeAlterJobHandler.java | 50 +++++++++--- .../entity/type/TaskEntityEventHandle.java | 2 +- .../cn/axzo/workflow/core/listener/Alter.java | 14 ++++ ...BpmnActivityEventListener_lo_Listener.java | 13 +++- .../workflow/server/alter/DingTalkAlter.java | 32 ++++++++ .../server/common/util/DingTalkUtils.java | 78 +++++++++++++++---- 11 files changed, 205 insertions(+), 42 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/Alter.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 91f4ab550..57a45a66d 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -40,6 +40,7 @@ public interface BpmnConstants { @Deprecated String OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT = "[_ASSIGNEE_INFO_SNAPSHOT_]"; String INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT = "[_ACTIVITY_INFO_SNAPSHOT_]"; + String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]"; String PROCESS_PREFIX = "Flowable"; @Deprecated String OLD_TASK_ASSIGNEE_SKIP_FLAT = "taskSkip"; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java new file mode 100644 index 000000000..e0408a44e --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/AlterDTO.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.Data; + +import java.util.Date; + +/** + * 告警对象 + * + * @author wangli + * @since 2024-09-13 11:37 + */ +@Data +public class AlterDTO { + private String processInstanceId; + + private String activityId; + + private String taskId; + + private Date startTime; + + private String prettyStartTime; + +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java index 345053959..6444bf20a 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/TermNodePausingDTO.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import java.io.Serializable; + /** * 卡住节点的查询条件模型 * @@ -17,8 +19,9 @@ import lombok.experimental.Accessors; @NoArgsConstructor @AllArgsConstructor @Builder -public class TermNodePausingDTO { +public class TermNodePausingDTO implements Serializable { + private static final long serialVersionUID = -1L; private String processInstanceId; private String activityId; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 0224420e7..b3276cf71 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -64,11 +64,10 @@ public class FlowableConfiguration { ObjectProvider listeners, CustomActivityBehaviorFactory customActivityBehaviorFactory, ExtAxHiTaskInstService extAxHiTaskInstService, - BpmnProcessActivityService bpmnProcessActivityService, List jobProcessors, NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties, - StringRedisTemplate redisTemplate) { + SupportRefreshProperties refreshProperties) { return configuration -> { configuration.setEnableHistoricTaskLogging(true); configuration.setHistoryLevel(HistoryLevel.AUDIT); @@ -94,7 +93,7 @@ public class FlowableConfiguration { configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); - configuration.addCustomJobHandler(new AsyncTermNodeAlterJobHandler()); + configuration.addCustomJobHandler(new AsyncTermNodeAlterJobHandler(refreshProperties)); // 异步任务异常重试时间间隔 configuration.setDefaultFailedJobWaitTime(30); configuration.setAsyncFailedJobWaitTime(30); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index d915b8e7b..f1b2586ea 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -1,10 +1,12 @@ package cn.axzo.workflow.core.conf; +import com.alibaba.nacos.api.config.annotation.NacosValue; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -39,23 +41,31 @@ public class SupportRefreshProperties { @Value("#{${workflow.assignee.map:{}}}") private Map assigneeMap; - @Value("${workflow.alter.enable:false}") - private Boolean alterEnable = false; + @Value(value = "${workflow.alter.enable:false}") + private Boolean alterEnable; /** - * 业务节点暂停告警的次数 + * 节点卡住多久才告警 */ - @Value("${workflow.alter.retries:3}") + @Value("${workflow.alter.delay:10}") + private Integer pauseDelay; + /** + * 业务节点暂停告警的次数,该值不建议改小 + */ + @Value(value = "${workflow.alter.retries:1000}") private Integer alterRetries; /** * 业务节点暂停告警次数间的间隔 */ - @Value("${workflow.alter.interval:10}") + @Value(value = "${workflow.alter.interval:10}") private Integer alterInterval; /** * 业务节点暂停告警次数间隔的时间单位 */ - @Value("${workflow.alter.intervalUnit:minutes}") + @Value(value = "${workflow.alter.intervalUnit:minutes}") private TimeUnit alterIntervalUnit; + + @Value(value = "${workflow.alter.mobiles}") + private List alterMobiles; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java index 330a70d4f..897d855e4 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncTermNodeAlterJobHandler.java @@ -1,18 +1,28 @@ package cn.axzo.workflow.core.engine.job; +import cn.axzo.workflow.common.model.dto.AlterDTO; import cn.axzo.workflow.common.model.dto.TermNodePausingDTO; +import cn.axzo.workflow.core.common.utils.SpringContextUtils; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; +import cn.axzo.workflow.core.listener.Alter; +import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; -import org.flowable.job.api.Job; import org.flowable.job.service.JobHandler; import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; import org.flowable.variable.api.delegate.VariableScope; import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_NODE_ALTER; + /** * 检查指定节点是否长时间卡住,如果卡住则进行钉钉告警 * @@ -22,6 +32,11 @@ import java.util.Objects; @Slf4j public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements JobHandler { public static final String TYPE = "term-node-alter-cycle"; + private final SupportRefreshProperties refreshProperties; + + public AsyncTermNodeAlterJobHandler(SupportRefreshProperties refreshProperties) { + this.refreshProperties = refreshProperties; + } @Override public String getType() { @@ -31,17 +46,32 @@ public class AsyncTermNodeAlterJobHandler extends AbstractJobHandler implements @Override public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { log.warn("AsyncActivityLeaveJobHandler exec start..."); - TermNodePausingDTO dto = JSON.parseObject(job.getCustomValues(), TermNodePausingDTO.class); ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); - Job timerJob = processEngineConfiguration.getManagementService() - .createTimerJobQuery().elementId(dto.getActivityId()) - .processInstanceId(dto.getProcessInstanceId()).singleResult(); - - if (Objects.isNull(timerJob) || Objects.equals(timerJob.getRetries(), dto.getRetries())) { + JSONObject jsonObject = JSON.parseObject(job.getJobHandlerConfiguration()); + if (!jsonObject.containsKey("activityId")) { return; } - - // 发送钉钉 - + String activityId = jsonObject.getString("activityId"); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + TermNodePausingDTO dto = runtimeService.getVariable(job.getProcessInstanceId(), BIZ_NODE_ALTER + activityId, TermNodePausingDTO.class); + TaskService taskService = processEngineConfiguration.getTaskService(); + Task task = taskService.createTaskQuery() + .processInstanceId(dto.getProcessInstanceId()) + .taskDefinitionKey(dto.getActivityId()) + .singleResult(); + if (Objects.isNull(task)) { + return; + } + if (DateUtil.compare(DateUtil.date(), DateUtil.offsetMinute(task.getCreateTime(), refreshProperties.getPauseDelay())) > 0) { + // 发送告警对象 + Alter alter = SpringContextUtils.getBean(Alter.class); + AlterDTO alterDTO = new AlterDTO(); + alterDTO.setProcessInstanceId(dto.getProcessInstanceId()); + alterDTO.setActivityId(dto.getActivityId()); + alterDTO.setTaskId(task.getId()); + alterDTO.setStartTime(task.getCreateTime()); + alterDTO.setPrettyStartTime(DateUtil.formatDateTime(task.getCreateTime())); + alter.invoke(alterDTO); + } } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java index bed2cf0bd..c3984bfa9 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java @@ -176,7 +176,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class); ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny() .ifPresent(assignee -> { - log.error("审批人: {}", JSON.toJSONString(assignee)); + log.debug("审批人: {}", JSON.toJSONString(assignee)); ExtAxProcessLog queryLog = new ExtAxProcessLog(); queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId()); queryLog.setTaskId(taskEntity.getId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/Alter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/Alter.java new file mode 100644 index 000000000..5ad691f57 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/Alter.java @@ -0,0 +1,14 @@ +package cn.axzo.workflow.core.listener; + +import cn.axzo.workflow.common.model.dto.AlterDTO; + +/** + * Core 往外转发的钩子 + * + * @author wangli + * @since 2024-09-13 11:33 + */ +public interface Alter { + + void invoke(AlterDTO alterDTO); +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java index ce56e3f16..fb136ee72 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java @@ -8,13 +8,13 @@ import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler; import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; import cn.axzo.workflow.core.listener.BpmnActivityEventListener; -import com.alibaba.fastjson.JSON; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.TimerEventDefinition; import org.flowable.engine.ManagementService; +import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.jobexecutor.TimerEventHandler; @@ -30,6 +30,8 @@ import org.springframework.stereotype.Component; import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_NODE_ALTER; + /** * Core 包内置的活动事件处理,可共用与 Jar 包集成和微服务集成 *

@@ -59,9 +61,13 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE */ @Override public void onStart(DelegateExecution execution) { - if(!Boolean.TRUE.equals(refreshProperties.getAlterEnable())) { + if (!Boolean.TRUE.equals(refreshProperties.getAlterEnable())) { return; } + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + TermNodePausingDTO dto = new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), refreshProperties.getAlterRetries()); + runtimeService.setVariable(execution.getProcessInstanceId(), BIZ_NODE_ALTER + execution.getCurrentActivityId(), dto); BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId()); FlowElement flowElement = bpmnModel.getFlowElement(execution.getCurrentActivityId()); BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(e -> { @@ -88,13 +94,12 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE timeUnit = "M"; break; } - timerEventDefinition.setTimeCycle("R" + refreshProperties.getAlterInterval() + "/PT" + refreshProperties.getAlterInterval() + timeUnit); + timerEventDefinition.setTimeCycle("R" + refreshProperties.getAlterRetries() + "/PT" + refreshProperties.getAlterInterval() + timeUnit); TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, execution.getCurrentFlowElement(), false, (ExecutionEntity) execution, AsyncTermNodeAlterJobHandler.TYPE, TimerEventHandler.createConfiguration(execution.getCurrentActivityId(), null, timerEventDefinition.getCalendarName())); if (timerJob != null) { - timerJob.setCustomValues(JSON.toJSONString(new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), refreshProperties.getAlterRetries()))); CommandContextUtil.getTimerJobService().scheduleTimerJob(timerJob); } break; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java new file mode 100644 index 000000000..bee558102 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.server.alter; + +import cn.axzo.workflow.common.model.dto.AlterDTO; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; +import cn.axzo.workflow.core.listener.Alter; +import cn.axzo.workflow.server.common.util.DingTalkUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 钉钉告警实现 + * + * @author wangli + * @since 2024-09-13 11:40 + */ +@Component +public class DingTalkAlter implements Alter { + + @Value("${spring.profiles.active}") + private String profile; + @Resource + private SupportRefreshProperties refreshProperties; + + @Override + public void invoke(AlterDTO alterDTO) { + DingTalkUtils.sendDingTalkForBizNodeAlter(profile, alterDTO, refreshProperties.getAlterMobiles()); + } + +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index a044031bf..a775b3af2 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.server.common.util; +import cn.axzo.workflow.common.model.dto.AlterDTO; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.dingtalk.api.DefaultDingTalkClient; @@ -9,9 +10,11 @@ import com.dingtalk.api.response.OapiRobotSendResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -27,16 +30,41 @@ import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; public class DingTalkUtils { private static final String dingtalk_robot_webhook = "https://oapi.dingtalk" + - ".com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; + ".com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; private static final Map ENV_URL_MAPPING = new HashMap<>(); + private static final Map WEB_URL_MAPPING = new HashMap<>(); static { + ENV_URL_MAPPING.put("local", "https://dev-app.axzo.cn"); ENV_URL_MAPPING.put("dev", "https://dev-app.axzo.cn"); ENV_URL_MAPPING.put("test", "https://test-api.axzo.cn"); ENV_URL_MAPPING.put("pre", "https://pre-api.axzo.cn"); ENV_URL_MAPPING.put("live", "https://live-api.axzo.cn"); ENV_URL_MAPPING.put("default", "https://api.axzo.cn"); + + WEB_URL_MAPPING.put("local", "https://dev-new-workflow-web.axzo.cn"); + WEB_URL_MAPPING.put("dev", "https://dev-new-workflow-web.axzo.cn"); + WEB_URL_MAPPING.put("test", "https://test-new-workflow-web.axzo.cn"); + WEB_URL_MAPPING.put("pre", "https://pre-new-workflow-web.axzo.cn"); + WEB_URL_MAPPING.put("live", "https://live-new-workflow-web.axzo.cn"); + WEB_URL_MAPPING.put("default", "https://new-workflow-web.axzo.cn"); + } + + public static String getEnvUrl(String profile) { + String urlPrefix = ENV_URL_MAPPING.get(profile); + if (!StringUtils.hasText(urlPrefix)) { + urlPrefix = ENV_URL_MAPPING.get("default"); + } + return urlPrefix; + } + + public static String getWebUrl(String profile) { + String urlPrefix = WEB_URL_MAPPING.get(profile); + if (!StringUtils.hasText(urlPrefix)) { + urlPrefix = WEB_URL_MAPPING.get("default"); + } + return urlPrefix; } @SneakyThrows @@ -46,32 +74,27 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice " + title + ", Env: " + profile); markdown.setText("#### [" + profile + "]" + title + "\n" + - "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + - "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : - throwable.getCause().getMessage()) + " \n\n" + - "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + - "> ##### 查看异常明细: " + getDeadLetterStacktrace(profile, req) + " \n"); + "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + + "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : + throwable.getCause().getMessage()) + " \n\n" + + "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + + "> ##### [点击查看异常明细](" + getDeadLetterStacktrace(profile, req) + ") \n"); request.setMarkdown(markdown); sendDingTalk(request); } private static String getDeadLetterStacktrace(String profile, Object req) { try { - String urlPrefix = ENV_URL_MAPPING.get(profile); - if (!StringUtils.hasText(urlPrefix)) { - urlPrefix = ENV_URL_MAPPING.get("default"); - } JSONObject entries = JSONUtil.parseObj(req); String jobId = entries.getStr("id"); if (!StringUtils.hasText(jobId)) { return ""; } - return urlPrefix + "/workflow-engine/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; + return getEnvUrl(profile) + "/workflow-engine/web/v1/api/process/job/dead-letter/exception/stacktrace/byId?jobId=" + jobId; } catch (Exception e) { log.warn("构造查询错误堆栈地址异常", e); return ""; } - } @SneakyThrows @@ -81,9 +104,9 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice 请求二方接口慢 URL, Env: " + profile); markdown.setText("#### [" + profile + "]请求二方接口过慢\n" + - "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + - "> 请求参数: " + JSONUtil.toJsonStr(requestParam) + "\n\n" + - "> ###### 结果: " + JSONUtil.toJsonStr(responseBody) + " \n"); + "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + + "> 请求参数: " + JSONUtil.toJsonStr(requestParam) + "\n\n" + + "> ###### 结果: " + JSONUtil.toJsonStr(responseBody) + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } @@ -95,8 +118,8 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice API 处理耗时报告, Env: " + profile); markdown.setText("#### [" + profile + "]API 处理耗时报告\n" + - "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + - "> ###### 标识: " + uniqueId + " \n"); + "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + + "> ###### 标识: " + uniqueId + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } @@ -106,4 +129,25 @@ public class DingTalkUtils { DingTalkClient client = new DefaultDingTalkClient(dingtalk_robot_webhook); OapiRobotSendResponse response = client.execute(request); } + + public static void sendDingTalkForBizNodeAlter(String profile, AlterDTO alterDTO, List atMobiles) { + if (CollectionUtils.isEmpty(atMobiles)) { + return; + } + String processInstanceId = alterDTO.getProcessInstanceId(); + OapiRobotSendRequest request = new OapiRobotSendRequest(); + request.setMsgtype("markdown"); + OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); + markdown.setTitle("Notice 业务节点长时间停止告警, Env: " + profile); + markdown.setText("#### [" + profile + "]业务节点长时间停止\n" + + "> 节点相关信息: " + JSONUtil.toJsonStr(alterDTO) + "\n\n" + + "> ##### [点击查看审批日志](" + getWebUrl(profile) + "/#/workflow/examples?processInstanceId=" + processInstanceId + ") \n\n" + + "> ##### 提示:如果以上地址提示未登录,请在对应环境 OMS 系统登录后并点击审批管理的功能后,再使用。或者复制实例 ID 到 OMS 中手动查询"); + request.setMarkdown(markdown); + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setAtMobiles(atMobiles); + at.setIsAtAll(false); + request.setAt(at); + sendDingTalk(request); + } } From 3e1b7a271be8fef142185e13a7315615de5b88a7 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 13 Sep 2024 18:54:14 +0800 Subject: [PATCH 077/139] =?UTF-8?q?fix=20-=20=E8=A7=A3=E5=86=B3=20nacos=20?= =?UTF-8?q?=E6=9C=AA=E9=85=8D=E7=BD=AE=E5=AF=BC=E8=87=B4=E7=9A=84=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/core/conf/SupportRefreshProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index f1b2586ea..1074a85c5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -66,6 +66,6 @@ public class SupportRefreshProperties { @Value(value = "${workflow.alter.intervalUnit:minutes}") private TimeUnit alterIntervalUnit; - @Value(value = "${workflow.alter.mobiles}") + @Value(value = "${workflow.alter.mobiles:}") private List alterMobiles; } From e3902f9da44ee7c25e46bb5013c044a3e5cc1d3c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 13 Sep 2024 19:12:56 +0800 Subject: [PATCH 078/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=9C=AA=E6=9D=A5=E8=8A=82=E7=82=B9=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/BpmnProcessInstanceServiceImpl.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index ba5fc3137..fb615d697 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1238,14 +1238,41 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic private static void getFutureTasks(List forecasting, List tasks) { ListUtils.emptyIfNull(forecasting).forEach(e -> { - tasks.add(BpmnTaskInstanceLogVO.builder() + BpmnTaskInstanceLogVO build = BpmnTaskInstanceLogVO.builder() .taskDefinitionKey(e.getId()) .name(e.getName()) .approvalMethod(e.getApprovalMethod()) .nodeType(e.getNodeType()) .nodeMode(e.getNodeMode()) .forecastAssignees(e.getForecastAssigners()) - .build()); + .build(); + if (Objects.nonNull(e.getApprovalMethod())) { + switch (e.getApprovalMethod()) { + case bizSpecify: + case nobody: + build.setOperationDesc("待处理"); + break; + case autoPassed: + case autoRejection: + break; + case human: + if (Objects.equals(e.getNodeMode(), EXCEPTIONAL)) { + build.setOperationDesc("节点异常"); + } else { + int countPerson = e.getForecastAssigners().size(); + if (Objects.equals(BpmnFlowNodeMode.AND, e.getNodeMode())) { + build.setOperationDesc(countPerson + "人会签,需要全部同意"); + } else if (Objects.equals(BpmnFlowNodeMode.OR, e.getNodeMode())) { + build.setOperationDesc(countPerson + "人或签,仅一人同意即可"); + } + } + break; + } + } + if (Objects.equals(e.getNodeType(), NODE_CARBON_COPY)) { + build.setOperationDesc("抄送" + e.getForecastAssigners().size() + "人"); + } + tasks.add(build); }); } From 102d73e663769d42a3374549369328cfd0ea6cf7 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 13 Sep 2024 19:34:16 +0800 Subject: [PATCH 079/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E8=8A=82=E7=82=B9=E6=8C=89=E9=92=AE=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index fb615d697..e3864d038 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1305,6 +1305,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } i.setAssigneeSnapshot(null); i.setForecastAssignees(assigners); + i.setButtonConf(e.getButtonConf()); // 根据当前登录人重设聚合后的节点 taskId assigners.stream().filter(user-> Objects.equals(user.getPersonId(), visitor.getPersonId())).findFirst() .ifPresent(user-> i.setTaskId(e.getTaskId())); @@ -1323,6 +1324,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic .operationDesc(e.getOperationDesc()) .advice(e.getAdvice()) .commentExt("") + .buttonConf(e.getButtonConf()) .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) From c4c2114db8f2aa48b4bddb1e00f0e6b2c5467d27 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 13 Sep 2024 23:15:28 +0800 Subject: [PATCH 080/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?eventproducer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/feign/ext/ComplexInvokeClient.java | 14 +++++++++----- .../WorkflowEngineStarterFeignConfiguration.java | 8 +++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 2e3f733a6..2f290bf81 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -15,6 +15,7 @@ import feign.Response; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.http.HttpStatus; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; @@ -42,7 +43,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -64,11 +64,11 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; - private final Optional optEventProducer; + private final ObjectProvider optEventProducer; private final Client feignClient; public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, - Optional optEventProducer, + ObjectProvider optEventProducer, Client feignClient) { this.starterProperties = starterProperties; this.optEventProducer = optEventProducer; //(RpcInvokeEventProducer) eventProducer; @@ -93,10 +93,14 @@ public class ComplexInvokeClient implements Client { * @param options */ private Response asyncInvoke(Request request, Request.Options options) throws IOException { - if (!optEventProducer.isPresent()) { + EventProducer ifAvailable = optEventProducer.getIfAvailable(() -> null); + if (ifAvailable == null) { return feignClient.execute(request, options); } - optEventProducer.ifPresent(eventProducer -> { +// if (!optEventProducer.isPresent()) { +// return feignClient.execute(request, options); +// } + optEventProducer.ifAvailable(eventProducer -> { WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); MethodMetadata metadata = request.requestTemplate().methodMetadata(); event.setClassName(metadata.targetType().getName()); diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 5d610f981..4c0aab4f5 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -15,7 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; @@ -30,9 +30,7 @@ import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Collections; import java.util.Objects; -import java.util.Optional; -//import static cn.axzo.framework.web.filter.BasicRecordExceptionFilter.MICRO_SERVER_RECORD_ERROR_GET_PARAM_NAME; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE; @@ -57,9 +55,9 @@ public class WorkflowEngineStarterFeignConfiguration { @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, - @Qualifier("workflowEngineStarterEventProducer") EventProducer eventProducer, + ObjectProvider producerObjectProvider, Client feignClient) { - return new ComplexInvokeClient(starterProperties, Optional.ofNullable(eventProducer), feignClient); + return new ComplexInvokeClient(starterProperties, producerObjectProvider, feignClient); } @Bean From dbfc0607913c616b9034425a06714ad89b209950 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 13 Sep 2024 23:21:23 +0800 Subject: [PATCH 081/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?eventproducer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/feign/ext/ComplexInvokeClient.java | 16 +++++++--------- .../WorkflowEngineStarterFeignConfiguration.java | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 2f290bf81..ea262e8de 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.starter.feign.ext; -import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; @@ -43,6 +42,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -64,11 +64,11 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; - private final ObjectProvider optEventProducer; + private final ObjectProvider optEventProducer; private final Client feignClient; public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, - ObjectProvider optEventProducer, + ObjectProvider optEventProducer, Client feignClient) { this.starterProperties = starterProperties; this.optEventProducer = optEventProducer; //(RpcInvokeEventProducer) eventProducer; @@ -93,13 +93,10 @@ public class ComplexInvokeClient implements Client { * @param options */ private Response asyncInvoke(Request request, Request.Options options) throws IOException { - EventProducer ifAvailable = optEventProducer.getIfAvailable(() -> null); - if (ifAvailable == null) { + Optional opt = Optional.ofNullable(optEventProducer.getIfAvailable()); + if (!opt.isPresent()) { return feignClient.execute(request, options); } -// if (!optEventProducer.isPresent()) { -// return feignClient.execute(request, options); -// } optEventProducer.ifAvailable(eventProducer -> { WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); MethodMetadata metadata = request.requestTemplate().methodMetadata(); @@ -110,8 +107,9 @@ public class ComplexInvokeClient implements Client { event.setParameters(args); buildArgs(request, metadata, args); log.debug("[async-invoke] sourceEvent: {}", JSON.toJSONString(event)); - ((RpcInvokeEventProducer) eventProducer).send(WORKFLOW_ENGINE_STARTER, event); + eventProducer.send(WORKFLOW_ENGINE_STARTER, event); }); + Map> headers = request.headers(); headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); return Response.builder() diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 4c0aab4f5..d411c6875 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -1,9 +1,9 @@ package cn.axzo.workflow.starter.feign.ext; -import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; +import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.azxo.framework.common.constatns.Constants; import feign.Client; import feign.RequestInterceptor; @@ -55,7 +55,7 @@ public class WorkflowEngineStarterFeignConfiguration { @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, - ObjectProvider producerObjectProvider, + ObjectProvider producerObjectProvider, Client feignClient) { return new ComplexInvokeClient(starterProperties, producerObjectProvider, feignClient); } From 80af410408e7749afa55ac20d2ef7505c867d428 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 13 Sep 2024 23:36:33 +0800 Subject: [PATCH 082/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=20starter=20=E7=9A=84=20Bean=20=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 5b9b39094..a7477efae 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -139,6 +139,7 @@ public class StarterRPCInvokeMQConfiguration { } @Bean(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { @@ -150,6 +151,7 @@ public class StarterRPCInvokeMQConfiguration { } @Bean(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) public EventConsumer workflowEngineStarterEventConsumer(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository workflowEngineStarterEventHandlerRepository) { Consumer callback = eventWrapper -> { From d4e4f4a45e04d8f44f8be9ae23f18377cf3c4e68 Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 13 Sep 2024 23:48:34 +0800 Subject: [PATCH 083/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=20starter=20=E7=9A=84=20Bean=20=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index a7477efae..6d07b7712 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -165,6 +165,7 @@ public class StarterRPCInvokeMQConfiguration { } @Component + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", @@ -199,6 +200,7 @@ public class StarterRPCInvokeMQConfiguration { } @Bean("workflowEngineClientRetryEventListener") + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) EventConsumer workflowEngineStarterEventConsumer, Environment environment, WorkflowEngineStarterProperties starterProperties, From 2bff396e6b3fff7f4e23e93caaddc616bb6b15fd Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 13 Sep 2024 23:49:27 +0800 Subject: [PATCH 084/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=20starter=20=E7=9A=84=20Bean=20=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/starter/StarterBroadcastMQConfiguration.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 7a1848191..9275beece 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -57,6 +57,7 @@ public class StarterBroadcastMQConfiguration { //================================= Workflow Engine Broadcast MQ =================================// @Bean(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository broadcastEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { @@ -69,6 +70,7 @@ public class StarterBroadcastMQConfiguration { } @Bean(BROADCAST_EVENT_CONSUMER_BEAN_NAME) + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = BROADCAST_EVENT_CONSUMER_BEAN_NAME) public EventConsumer broadcastEventConsumer(@Qualifier(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository eventHandlerRepository) { Consumer callback = eventWrapper -> { @@ -84,6 +86,7 @@ public class StarterBroadcastMQConfiguration { } @Component + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", @@ -125,6 +128,7 @@ public class StarterBroadcastMQConfiguration { } @Bean("workflowEngineBroadcastEventListener") + @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier(BROADCAST_EVENT_CONSUMER_BEAN_NAME) EventConsumer broadcastEventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List listenerProvider) { From d6e837df53cf68190007fa4c53fee1b89e94674a Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Sat, 14 Sep 2024 10:42:36 +0800 Subject: [PATCH 085/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=80=80=E5=9B=9E=E8=8A=82=E7=82=B9=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/BpmnProcessTaskServiceImpl.java | 83 ++++++++++--------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 72ea20e13..a21ed2b76 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.core.service.impl; +import cn.axzo.framework.domain.ServiceException; import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; @@ -55,12 +57,10 @@ import cn.hutool.core.collection.CollUtil; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; import org.flowable.bpmn.model.BaseElement; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.SequenceFlow; -import org.flowable.bpmn.model.ServiceTask; -import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandExecutor; @@ -69,7 +69,6 @@ import org.flowable.engine.ManagementService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; -import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; @@ -101,6 +100,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -365,45 +365,54 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { //流程为空,已经结束,返回空 throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); } - List hisList = historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .orderByHistoricActivityInstanceStartTime() - .asc() - .list(); - List activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId); - if (CollectionUtils.isEmpty(activeActivityIds)) { - return Collections.emptyList(); + List tasks = this.getHistoricTaskListByProcessInstanceId(processInstanceId, null); + tasks.sort(Comparator.comparing(BpmnHistoricTaskInstanceVO::getCreateTime)); + LinkedList>> executedList = new LinkedList<>(); + for (BpmnHistoricTaskInstanceVO vo : tasks) { + Pair> last = org.springframework.util.CollectionUtils.isEmpty(executedList) ? null : executedList.getLast(); + if (last != null && last.getLeft().equals(vo.getTaskDefinitionKey())) { + last.getRight().add(vo); + continue; + } + ArrayList objects = new ArrayList<>(); + objects.add(vo); + executedList.addLast(Pair.of(vo.getTaskDefinitionKey(), objects)); } - List flowElements = bpmnProcessModelService.findFlowElements(task.getProcessDefinitionId()); - if (CollectionUtils.isEmpty(flowElements)) { - return Collections.emptyList(); - } - //考虑会签 - Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); - List executePath = new ArrayList<>(); - for (HistoricActivityInstance his : hisList) { - FlowElement flowElement = flowElementMap.get(his.getActivityId()); - if (flowElement != null) { - FlowElement previousNode = CollectionUtils.isEmpty(executePath) ? null : executePath.get(executePath.size() - 1); - //上一级直接连接,不是同一个节点,表示跳转过去的, - if (previousNode != null && !his.getActivityId().equals(previousNode.getId()) && (previousNode instanceof UserTask || previousNode instanceof ServiceTask) && !(flowElement instanceof SequenceFlow)) { - int i = executePath.size() - 1; - for (; i >= 0; i--) { - if (executePath.get(i).getId().equals(flowElement.getId())) { - break; - } + List>> valuableList = new LinkedList<>(); + for (Pair> pair : executedList) { + List taskInstanceVOList = pair.getRight(); + Optional backTaskOpt = taskInstanceVOList + .stream() + .filter(t -> t.getResult() != null) + .filter(t -> t.getResult() == BpmnProcessInstanceResultEnum.BACKED) + .findFirst(); + if (backTaskOpt.isPresent()) { + String deleteReason = backTaskOpt.get().getDeleteReason(); + String changeParentActivityTo = deleteReason + .replace("Change parent activity to ", "") + .replace("Change activity to ", ""); + if (org.springframework.util.CollectionUtils.isEmpty(valuableList)) { + throw new ServiceException("状态异常,首个节点进行了退回操作"); + } + int j = valuableList.size() - 1; + for (; j >= 0; j--) { + Pair> vPair = valuableList.get(j); + if (vPair.getLeft().equals(changeParentActivityTo)) { + break; } - //去掉跳过的路径 - executePath = executePath.subList(0, i); - } - if (previousNode == null || !previousNode.getId().equals(his.getActivityId())) { - executePath.add(flowElement); } + valuableList = valuableList.subList(0, j); + } else { + valuableList.add(pair); } } + List flowElements = bpmnProcessModelService.findFlowElements(processInstance.getProcessDefinitionId()); + Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); AtomicInteger index = new AtomicInteger(0); - List resultList = executePath.stream() - .filter(flowElement -> !activeActivityIds.contains(flowElement.getId())) //排除当前节点 + List resultList = valuableList + .stream() + .filter(pair -> !task.getTaskDefinitionKey().equals(pair.getLeft())) //排除当前节点 + .map(pair -> flowElementMap.get(pair.getLeft())) .filter(flowElement -> { BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; From fc36c31bfd2ac503b7e95a73ff67debeca679568 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Sat, 14 Sep 2024 10:53:45 +0800 Subject: [PATCH 086/139] =?UTF-8?q?REQ-2924-=E9=80=80=E5=9B=9E=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8F=90=E4=BA=A4=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/bpmn/BpmnProcessTaskController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java index 17fecb552..a19b53079 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java @@ -138,7 +138,6 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp @Operation(summary = "获取当前节点可回退节点选项列表") @GetMapping("/back/optional/nodes") @Override - @RepeatSubmit public CommonResponse> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId) { List approveOptionalNodes = bpmnProcessTaskService.getBackOptionalNodes(taskId); return success(approveOptionalNodes); From 748e8b1906315503cda6d39be0013494f43fccfa Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 12:15:57 +0800 Subject: [PATCH 087/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20Starter=20=E4=B8=AD=E7=9A=84=20Bean=20=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessJobApi.java | 2 + .../StarterBroadcastMQConfiguration.java | 10 ++--- .../StarterRPCInvokeMQConfiguration.java | 11 +++-- ...orkflowEngineStarterAutoConfiguration.java | 6 ++- .../starter/api/WorkflowCoreService.java | 18 +++++++- .../starter/api/WorkflowManageService.java | 2 +- .../feign/ext/ComplexInvokeClient.java | 44 +++++++++---------- ...rkflowEngineStarterFeignConfiguration.java | 5 ++- ...orkflowEngineStarterInvocationHandler.java | 2 +- 9 files changed, 61 insertions(+), 39 deletions(-) diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java index 732913fdd..5e6da7692 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessJobApi.java @@ -31,6 +31,7 @@ public interface ProcessJobApi { * @return */ @GetMapping("/dead-letter/exception/stacktrace") + @Manageable String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); /** @@ -39,5 +40,6 @@ public interface ProcessJobApi { * @return */ @GetMapping("/dead-letter/exception/stacktrace/byId") + @Manageable String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId); } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 9275beece..27d4868bb 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -19,12 +19,14 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; +import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -37,6 +39,7 @@ import java.util.List; import java.util.function.Consumer; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; +import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration.ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME; /** * 配置监听流程引擎服务广播消息的 RocketMQ 相关配置 @@ -45,7 +48,7 @@ import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_E * @since 2024/6/5 17:39 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(prefix = "rocketmq", value = "name-server") +@ConditionalOnBean(name = ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME) public class StarterBroadcastMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterBroadcastMQConfiguration.class); public static final String BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME = "broadcastEventHandlerRepository"; @@ -57,7 +60,6 @@ public class StarterBroadcastMQConfiguration { //================================= Workflow Engine Broadcast MQ =================================// @Bean(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository broadcastEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { @@ -70,7 +72,6 @@ public class StarterBroadcastMQConfiguration { } @Bean(BROADCAST_EVENT_CONSUMER_BEAN_NAME) - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = BROADCAST_EVENT_CONSUMER_BEAN_NAME) public EventConsumer broadcastEventConsumer(@Qualifier(BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository eventHandlerRepository) { Consumer callback = eventWrapper -> { @@ -86,7 +87,7 @@ public class StarterBroadcastMQConfiguration { } @Component - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") + @ConditionalOnBean(RocketMQTemplate.class) @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", @@ -128,7 +129,6 @@ public class StarterBroadcastMQConfiguration { } @Bean("workflowEngineBroadcastEventListener") - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public WorkflowEngineBroadcastEventListener workflowEngineBroadcastEventListener(@Qualifier(BROADCAST_EVENT_CONSUMER_BEAN_NAME) EventConsumer broadcastEventConsumer, WorkflowEngineStarterProperties workflowEngineStarterProperties, List listenerProvider) { diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 6d07b7712..25e15d6d8 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -42,6 +43,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; +import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration.ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME; /** * 配置 RPC 动作的 RocketMQ 消息的发送方和消息方等配置信息 @@ -50,7 +52,7 @@ import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(prefix = "rocketmq", value = "name-server") +@ConditionalOnBean(name = ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME) public class StarterRPCInvokeMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterRPCInvokeMQConfiguration.class); public static final String WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME = "workflowEngineStarterEventProducer"; @@ -74,7 +76,7 @@ public class StarterRPCInvokeMQConfiguration { * @return */ @Bean(WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME) - public EventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { + public RpcInvokeEventProducer workflowEngineStarterEventProducer(RocketMQTemplate rocketMQTemplate) { return new RpcInvokeEventProducer(rocketMQTemplate, DEFAULT_MODULE, applicationName + MODULE_NAME_SUFFIX, @@ -139,7 +141,6 @@ public class StarterRPCInvokeMQConfiguration { } @Bean(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) public EventHandlerRepository workflowEngineStarterEventHandlerRepository() { return new EventHandlerRepository((ex, logText) -> { @@ -151,7 +152,6 @@ public class StarterRPCInvokeMQConfiguration { } @Bean(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") @ConditionalOnMissingBean(name = WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) public EventConsumer workflowEngineStarterEventConsumer(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_HANDLER_REPOSITORY_BEAN_NAME) EventHandlerRepository workflowEngineStarterEventHandlerRepository) { Consumer callback = eventWrapper -> { @@ -165,7 +165,7 @@ public class StarterRPCInvokeMQConfiguration { } @Component - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") + @ConditionalOnBean(RocketMQTemplate.class) @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", @@ -200,7 +200,6 @@ public class StarterRPCInvokeMQConfiguration { } @Bean("workflowEngineClientRetryEventListener") - @ConditionalOnProperty(prefix = "rocketmq", value = "name-server") public WorkflowEngineStarterRetryEventListener workflowEngineClientRetryEventListener(@Qualifier(WORKFLOW_ENGINE_STARTER_EVENT_CONSUMER_BEAN_NAME) EventConsumer workflowEngineStarterEventConsumer, Environment environment, WorkflowEngineStarterProperties starterProperties, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 01a19b309..cf4ba4f3d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -30,10 +30,12 @@ import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -52,7 +54,7 @@ import java.util.List; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WorkflowEngineStarterProperties.class) -@Import({StarterFeignClientConfiguration.class, MetaFeignClientEnableSelector.class}) +@Import({StarterFeignClientConfiguration.class, MetaFeignClientEnableSelector.class, StarterRPCInvokeMQConfiguration.class, StarterBroadcastMQConfiguration.class}) public class WorkflowEngineStarterAutoConfiguration { private final Logger log = LoggerFactory.getLogger(WorkflowEngineStarterAutoConfiguration.class); @@ -116,6 +118,7 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean(destroyMethod = "shutdown", name = "defaultMQAdminExt") + @ConditionalOnBean(RocketMQTemplate.class) @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true", matchIfMissing = true) public DefaultMQAdminExt defaultMQAdminExt(Environment environment) { String namesrvAddress = environment.getProperty("rocketmq.name-server"); @@ -140,6 +143,7 @@ public class WorkflowEngineStarterAutoConfiguration { } @Bean + @ConditionalOnBean(RocketMQTemplate.class) @ConditionalOnProperty(prefix = "workflow.engine.starter", value = "enable-dlq-monitor", havingValue = "true", matchIfMissing = true) public WorkflowEngineStarterDefaultMQMonitor workflowEngineStarterDefaultMQMonitor(ObjectProvider mqAdminExtObjectProvider, ObjectProvider broadcastDLQProcessorObjectProvider, diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index 6ca079346..b3aacf712 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -66,7 +66,7 @@ import javax.validation.constraints.NotEmpty; *

* Auto generation by workflow engine, It cannot be manually modified */ -@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowCoreService { /** @@ -198,6 +198,22 @@ public interface WorkflowCoreService { @InvokeMode(SYNC) BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); + /** + * 查询死信消息数据 + * @param procInstId 流程实例id + * @return + */ + @GetMapping("/dead-letter/exception/stacktrace") + String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); + + /** + * 查询死信消息数据 + * @param jobId 死信job的id + * @return + */ + @GetMapping("/dead-letter/exception/stacktrace/byId") + String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId); + /** * 同意 * diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index 3424cc527..f06c18b58 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -86,7 +86,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinition *

* Auto generation by workflow engine, It cannot be manually modified */ -@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine.starter:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) +@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-manage", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class) public interface WorkflowManageService { /** diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index ea262e8de..96b624360 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.starter.feign.ext; +import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; @@ -14,7 +15,7 @@ import feign.Response; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.BeanFactory; import org.springframework.http.HttpStatus; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.DeleteMapping; @@ -42,7 +43,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Queue; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -50,6 +50,7 @@ import java.util.regex.Pattern; import static cn.axzo.workflow.common.constant.StarterConstants.STARTER_INVOKE_MODE; import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC; import static cn.axzo.workflow.common.enums.WorkflowEngineEventEnum.WORKFLOW_ENGINE_STARTER; +import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME; import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -64,14 +65,14 @@ public class ComplexInvokeClient implements Client { private final Logger log = LoggerFactory.getLogger(ComplexInvokeClient.class); private final WorkflowEngineStarterProperties starterProperties; - private final ObjectProvider optEventProducer; + private final BeanFactory beanFactory; private final Client feignClient; public ComplexInvokeClient(WorkflowEngineStarterProperties starterProperties, - ObjectProvider optEventProducer, + BeanFactory beanFactory, Client feignClient) { this.starterProperties = starterProperties; - this.optEventProducer = optEventProducer; //(RpcInvokeEventProducer) eventProducer; + this.beanFactory = beanFactory; //(RpcInvokeEventProducer) eventProducer; this.feignClient = feignClient; } @@ -93,11 +94,9 @@ public class ComplexInvokeClient implements Client { * @param options */ private Response asyncInvoke(Request request, Request.Options options) throws IOException { - Optional opt = Optional.ofNullable(optEventProducer.getIfAvailable()); - if (!opt.isPresent()) { - return feignClient.execute(request, options); - } - optEventProducer.ifAvailable(eventProducer -> { + RpcInvokeEventProducer producer = null; + try { + producer = beanFactory.getBean(WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME, RpcInvokeEventProducer.class); WorkflowEngineStarterRpcInvokeDTO event = new WorkflowEngineStarterRpcInvokeDTO(); MethodMetadata metadata = request.requestTemplate().methodMetadata(); event.setClassName(metadata.targetType().getName()); @@ -107,18 +106,19 @@ public class ComplexInvokeClient implements Client { event.setParameters(args); buildArgs(request, metadata, args); log.debug("[async-invoke] sourceEvent: {}", JSON.toJSONString(event)); - eventProducer.send(WORKFLOW_ENGINE_STARTER, event); - }); - - Map> headers = request.headers(); - headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); - return Response.builder() - .status(HttpStatus.OK.value()) - .reason(HttpStatus.OK.getReasonPhrase()) - .headers(headers) - .request(request) - .body(body) - .build(); + producer.send(WORKFLOW_ENGINE_STARTER, event); + Map> headers = request.headers(); + headers.forEach((k, v) -> log.debug("ComplexInvokeClient Header: {} = {}", k, v)); + return Response.builder() + .status(HttpStatus.OK.value()) + .reason(HttpStatus.OK.getReasonPhrase()) + .headers(headers) + .request(request) + .body(body) + .build(); + } catch (Exception e) { + return feignClient.execute(request, options); + } } @SneakyThrows diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index d411c6875..278aa331d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -14,6 +14,7 @@ import feign.codec.Decoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -55,9 +56,9 @@ public class WorkflowEngineStarterFeignConfiguration { @Bean public Client complexInvokeClient(WorkflowEngineStarterProperties starterProperties, - ObjectProvider producerObjectProvider, + BeanFactory beanFactory, Client feignClient) { - return new ComplexInvokeClient(starterProperties, producerObjectProvider, feignClient); + return new ComplexInvokeClient(starterProperties, beanFactory, feignClient); } @Bean diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java index a3c4ba593..3f20ac432 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterInvocationHandler.java @@ -70,7 +70,7 @@ class WorkflowEngineStarterInvocationHandler implements InvocationHandler { private void parseInvokeModelAnnotation(Method method) { InvokeMode annotation = AnnotationUtils.getAnnotation(method, InvokeMode.class); - if (Objects.nonNull(annotation)) { + if (Objects.nonNull(annotation) && Objects.isNull(ThreadUtil.get())) { ThreadUtil.set(annotation.value()); } } From 4ab77e7a4fb28eb918bf2da842b63d5dd726d543 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 12:49:17 +0800 Subject: [PATCH 088/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E7=9A=84=E7=9B=AE=E6=A0=87=E8=8A=82=E7=82=B9?= =?UTF-8?q?=EF=BC=8C=E6=9C=89=E8=BD=AC=E4=BA=A4=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=EF=BC=8C=E6=97=A5=E5=BF=97=E5=B1=95=E7=A4=BA=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/engine/cmd/CustomBackTaskCmd.java | 13 ++++++++----- .../workflow/server/common/util/DingTalkUtils.java | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index a3d113c81..ddc787e8b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -27,6 +27,7 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; @@ -65,9 +66,9 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ @Override public Void execute(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService(); HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); @@ -95,10 +96,12 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); + // 移除回退到的指定节点的变量,让 EngineExecutionStartListener 重新计算该节点的人 + runtimeService.removeVariable(task.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + dto.getToActivityId()); runtimeService.createChangeActivityStateBuilder() - .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) - .changeState(); + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) + .changeState(); return null; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index a775b3af2..0af16217a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -148,6 +148,6 @@ public class DingTalkUtils { at.setAtMobiles(atMobiles); at.setIsAtAll(false); request.setAt(at); - sendDingTalk(request); +// sendDingTalk(request); } } From 9606589bab877a02349e77ad613073e115a26627 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 13:06:03 +0800 Subject: [PATCH 089/139] =?UTF-8?q?feat(REQ-2924)=20-=20Starter=20?= =?UTF-8?q?=E9=80=82=E9=85=8D=E6=97=A0=E9=9C=80=E4=BD=BF=E7=94=A8=20MQ=20?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterBroadcastMQConfiguration.java | 4 ++-- .../StarterRPCInvokeMQConfiguration.java | 4 ++-- .../starter/api/WorkflowCoreService.java | 16 ---------------- .../starter/api/WorkflowManageService.java | 18 ++++++++++++++++++ 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index 27d4868bb..bb1d862c7 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -48,7 +48,7 @@ import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration * @since 2024/6/5 17:39 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnBean(name = ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME) +@ConditionalOnProperty(name = "rocketmq.name-server") public class StarterBroadcastMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterBroadcastMQConfiguration.class); public static final String BROADCAST_EVENT_HANDLER_REPOSITORY_BEAN_NAME = "broadcastEventHandlerRepository"; @@ -87,7 +87,7 @@ public class StarterBroadcastMQConfiguration { } @Component - @ConditionalOnBean(RocketMQTemplate.class) + @ConditionalOnProperty(name = "rocketmq.name-server") @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_${GID_SEGMENT}_consumer", diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 25e15d6d8..7ae0fdca4 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -52,7 +52,7 @@ import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration * @since 2024/5/30 14:05 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnBean(name = ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME) +@ConditionalOnProperty(name = "rocketmq.name-server") public class StarterRPCInvokeMQConfiguration { private final Logger log = LoggerFactory.getLogger(StarterRPCInvokeMQConfiguration.class); public static final String WORKFLOW_ENGINE_STARTER_EVENT_PRODUCER_BEAN_NAME = "workflowEngineStarterEventProducer"; @@ -165,7 +165,7 @@ public class StarterRPCInvokeMQConfiguration { } @Component - @ConditionalOnBean(RocketMQTemplate.class) + @ConditionalOnProperty(name = "rocketmq.name-server") @Conditional(NonContainerEnvironmentCondition.class) @RocketMQMessageListener(topic = DEFAULT_EVENT + "${spring.profiles.active}", consumerGroup = "GID_${spring.application.name}_workflow_engine_starter_${GID_SEGMENT}_consumer", diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java index b3aacf712..bb5f7f8c1 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowCoreService.java @@ -198,22 +198,6 @@ public interface WorkflowCoreService { @InvokeMode(SYNC) BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto); - /** - * 查询死信消息数据 - * @param procInstId 流程实例id - * @return - */ - @GetMapping("/dead-letter/exception/stacktrace") - String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); - - /** - * 查询死信消息数据 - * @param jobId 死信job的id - * @return - */ - @GetMapping("/dead-letter/exception/stacktrace/byId") - String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId); - /** * 同意 * diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java index f06c18b58..b076bd213 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/api/WorkflowManageService.java @@ -357,6 +357,24 @@ public interface WorkflowManageService { @Manageable Void executeDeadLetterJobAction(@RequestParam(required = false) String jobId, @RequestParam(required = false) String procInstId); + /** + * 查询死信消息数据 + * @param procInstId 流程实例id + * @return + */ + @GetMapping("/dead-letter/exception/stacktrace") + @Manageable + String getDeadLetterJobExceptionStacktrace(@RequestParam String procInstId); + + /** + * 查询死信消息数据 + * @param jobId 死信job的id + * @return + */ + @GetMapping("/dead-letter/exception/stacktrace/byId") + @Manageable + String getDeadLetterJobExceptionStacktraceByJobId(@RequestParam String jobId); + /** * 获取指定业务分类 * From d9b450ca619e5afe70c8522a687eaf12328281b8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 13:08:19 +0800 Subject: [PATCH 090/139] =?UTF-8?q?feat(REQ-2924)=20-=20Starter=20?= =?UTF-8?q?=E9=80=82=E9=85=8D=E6=97=A0=E9=9C=80=E4=BD=BF=E7=94=A8=20MQ=20?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/WorkflowEngineStarterFeignConfiguration.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 278aa331d..197bb466b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -17,6 +17,7 @@ import org.slf4j.MDC; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; import org.springframework.cloud.openfeign.support.ResponseEntityDecoder; @@ -69,7 +70,7 @@ public class WorkflowEngineStarterFeignConfiguration { @Bean public RequestInterceptor workflowEngineStarterRequestInterceptor(WorkflowEngineStarterProperties starterProperties, Environment environment, - String serviceVersion) { + @Qualifier("serviceVersion") String serviceVersion) { return template -> { // 接入应用上报 template.header(HEADER_SERVER_NAME, environment.getProperty("spring.application.name")); From 2b22fe42db71cb394b4c10a80da2897a6704f578 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 13:37:53 +0800 Subject: [PATCH 091/139] =?UTF-8?q?feat(REQ-2924)=20-=20Starter=20?= =?UTF-8?q?=E9=80=82=E9=85=8D=E6=97=A0=E9=9C=80=E4=BD=BF=E7=94=A8=20MQ=20?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/feign/ext/ComplexInvokeClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 96b624360..ac138e139 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -15,6 +15,7 @@ import feign.Response; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.http.HttpStatus; import org.springframework.util.CollectionUtils; @@ -116,7 +117,7 @@ public class ComplexInvokeClient implements Client { .request(request) .body(body) .build(); - } catch (Exception e) { + } catch (BeansException e) { return feignClient.execute(request, options); } } From 668edf04ca5694f4ffcc25316e38df7ccc6f3925 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 13:56:57 +0800 Subject: [PATCH 092/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=A1=A8=E8=84=9A=E6=9C=AC=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/sql/upgrade_to_1.4.2.sql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index 68126ece0..773b7040c 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -26,3 +26,8 @@ create table `workflow-engine`.ext_ax_process_log update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间', is_delete bigint default 0 not null comment '是否删除' ) comment '审批日志持久化'; + +create unique index idx_process_task_status + on ext_ax_process_log (process_instance_id, task_id, status, is_delete); + + From e7b26a1d04cc3c39fa15d2dd148e93412573fd34 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 14:16:16 +0800 Subject: [PATCH 093/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=A1=A8=E8=84=9A=E6=9C=AC=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/sql/upgrade_to_1.4.2.sql | 2 +- .../controller/web/bpmn/BpmnProcessInstanceController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql index 773b7040c..78de441ee 100644 --- a/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql +++ b/workflow-engine-core/src/main/resources/sql/upgrade_to_1.4.2.sql @@ -28,6 +28,6 @@ create table `workflow-engine`.ext_ax_process_log ) comment '审批日志持久化'; create unique index idx_process_task_status - on ext_ax_process_log (process_instance_id, task_id, status, is_delete); + on ext_ax_process_log (process_instance_id asc, task_id asc, status asc, create_at desc); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index ade90a7d7..f00528e8b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -345,7 +345,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController public CommonResponse getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto) { log.info("获取指定流程实例的日志 getProcessInstanceLog===>>>参数:{}", JSONUtil.toJsonStr(dto)); BpmnProcessInstanceLogVO log = bpmnProcessInstanceService.getProcessInstanceLog(dto); - parseSignatureUrl(log); +// parseSignatureUrl(log); return success(log); } From e9c189c589a9cac50284484482c30fc33c8cb129 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 14:17:04 +0800 Subject: [PATCH 094/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/bpmn/BpmnProcessInstanceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java index f00528e8b..ade90a7d7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessInstanceController.java @@ -345,7 +345,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController public CommonResponse getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto) { log.info("获取指定流程实例的日志 getProcessInstanceLog===>>>参数:{}", JSONUtil.toJsonStr(dto)); BpmnProcessInstanceLogVO log = bpmnProcessInstanceService.getProcessInstanceLog(dto); -// parseSignatureUrl(log); + parseSignatureUrl(log); return success(log); } From 09f2d09ae16714ea58a040fed1227e7bbd2c20e5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 14:29:34 +0800 Subject: [PATCH 095/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E9=98=B2=E5=BE=A1=E6=80=A7=E9=80=BB=E8=BE=91=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E7=9B=B4=E6=8E=A5=E8=B7=91=E5=87=BA=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index e3864d038..4dc5eaf92 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1289,7 +1289,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic processingTask.ifPresent(i -> { List assigners = new ArrayList<>(ListUtils.emptyIfNull(i.getForecastAssignees())); if(CollectionUtils.isEmpty(assigners)) { - assigners.add(i.getAssigneeSnapshot()); + if(Objects.nonNull(i.getAssigneeSnapshot())) { + assigners.add(i.getAssigneeSnapshot()); + } } assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))); switch (i.getNodeMode()) { From e221cb1d6ba1ea886e6609c4752eee0b4df84bd6 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 14:56:40 +0800 Subject: [PATCH 096/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=91=8A=E8=AD=A6=E7=9A=84=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/common/annotation/ReporterType.java | 12 ++++++------ .../server/common/aspectj/ErrorReportAspect.java | 8 +++++++- .../workflow/server/common/util/DingTalkUtils.java | 9 ++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java index e42b9df9d..034fdfd47 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java @@ -20,9 +20,9 @@ public enum ReporterType { */ ONLY_DING_TALK { @Override - public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade) { + public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, String invokeServerName, Throwable e, Boolean downgrade) { if (sendDingTalk) { - DingTalkUtils.sendDingTalk(profile, title, argsArrayToString(args), e); + DingTalkUtils.sendDingTalk(profile, title, argsArrayToString(args), invokeServerName, e); } } @@ -32,7 +32,7 @@ public enum ReporterType { */ ONLY_LOG { @Override - public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade) { + public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, String invokeServerName, Throwable e, Boolean downgrade) { if (downgrade) { log.warn("ER: {}", e.getMessage()); } else { @@ -46,9 +46,9 @@ public enum ReporterType { */ BOTH { @Override - public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade) { + public void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, String invokeServerName, Throwable e, Boolean downgrade) { if (sendDingTalk) { - DingTalkUtils.sendDingTalk(profile, title, argsArrayToString(args), e); + DingTalkUtils.sendDingTalk(profile, title, argsArrayToString(args),invokeServerName, e); } if (downgrade) { log.warn("ER: {}", e.getMessage()); @@ -66,7 +66,7 @@ public enum ReporterType { * @param shortString 用于日志输出的关键信息 * @param e 异常对象 */ - public abstract void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade); + public abstract void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, String invokeServerName, Throwable e, Boolean downgrade); private static void logWarn(Throwable throwable, String shortString) { // 由于框架底层 AbstractExceptionApiResultHandler 默认会打印,所以此处都只是降级打印 diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java index dbebfcaae..3e2c96221 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/aspectj/ErrorReportAspect.java @@ -138,7 +138,13 @@ public class ErrorReportAspect implements Ordered { } log.warn("request header server name: {}", getHeader()); - envConfig.type().executeAction(profile, operation.summary(), filterSendDingTalk, joinPoint.getArgs(), joinPoint.getSignature().toShortString(), e, + envConfig.type().executeAction(profile, + operation.summary(), + filterSendDingTalk, + joinPoint.getArgs(), + joinPoint.getSignature().toShortString(), + getHeader(), + e, workflowProperties.getFilterOperations().contains(operation.summary())); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java index 0af16217a..7fa8f7838 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java @@ -68,17 +68,20 @@ public class DingTalkUtils { } @SneakyThrows - public static void sendDingTalk(String profile, String title, Object req, Throwable throwable) { + public static void sendDingTalk(String profile, String title, Object req, String invokeServerName, Throwable throwable) { OapiRobotSendRequest request = new OapiRobotSendRequest(); request.setMsgtype("markdown"); OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice " + title + ", Env: " + profile); - markdown.setText("#### [" + profile + "]" + title + "\n" + + String text = "#### [" + profile + "]" + title + "\n" + "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : throwable.getCause().getMessage()) + " \n\n" + "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + - "> ##### [点击查看异常明细](" + getDeadLetterStacktrace(profile, req) + ") \n"); + "> ##### 调用方服务名称:" + invokeServerName + " \n"; + String deadLetterStacktrace = getDeadLetterStacktrace(profile, req); + text = text + (StringUtils.hasText(deadLetterStacktrace) ? "> ##### [点击查看异常明细](" + deadLetterStacktrace + ") \n" : ""); + markdown.setText(text); request.setMarkdown(markdown); sendDingTalk(request); } From adcb49c80688faca05b27666443ff50f20740954 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Sat, 14 Sep 2024 15:10:18 +0800 Subject: [PATCH 097/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=80=80=E5=9B=9E=E8=8A=82=E7=82=B9=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessTaskServiceImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index a21ed2b76..75a899bba 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -366,6 +366,12 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); } List tasks = this.getHistoricTaskListByProcessInstanceId(processInstanceId, null); + tasks = tasks.stream() + .filter(t -> t.getNodeType() == NODE_STARTER || t.getNodeType() == NODE_TASK || t.getNodeType() == NODE_BUSINESS) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(tasks)) { + return Collections.emptyList(); + } tasks.sort(Comparator.comparing(BpmnHistoricTaskInstanceVO::getCreateTime)); LinkedList>> executedList = new LinkedList<>(); for (BpmnHistoricTaskInstanceVO vo : tasks) { From 9ccfa1334090032943a2c4337ab81b0d820c6a4c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 14 Sep 2024 15:23:50 +0800 Subject: [PATCH 098/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=91=8A=E8=AD=A6=E7=9A=84=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/listener/error/ErrorReporterEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ErrorReporterEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ErrorReporterEventListener.java index aff371d14..f77d9bc8e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ErrorReporterEventListener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/error/ErrorReporterEventListener.java @@ -51,7 +51,7 @@ public class ErrorReporterEventListener implements BpmnAsyncJobEventListener { reporterType = ReporterType.ONLY_LOG; } if (job.getRetries() <= 1) { - reporterType.executeAction(profile, "异步任务执行异常, 重试 3 次后仍未成功", sendDingTalk, new Object[]{job}, "act_ru_job", throwable, false); + reporterType.executeAction(profile, "异步任务执行异常, 重试 3 次后仍未成功", sendDingTalk, new Object[]{job}, "act_ru_job", "", throwable, false); } } From ee04987a99a55fff040b5c4bb3ea8d6fa4a03faf Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Sat, 14 Sep 2024 15:52:12 +0800 Subject: [PATCH 099/139] =?UTF-8?q?REQ-2924-=E5=A2=9E=E5=8A=A0=E9=80=80?= =?UTF-8?q?=E5=9B=9E=E6=AC=A1=E6=95=B0=E9=99=90=E5=88=B6=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 5 + .../core/common/code/BpmnTaskRespCode.java | 1 + .../engine/cmd/CustomBackTaskAsyncCmd.java | 5 +- .../impl/BpmnProcessTaskServiceImpl.java | 210 ++++++++++-------- 4 files changed, 123 insertions(+), 98 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index 57a45a66d..cfe38712a 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -181,4 +181,9 @@ public interface BpmnConstants { * 加签显示人员数量 */ Integer COUNTERSIGN_ASSIGNER_SHOW_NUMBER = 2; + + /** + * 回退操作次数上限 + */ + Integer MAX_BACKED_OPERATE_COUNT = 20; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java index ff4fec3a7..350b4f9d3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java @@ -39,6 +39,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT("022", String.format("人员数量超过限制,节点审批人限制数量为: %d!", APPROVAL_ASSIGNER_LIMIT_NUMBER)), BACK_TARGET_ACTIVITY_NOT_EXISTS("023", "回退到指定节点【{}】失败!"), BACK_NODE_CANNOT_REACHABLE("024", "退回节点【{}】不可达,不允许退回"), + REACHED_BACKED_MAXIMUM_NUM("025", "达到退回操作次数上限【{}】次"), ; private final String code; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java index d43b60a7e..dcf368651 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskAsyncCmd.java @@ -43,11 +43,10 @@ public class CustomBackTaskAsyncCmd extends AbstractCommand implements S @Override public String executeInternal(CommandContext commandContext) { ProcessEngineConfigurationImpl processEngineConfiguration = - CommandContextUtil.getProcessEngineConfiguration(commandContext); + CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoricTaskInstanceQuery taskQuery = - processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); + processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService(); - HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); TaskEntity taskEntity = taskService.getTask(dto.getTaskId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java index 75a899bba..8930b24a0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java @@ -116,6 +116,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_COMMEN import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.MAX_BACKED_OPERATE_COUNT; import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; @@ -125,6 +126,7 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; @@ -134,6 +136,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_TASK_NOT_EXISTS; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.FIND_TASK_BY_PERSON_ID_ERROR; +import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.REACHED_BACKED_MAXIMUM_NUM; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS; import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet; import static cn.axzo.workflow.core.common.utils.BpmnNativeQueryUtil.countSql; @@ -181,8 +184,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { Long resultTotalCount; if (CollectionUtils.isEmpty(dto.getResults())) { HistoricTaskInstanceQuery query = - historyService.createHistoricTaskInstanceQuery().unfinished().taskAssignee(dto.getUserId()) // 分配给自己 - .orderByTaskCreateTime().desc(); + historyService.createHistoricTaskInstanceQuery().unfinished().taskAssignee(dto.getUserId()) // 分配给自己 + .orderByTaskCreateTime().desc(); populateQuery(dto, query); tasks = query.listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); resultTotalCount = query.count(); @@ -201,7 +204,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { // 获得 ProcessInstance Map Map processInstanceMap = - processInstanceService.getProcessInstanceMap(processInstanceIds); + processInstanceService.getProcessInstanceMap(processInstanceIds); List vos = todoPageItemConverter.toVos(tasks, processInstanceMap); return new BpmPageResult<>(vos, resultTotalCount); @@ -215,8 +218,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { if (CollectionUtils.isEmpty(dto.getResults())) { // 查询已办任务 HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 - .taskAssignee(dto.getUserId()) // 分配给自己 - .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 + .taskAssignee(dto.getUserId()) // 分配给自己 + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 populateQuery(dto, query); // 执行查询 tasks = query.listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); @@ -233,7 +236,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } Set processInstanceIds = convertSet(tasks, HistoricTaskInstance::getProcessInstanceId); Map historicProcessInstanceMap = - processInstanceService.getHistoricProcessInstanceMap(processInstanceIds); + processInstanceService.getHistoricProcessInstanceMap(processInstanceIds); List vos = donePageItemConverter.toVos(tasks, historicProcessInstanceMap); return new BpmPageResult<>(vos, resultTotalCount); } @@ -257,7 +260,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { NativeHistoricTaskInstanceQuery nativeQuery = historyService.createNativeHistoricTaskInstanceQuery(); String tableName = managementService.getTableName(HistoricTaskInstance.class); baseQuerySql.append("SELECT a.* FROM ").append(tableName).append(" a JOIN " + "ACT_HI_PROCINST b").append(" " + - "ON b.PROC_INST_ID_ = a.PROC_INST_ID_"); + "ON b.PROC_INST_ID_ = a.PROC_INST_ID_"); if (Objects.nonNull(dto.getTenantId())) { baseQuerySql.append(sqlConnectors(baseQuerySql)).append(" b.TENANT_ID_ = #{tenantId}").append(sqlConnectors(baseQuerySql)).append(" a.TENANT_ID_ = #{tenantId}"); @@ -276,7 +279,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } if (StringUtils.hasLength(dto.getCategories())) { List categories = - Arrays.stream(dto.getCategories().split(",")).map(String::trim).collect(Collectors.toList()); + Arrays.stream(dto.getCategories().split(",")).map(String::trim).collect(Collectors.toList()); baseQuerySql.append(sqlConnectors(baseQuerySql)).append(" a.CATEGORY_ in ("); for (int i = 0; i < categories.size(); i++) { baseQuerySql.append("#{category").append(i).append("}"); @@ -317,7 +320,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } if (StringUtils.hasLength(dto.getCategories())) { List categories = - Arrays.stream(dto.getCategories().split(",")).map(String::trim).collect(Collectors.toList()); + Arrays.stream(dto.getCategories().split(",")).map(String::trim).collect(Collectors.toList()); query.processCategoryIn(categories); } } @@ -344,6 +347,23 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { if (!activityList.contains(dto.getToActivityId())) { throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); } + Optional instOpt = backOptionalNodes.stream() + .map(BpmnOptionalNodeDTO::getProcessInstanceId) + .filter(StringUtils::hasText) + .findAny(); + if (instOpt.isPresent()) { + ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); + searchDTO.setProcessInstanceId(instOpt.get()); + List extAxHiTaskInsts = extAxHiTaskInstService.queryList(searchDTO); + if (CollectionUtils.isNotEmpty(extAxHiTaskInsts)) { + long backOpeCount = extAxHiTaskInsts.stream() + .filter(ext -> BACKED.getStatus().equals(ext.getStatus())) + .count(); + if (backOpeCount > MAX_BACKED_OPERATE_COUNT) { + throw new WorkflowEngineException(REACHED_BACKED_MAXIMUM_NUM, String.valueOf(MAX_BACKED_OPERATE_COUNT)); + } + } + } CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); if (Boolean.TRUE.equals(dto.getAsync())) { commandExecutor.execute(new CustomBackTaskAsyncCmd(dto)); @@ -388,15 +408,15 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { for (Pair> pair : executedList) { List taskInstanceVOList = pair.getRight(); Optional backTaskOpt = taskInstanceVOList - .stream() - .filter(t -> t.getResult() != null) - .filter(t -> t.getResult() == BpmnProcessInstanceResultEnum.BACKED) - .findFirst(); + .stream() + .filter(t -> t.getResult() != null) + .filter(t -> t.getResult() == BpmnProcessInstanceResultEnum.BACKED) + .findFirst(); if (backTaskOpt.isPresent()) { String deleteReason = backTaskOpt.get().getDeleteReason(); String changeParentActivityTo = deleteReason - .replace("Change parent activity to ", "") - .replace("Change activity to ", ""); + .replace("Change parent activity to ", "") + .replace("Change activity to ", ""); if (org.springframework.util.CollectionUtils.isEmpty(valuableList)) { throw new ServiceException("状态异常,首个节点进行了退回操作"); } @@ -416,25 +436,25 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { Map flowElementMap = flowElements.stream().collect(Collectors.toMap(BaseElement::getId, f -> f)); AtomicInteger index = new AtomicInteger(0); List resultList = valuableList - .stream() - .filter(pair -> !task.getTaskDefinitionKey().equals(pair.getLeft())) //排除当前节点 - .map(pair -> flowElementMap.get(pair.getLeft())) - .filter(flowElement -> { - BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); - return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; - }) - .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) - .map(flowElement -> BpmnOptionalNodeDTO - .builder() - .processInstanceId(task.getProcessInstanceId()) - .processDefinitionId(task.getProcessDefinitionId()) - .processActivityId(flowElement.getId()) - .processActivityName(flowElement.getName()) - .processNodeDesc(flowElement.getName()) - .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) - .ordinal(index.incrementAndGet()) - .build()) - .collect(Collectors.toList()); + .stream() + .filter(pair -> !task.getTaskDefinitionKey().equals(pair.getLeft())) //排除当前节点 + .map(pair -> flowElementMap.get(pair.getLeft())) + .filter(flowElement -> { + BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); + return currentNodeType == NODE_TASK || currentNodeType == NODE_BUSINESS; + }) + .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) + .map(flowElement -> BpmnOptionalNodeDTO + .builder() + .processInstanceId(task.getProcessInstanceId()) + .processDefinitionId(task.getProcessDefinitionId()) + .processActivityId(flowElement.getId()) + .processActivityName(flowElement.getName()) + .processNodeDesc(flowElement.getName()) + .nodeType(BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY)) + .ordinal(index.incrementAndGet()) + .build()) + .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(resultList)) { BpmnOptionalNodeDTO bpmnOptionalNodeDTO = resultList.get(resultList.size() - 1); bpmnOptionalNodeDTO.setProcessNodeDesc(bpmnOptionalNodeDTO.getProcessActivityName() + "(上一步)"); @@ -468,13 +488,13 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { public List getHistoricTaskListByProcessInstanceId(String processInstanceId, String tenantId) { HistoricTaskInstanceQuery query = - historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId); + historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId); if (StringUtils.hasLength(tenantId)) { query.taskTenantId(tenantId); } HistoricProcessInstanceQuery instanceQuery = - historyService.createHistoricProcessInstanceQuery() - .processInstanceId(processInstanceId); + historyService.createHistoricProcessInstanceQuery() + .processInstanceId(processInstanceId); // .includeProcessVariables(); if (StringUtils.hasLength(tenantId)) { instanceQuery.processInstanceTenantId(tenantId); @@ -485,35 +505,35 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } List taskInstances = query.orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序 - .list(); + .list(); taskInstances.forEach(task -> ((HistoricTaskInstanceEntity) task).setCreateTime(((HistoricTaskInstanceEntity) task).getLastUpdateTime())); taskInstances.sort(Comparator.comparing(p -> ((HistoricTaskInstanceEntity) p).getLastUpdateTime())); Map variableInstanceMap = - // 不能使用框架提供的历史变量 API 查询,有 BUG - historyService.createNativeHistoricVariableInstanceQuery() - .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") - .parameter("processInstanceId", processInstanceId) - .list().stream() - .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, Function.identity(), - (s, t) -> s)); + // 不能使用框架提供的历史变量 API 查询,有 BUG + historyService.createNativeHistoricVariableInstanceQuery() + .sql("select * from ACT_HI_VARINST t where t.proc_inst_id_= #{processInstanceId}") + .parameter("processInstanceId", processInstanceId) + .list().stream() + .collect(Collectors.toMap(HistoricVariableInstance::getVariableName, Function.identity(), + (s, t) -> s)); HistoricVariableInstance instanceVersion = variableInstanceMap.getOrDefault(WORKFLOW_ENGINE_VERSION, null); // 过滤了多实例或签自动完成的任务 List vos = historicTaskInstanceConverter.toVosSkipSystemOperation(taskInstances, - Objects.isNull(instanceVersion) ? null : - ((HistoricVariableInstanceEntityImpl) instanceVersion).getTextValue()); + Objects.isNull(instanceVersion) ? null : + ((HistoricVariableInstanceEntityImpl) instanceVersion).getTextValue()); Map> commentByTaskIdMap = - taskService.getProcessInstanceComments(processInstanceId).stream() - .collect(Collectors.groupingBy(Comment::getTaskId)); + taskService.getProcessInstanceComments(processInstanceId).stream() + .collect(Collectors.groupingBy(Comment::getTaskId)); Map> attachmentByTaskIdMap = - taskService.getProcessInstanceAttachments(processInstanceId).stream() - .collect(Collectors.groupingBy(Attachment::getTaskId)); + taskService.getProcessInstanceAttachments(processInstanceId).stream() + .collect(Collectors.groupingBy(Attachment::getTaskId)); ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); searchDTO.setProcessInstanceId(processInstanceId); Map extTaskInstMap = extAxHiTaskInstService.queryList(searchDTO).stream() - .collect(Collectors.toMap(ExtAxHiTaskInst::getTaskId, Function.identity(), (s, t) -> s)); + .collect(Collectors.toMap(ExtAxHiTaskInst::getTaskId, Function.identity(), (s, t) -> s)); BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId()); List resultList = new ArrayList<>(); @@ -528,29 +548,29 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { // 处理 advice taskComments.stream().filter(i -> Objects.equals(i.getTaskId(), vo.getTaskId())) - .filter(i -> Objects.equals(i.getType(), COMMENT_TYPE_ADVICE)).findFirst() - .ifPresent(i -> vo.setAdvice(i.getFullMessage())); + .filter(i -> Objects.equals(i.getType(), COMMENT_TYPE_ADVICE)).findFirst() + .ifPresent(i -> vo.setAdvice(i.getFullMessage())); // 处理 operationDesc taskComments.stream().filter(i -> Objects.equals(i.getTaskId(), vo.getTaskId())) - .filter(i -> Objects.equals(COMMENT_TYPE_OPERATION_DESC, i.getType())) - .max(Comparator.comparing(Comment::getTime)) - .ifPresent(i -> vo.setOperationDesc(i.getFullMessage())); + .filter(i -> Objects.equals(COMMENT_TYPE_OPERATION_DESC, i.getType())) + .max(Comparator.comparing(Comment::getTime)) + .ifPresent(i -> vo.setOperationDesc(i.getFullMessage())); // 处理 CommentExt taskComments.stream().filter(i -> Objects.equals(i.getTaskId(), vo.getTaskId())) - .filter(i -> Objects.equals(i.getType(), COMMENT_TYPE_COMMENT_EXT)).findFirst() - .ifPresent(i -> vo.setCommentExt(i.getFullMessage())); + .filter(i -> Objects.equals(i.getType(), COMMENT_TYPE_COMMENT_EXT)).findFirst() + .ifPresent(i -> vo.setCommentExt(i.getFullMessage())); List attachments = attachmentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList()); vo.setAttachments(attachmentConverter.toVos(attachments)); HistoricVariableInstance assginerSnapshot = - variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), - null); + variableInstanceMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + vo.getTaskId(), + null); if (Objects.isNull(assginerSnapshot)) { assginerSnapshot = - variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); + variableInstanceMap.getOrDefault(OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + vo.getTaskId(), null); } BpmnTaskDelegateAssigner assigner = null; @@ -564,15 +584,15 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { vo.setNodeType(nodeType); if (Objects.equals(NODE_CARBON_COPY, nodeType)) { HistoricVariableInstance carbonUsers = - variableInstanceMap.getOrDefault(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + vo.getTaskDefinitionKey(), null); + variableInstanceMap.getOrDefault(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + vo.getTaskDefinitionKey(), null); vo.setForecastAssignees(Objects.isNull(carbonUsers) ? Collections.emptyList() : - (List) carbonUsers.getValue()); + (List) carbonUsers.getValue()); } else { vo.setForecastAssignees(Collections.emptyList()); } }); BpmnMetaParserHelper.getApprovalMethod(bpmnModel.getFlowElement(vo.getTaskDefinitionKey())) - .ifPresent(vo::setApprovalMethod); + .ifPresent(vo::setApprovalMethod); } return resultList; } @@ -586,11 +606,11 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { */ @Override public List getHistoricTaskListGroupByProcessInstanceId(String processInstanceId - , String tenantId) { + , String tenantId) { List vos = getHistoricTaskListByProcessInstanceId(processInstanceId, tenantId); Map> voMapByTaskDefKey = - vos.stream().collect(Collectors.groupingBy(BpmnHistoricTaskInstanceVO::getTaskDefinitionKey)); + vos.stream().collect(Collectors.groupingBy(BpmnHistoricTaskInstanceVO::getTaskDefinitionKey)); List groupVos = new ArrayList<>(); for (Map.Entry> entry : voMapByTaskDefKey.entrySet()) { @@ -628,9 +648,9 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } List vos = bpmnTaskConverter.toVos(query.list()); List snapshotTaskIds = - vos.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO + i.getTaskId()).collect(Collectors.toList()); + vos.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO + i.getTaskId()).collect(Collectors.toList()); Map instanceMap = runtimeService.getVariableInstances(processInstanceId, - snapshotTaskIds); + snapshotTaskIds); vos.forEach(i -> i.setAssigner(BpmnTaskDelegateAssigner.toObjectCompatible(instanceMap.get(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + i.getTaskId()).getValue()))); return vos; } @@ -664,7 +684,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { commandExecutor.execute(new CustomTransferUserTaskAsyncCmd(dto)); } else { commandExecutor.execute(new CustomTransferUserTaskCmd(dto.getTaskId(), - dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner())); + dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner())); } } @@ -706,8 +726,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { public void commentTask(BpmnTaskCommentDTO dto) { CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); commandExecutor.execute(new CustomCommentTaskCmd(dto.getProcessInstanceId(), - dto.getOperator(), dto.getComment(), dto.getCommentExt(), dto.getAttachmentList(), - extAxHiTaskInstService)); + dto.getOperator(), dto.getComment(), dto.getCommentExt(), dto.getAttachmentList(), + extAxHiTaskInstService)); } @Override @@ -715,8 +735,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { public void attachmentTask(BpmnTaskAttachmentDTO dto, String assignee) { Authentication.setAuthenticatedUserId(assignee); Attachment attachment = taskService.createAttachment(dto.getType(), dto.getTaskId(), - dto.getProcessInstanceId(), dto.getName(), dto.getDescription(), - dto.getUrl()); + dto.getProcessInstanceId(), dto.getName(), dto.getDescription(), + dto.getUrl()); taskService.saveAttachment(attachment); Authentication.setAuthenticatedUserId(null); } @@ -730,8 +750,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { commandExecutor.execute(new CustomCountersignUserTaskAsyncCmd(dto)); } else { commandExecutor.execute(new CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum.valueOfType(dto.getCountersignType()), dto.getTaskId(), - dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssignerList(), - extAxHiTaskInstService)); + dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssignerList(), + extAxHiTaskInstService)); } } @@ -752,22 +772,22 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); ProcessInstance processInstance = - runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult(); + runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult(); Optional noticeConfig = - BpmnMetaParserHelper.getNoticeConfig(ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId())); + BpmnMetaParserHelper.getNoticeConfig(ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId())); List assigners = - (List) runtimeService.getVariable(dto.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + dto.getTaskDefinitionKey()); + (List) runtimeService.getVariable(dto.getProcessInstanceId(), + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + dto.getTaskDefinitionKey()); // 过滤出未审批的任何,用选择的方式去发送消息 dto.getRemindTypes().forEach(type -> { list.forEach(task -> { assigners.stream().filter(i -> Objects.equals(task.getAssignee(), i.buildAssigneeId())).findAny().ifPresent(assigner -> { MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.valueOf(type), - Lists.newArrayList(assigner), noticeConfig.orElse(null), - processInstance.getProcessInstanceId(), - processInstance.getProcessDefinitionKey(), - processInstance.getTenantId(), task.getId()); + Lists.newArrayList(assigner), noticeConfig.orElse(null), + processInstance.getProcessInstanceId(), + processInstance.getProcessDefinitionKey(), + processInstance.getTenantId(), task.getId()); event.setProcessInstanceId(processInstance.getProcessInstanceId()); event.setTenantId(processInstance.getTenantId()); event.setTaskId(task.getId()); @@ -782,8 +802,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { public String createRobotTask(BpmnRobotTaskCreateDTO dto) { CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); return commandExecutor.execute(new CustomCreateDummyTaskCmd(dto.getProcessInstanceId(), - dto.getRobotNode().getFlowNodeName(), dto.getRobotNode().getOperationDesc(), dto.getApprover(), - extAxHiTaskInstService)); + dto.getRobotNode().getFlowNodeName(), dto.getRobotNode().getOperationDesc(), dto.getApprover(), + extAxHiTaskInstService)); } @Override @@ -791,17 +811,17 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { public void completeRobotTask(BpmnRobotTaskCompleteDTO dto) { CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); commandExecutor.execute(new CustomCompleteDummyTaskCmd(dto.getProcessInstanceId(), dto.getTaskId(), - Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getFlowNodeName(), - Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getOperationDesc(), - extAxHiTaskInstService)); + Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getFlowNodeName(), + Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getOperationDesc(), + extAxHiTaskInstService)); } @Override public String findTaskIdByInstanceIdAndPersonId(String processInstanceId, String personId) { List list = taskService.createTaskQuery().processInstanceId(processInstanceId) - .taskAssigneeLike("%" + personId) - .active() - .list(); + .taskAssigneeLike("%" + personId) + .active() + .list(); if (CollectionUtils.isEmpty(list) || list.size() > 1) { throw new WorkflowEngineException(FIND_TASK_BY_PERSON_ID_ERROR, processInstanceId, personId); } @@ -811,9 +831,9 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { @Override public Map findTaskIdByInstanceIdsAndPersonId(List processInstanceIds, String personId) { List tasks = taskService.createTaskQuery().processInstanceIdIn(processInstanceIds) - .taskAssigneeLike("%" + personId) - .active() - .list(); + .taskAssigneeLike("%" + personId) + .active() + .list(); if (CollectionUtils.isEmpty(tasks)) { return new HashMap<>(); } From e23595225785d78f53aea29e2689e2f054ef6622 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 18 Sep 2024 11:18:57 +0800 Subject: [PATCH 100/139] =?UTF-8?q?REQ-2924-=E4=BA=8B=E4=BB=B6=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E5=A2=9E=E5=8A=A0=E9=99=84=E4=BB=B6=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=92=8CbusinessKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/response/mq/ProcessTaskDTO.java | 9 +++ .../RocketMqBpmnTaskEvent_102_Listener.java | 63 ++++++++++++------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java index 0dfef6a2f..275fc6ab0 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.common.model.response.mq; import cn.axzo.workflow.common.enums.BpmnNoticeEnum; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf; +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import lombok.Data; import lombok.experimental.Accessors; @@ -44,6 +45,10 @@ public class ProcessTaskDTO implements Serializable { * 流程实例 ID */ private String processInstanceId; + /** + * 流程实例的businessKey + */ + private String businessKey; /** * 流程实例所属业务分类,同时也等于流程模型对应的业务分类 ID */ @@ -103,4 +108,8 @@ public class ProcessTaskDTO implements Serializable { * 当前数据的流程引擎版本 */ private String workflowEngineVersion; + /** + * 任务关联的附件 + */ + private List attachments; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index d56610415..d5390b09f 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -9,12 +9,15 @@ import cn.axzo.workflow.core.common.context.TaskOperationContext; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; import cn.axzo.workflow.core.listener.BpmnTaskEventListener; +import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Process; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Attachment; import org.flowable.task.service.delegate.DelegateTask; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; @@ -23,9 +26,12 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; @@ -59,6 +65,10 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene @Resource private RuntimeService runtimeService; @Resource + private TaskService taskService; + @Resource + private BpmnHistoricAttachmentConverter attachmentConverter; + @Resource private RepositoryService repositoryService; @Value("${sendMq:true}") private Boolean sendMQ; @@ -100,35 +110,44 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene private Deployment getDeployment(String processInstanceId) { ProcessInstance processInstance = - runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); return repositoryService.createDeploymentQuery().deploymentId(processInstance.getDeploymentId()).singleResult(); } public ProcessTaskDTO build(DelegateTask delegateTask, ProcessTaskEventEnum type) { Process mainProcess = getContext().getProcess(() -> repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess()); + //1.获取当前的流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(delegateTask.getProcessInstanceId()).singleResult(); String category = getDeployment(delegateTask.getProcessInstanceId()).getCategory(); ProcessTaskDTO dto = new ProcessTaskDTO() - .setType(type) - .setCategory(category) - .setProcessDefinitionKey(category) - .setProcessTaskId(delegateTask.getId()) - .setProcessInstanceId(delegateTask.getProcessInstanceId()) - .setCurrentElementKey(delegateTask.getTaskDefinitionKey()) - .setCurrentElementName(delegateTask.getName()) - .setProcessDefinitionId(delegateTask.getProcessDefinitionId()) - .setInitiator(BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR))) - .setApprover(BpmnTaskDelegateAssigner.toObjectCompatible( - delegateTask.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId()))) - .setVariables(delegateTask.getVariables()) - .setStartTime(delegateTask.getCreateTime()) - .setTenantId(delegateTask.getTenantId()); + .setType(type) + .setCategory(category) + .setProcessDefinitionKey(category) + .setProcessTaskId(delegateTask.getId()) + .setProcessInstanceId(delegateTask.getProcessInstanceId()) + .setCurrentElementKey(delegateTask.getTaskDefinitionKey()) + .setCurrentElementName(delegateTask.getName()) + .setProcessDefinitionId(delegateTask.getProcessDefinitionId()) + .setInitiator(BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR))) + .setApprover(BpmnTaskDelegateAssigner.toObjectCompatible( + delegateTask.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId()))) + .setVariables(delegateTask.getVariables()) + .setStartTime(delegateTask.getCreateTime()) + .setTenantId(delegateTask.getTenantId()) + .setBusinessKey(processInstance.getBusinessKey()); BpmnMetaParserHelper.getNoticeConfig(mainProcess).ifPresent(dto::setNoticeConf); String version = (String) runtimeService.getVariable(delegateTask.getProcessInstanceId(), - WORKFLOW_ENGINE_VERSION); + WORKFLOW_ENGINE_VERSION); if (Objects.isNull(version)) { version = FLOW_SERVER_VERSION_121; } dto.setWorkflowEngineVersion(version); + Map> listMap = taskService.getProcessInstanceAttachments(delegateTask.getProcessInstanceId()).stream() + .collect(Collectors.groupingBy(Attachment::getTaskId)); + if (!listMap.isEmpty()) { + List attachments = listMap.getOrDefault(delegateTask.getId(), Collections.emptyList()); + dto.setAttachments(attachmentConverter.toVos(attachments)); + } return dto; } @@ -144,12 +163,12 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey()); } eventProducer.send(Event.builder() - .shardingKey(dto.getProcessInstanceId()) - .eventCode(eventEnum.getEventCode()) - .targetId(dto.getProcessInstanceId()) - .targetType(dto.getProcessDefinitionKey()) - .data(dto) - .build(), header); + .shardingKey(dto.getProcessInstanceId()) + .eventCode(eventEnum.getEventCode()) + .targetId(dto.getProcessInstanceId()) + .targetType(dto.getProcessDefinitionKey()) + .data(dto) + .build(), header); } From 2b98fc5311625f460789d5b0be531985027c266f Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 18 Sep 2024 15:38:46 +0800 Subject: [PATCH 101/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=AE=A1=E6=89=B9=E8=8A=82=E7=82=B9=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=AE=A1=E7=AE=97=E9=94=99=E8=AF=AF=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/code/BpmnTaskRespCode.java | 2 +- .../impl/CheckApproverServiceImpl.java | 88 +++++++++++-------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java index 350b4f9d3..732e6be42 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java @@ -39,7 +39,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT("022", String.format("人员数量超过限制,节点审批人限制数量为: %d!", APPROVAL_ASSIGNER_LIMIT_NUMBER)), BACK_TARGET_ACTIVITY_NOT_EXISTS("023", "回退到指定节点【{}】失败!"), BACK_NODE_CANNOT_REACHABLE("024", "退回节点【{}】不可达,不允许退回"), - REACHED_BACKED_MAXIMUM_NUM("025", "达到退回操作次数上限【{}】次"), + REACHED_BACKED_MAXIMUM_NUM("025", "达到回退操作次数上限【{}】次"), ; private final String code; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java index 62db9bd4a..983907017 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -57,8 +58,8 @@ public class CheckApproverServiceImpl implements CheckApproverService { //业务节点,指定业务审批人,或者业务设置了审批人,也要参与自动过审,node_type为NODE_BUSINESS,节点元素类型为UserTask //业务节点审批人为空,或者人员未指定,此时不进行自动过审操作,需要再业务指定审批人后,再做自动过审动作 if (!(Objects.equals(currentNodeType, NODE_TASK) || Objects.equals(currentNodeType, NODE_BUSINESS)) || - !StringUtils.hasText(delegateTask.getAssignee()) || - delegateTask.getAssignee().equals(NO_ASSIGNEE)) { + !StringUtils.hasText(delegateTask.getAssignee()) || + delegateTask.getAssignee().equals(NO_ASSIGNEE)) { return exists.get(); } Optional optConfig = BpmnMetaParserHelper.getButtonConfig(mainProcess, delegateTask.getTaskDefinitionKey()); @@ -71,49 +72,60 @@ public class CheckApproverServiceImpl implements CheckApproverService { return exists.get(); } Optional agreeButton = currentButtons.stream() - .filter(button -> button.getType().equals("SYSTEM") //系统按钮 - && button.getChecked() != null && button.getChecked() //选中 - && (button.getDisabled() == null || !button.getDisabled()) //没用禁用 - && button.getBtnKey().equals(BpmnButtonEnum.BPMN_APPROVE.getBtnKey())) //类型为同意 - .findFirst(); + .filter(button -> button.getType().equals("SYSTEM") //系统按钮 + && button.getChecked() != null && button.getChecked() //选中 + && (button.getDisabled() == null || !button.getDisabled()) //没用禁用 + && button.getBtnKey().equals(BpmnButtonEnum.BPMN_APPROVE.getBtnKey())) //类型为同意 + .findFirst(); //不存在同意按钮 if (!agreeButton.isPresent()) { return exists.get(); } ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); processEngineConfiguration.getActivityInstanceEntityManager() - .findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false) - .stream() - .filter(i -> !Objects.equals(i.getActivityId(), userTask.getId())) - .filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway")) - .filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow")) - .max(Comparator.comparing(ActivityInstanceEntity::getStartTime)) - .ifPresent(i -> { - // 与发起人比对 - if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) { - BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)); - if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) { - exists.compareAndSet(false, true); - } - } else { - FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId()); - BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> { - //上一节点如果是业务节点,但是是人员审批,也需要加入到自动过审 - if (Objects.equals(NODE_TASK, j) || (Objects.equals(NODE_BUSINESS, j) && flowElement.getClass().isAssignableFrom(UserTask.class))) { - ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); - searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId()); - searchDTO.setTaskDefinitionKey(i.getActivityId()); - taskOperationContext.getExtAxHiTaskInsts(() -> extAxHiTaskInstService.queryList(searchDTO)) - .stream().filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus())) - .map(ExtAxHiTaskInst::getAssignee) - .filter(Objects::nonNull) - .filter(StringUtils::hasText) - .filter(k -> specialApproverComparison(k, delegateTask.getAssignee())) - .findAny().ifPresent(k -> exists.compareAndSet(false, true)); - } - }); + .findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false) + .stream() + .filter(i -> !Objects.equals(i.getActivityId(), userTask.getId())) + .filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway")) + .filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow")) + .max(Comparator.comparing(ActivityInstanceEntity::getStartTime)) + .ifPresent(i -> { + // 与发起人比对 + if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) { + BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)); + if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) { + exists.compareAndSet(false, true); } - }); + } else { + FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId()); + BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> { + //上一节点如果是业务节点,但是是人员审批,也需要加入到自动过审 + if (Objects.equals(NODE_TASK, j) || (Objects.equals(NODE_BUSINESS, j) && flowElement.getClass().isAssignableFrom(UserTask.class))) { + ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); + searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId()); + List extAxHiTaskInsts = extAxHiTaskInstService.queryList(searchDTO); + extAxHiTaskInsts.sort(Comparator.comparing(ExtAxHiTaskInst::getCreateAt)); + List previousTasks = new ArrayList<>(); + for (int k = extAxHiTaskInsts.size() - 1; k > 0; k--) { + ExtAxHiTaskInst extAxHiTaskInst = extAxHiTaskInsts.get(k); + if (!extAxHiTaskInst.getTaskDefinitionKey().equals(i.getActivityId()) && !CollectionUtils.isEmpty(previousTasks)) { + break; + } + if (extAxHiTaskInst.getTaskDefinitionKey().equals(i.getActivityId())) { + previousTasks.add(extAxHiTaskInst); + } + } + previousTasks.stream() + .filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus())) + .map(ExtAxHiTaskInst::getAssignee) + .filter(Objects::nonNull) + .filter(StringUtils::hasText) + .filter(k -> specialApproverComparison(k, delegateTask.getAssignee())) + .findAny().ifPresent(k -> exists.compareAndSet(false, true)); + } + }); + } + }); return exists.get(); } From 969f5dc70b8b298c67168865e49684f2189dd30c Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 18 Sep 2024 17:54:47 +0800 Subject: [PATCH 102/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E5=8A=A0?= =?UTF-8?q?=E7=AD=BE=E6=97=A5=E5=BF=97=E6=96=87=E6=A1=88=E5=A4=9A=E4=BD=99?= =?UTF-8?q?"=E3=80=81"=E7=AC=A6=E5=8F=B7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java index 577e5af01..3b604b897 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java @@ -149,7 +149,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen //加签人员数量显示指定个数 for (int i = 0; i < end; i++) { message.append(targetTaskAssigneeList.get(i).getAssignerName()); - if (i < targetTaskAssigneeList.size() - 1) { + if (i < end - 1) { message.append("、"); } } From fa66b6f4ece67074fa5480e57d3f3b46a4449d1b Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 19 Sep 2024 11:53:51 +0800 Subject: [PATCH 103/139] =?UTF-8?q?REQ-2924-=E8=B0=83=E6=95=B4=E8=A7=92?= =?UTF-8?q?=E8=89=B2=EF=BC=8C=E7=AE=A1=E7=90=86=E5=91=98=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BasedRoleTaskAssigneeSelector.java | 77 ++++++++++++------- .../TransferToAdminTaskAssigneeSelector.java | 4 +- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index 8e3968943..ff959fc20 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -1,24 +1,30 @@ package cn.axzo.workflow.server.controller.delegate; -import cn.axzo.tyr.client.feign.TyrSaasRoleUserApi; -import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserDTO; -import cn.axzo.tyr.client.model.roleuser.req.RoleUserParam; +import cn.axzo.karma.client.feign.FlowSupportApi; +import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq; +import cn.axzo.karma.client.model.response.FlowTaskAssignerResp; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; -import cn.axzo.workflow.common.model.dto.CooperationOrgDTO.OrgScope; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; +import cn.axzo.workflow.core.service.BpmnProcessModelService; +import cn.axzo.workflow.core.service.CategoryService; import cn.hutool.core.collection.CollUtil; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; -import java.util.Set; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; +import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY; + /** * 基于"角色"查询审批人 * @@ -30,7 +36,13 @@ import java.util.stream.Collectors; public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { @Autowired - private TyrSaasRoleUserApi tyrSaasRoleUserApi; + private FlowSupportApi flowSupportApi; + + @Autowired + private CategoryService categoryService; + + @Autowired + private BpmnProcessModelService bpmnProcessModelService; @Override public String getType() { @@ -51,33 +63,46 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec @Override protected List invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { - Set workspaceIdSet = ListUtils.emptyIfNull(scopeDto.getOrgScopes()).stream() - .map(OrgScope::getWorkspaceId) - .collect(Collectors.toSet()); - - - // ouIds、workspaceIds 只能传其中一个 然后代码过滤 - RoleUserParam param = RoleUserParam.builder() - .roleIds(super.getTypes(flowElement).stream().map(Long::valueOf).collect(Collectors.toSet())) - .ouIds(ListUtils.emptyIfNull(scopeDto.getOrgScopes()).stream() - .map(OrgScope::getOuId) + BpmnModelDetailVO detailVO = bpmnProcessModelService.getById(execution.getProcessDefinitionId(), null); + Optional categoryItemVO = categoryService.get(BPM_MODEL_CATEGORY, detailVO.getKey()); + Map variables = execution.getVariables(); + ListFlowTaskAssignerReq req = ListFlowTaskAssignerReq.builder() + .procInstId(execution.getProcessInstanceId()) + .procInstType(Integer.valueOf(Objects.requireNonNull(categoryItemVO.map(CategoryItemVO::getWorkspaceTypeCode).orElse(null)))) + .orgScopes(scopeDto.getOrgScopes().stream() + .map(os -> ListFlowTaskAssignerReq.OrgScope.builder() + .ouId(os.getOuId()) + .nodeId(os.getNodeId()) + .workspaceId(os.getWorkspaceId()) + .workspaceType(os.getWorkspaceType()) + .build()) .collect(Collectors.toList())) + .workerTeamScopes(scopeDto.getWorkerTeamScopes().stream() + .map(ot -> ListFlowTaskAssignerReq.OrgScope.builder() + .workspaceId(ot.getWorkspaceId()) + .ouId(ot.getOuId()) + .nodeId(ot.getNodeId()) + .workspaceType(ot.getWorkspaceType()) + .build()) + .collect(Collectors.toList())) + .roleIds(super.getTypes(flowElement).stream().map(Long::valueOf).collect(Collectors.toList())) + .variables(variables) .build(); - List flowTaskAssigners = parseApiResult(() -> tyrSaasRoleUserApi.roleUserList(param), + + List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerByRoles(req), "审批节点: " + flowElement.getId() + ", 通过角色查询审批人", - "cn.axzo.tyr.client.feign.TyrSaasRoleUserApi.roleUserList", param) - .stream().filter(f -> workspaceIdSet.contains(f.getWorkspaceId())) - .collect(Collectors.toList()); + "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerByRoles", req); if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); } - return flowTaskAssigners.stream().map(u -> BpmnTaskDelegateAssigner.builder() - .assignee(String.valueOf(u.getIdentityId())) - .assigneeType(String.valueOf(u.getIdentityType())) - .tenantId(String.valueOf(u.getWorkspaceId())) + return flowTaskAssigners.stream() + .map(u -> BpmnTaskDelegateAssigner.builder() + .assignee(String.valueOf(u.getAssignee())) + .assigneeType(String.valueOf(u.getAssigneeType())) + .tenantId(String.valueOf(u.getTenantId())) .ouId(String.valueOf(u.getOuId())) - .personId(String.valueOf(u.getNaturalPersonId())) + .personId(String.valueOf(u.getPersonId())) .build()) .collect(Collectors.toList()); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 62e47c22c..a282e55c5 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -70,9 +70,9 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne } }); List flowTaskAssigners = - parseApiResult(() -> flowSupportApi.listTaskAssignerAdmin(req), + parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", - "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerAdmin", req); + "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerAdminV2", req); if (CollUtil.isEmpty(flowTaskAssigners)) { From 9ea952ca8df16e7a150c5be038cbe671539640f9 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 19 Sep 2024 17:23:12 +0800 Subject: [PATCH 104/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8D=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E4=BA=BA=E5=91=98=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/BasedRoleTaskAssigneeSelector.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index ff959fc20..f05d1b81b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -5,10 +5,10 @@ import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq; import cn.axzo.karma.client.model.response.FlowTaskAssignerResp; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; -import cn.axzo.workflow.common.model.response.bpmn.model.BpmnModelDetailVO; +import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; import cn.axzo.workflow.common.model.response.category.CategoryItemVO; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; -import cn.axzo.workflow.core.service.BpmnProcessModelService; +import cn.axzo.workflow.core.service.BpmnProcessDefinitionService; import cn.axzo.workflow.core.service.CategoryService; import cn.hutool.core.collection.CollUtil; import lombok.extern.slf4j.Slf4j; @@ -42,7 +42,7 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec private CategoryService categoryService; @Autowired - private BpmnProcessModelService bpmnProcessModelService; + private BpmnProcessDefinitionService bpmnProcessDefinitionService; @Override public String getType() { @@ -63,8 +63,8 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec @Override protected List invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { - BpmnModelDetailVO detailVO = bpmnProcessModelService.getById(execution.getProcessDefinitionId(), null); - Optional categoryItemVO = categoryService.get(BPM_MODEL_CATEGORY, detailVO.getKey()); + BpmnProcessDefinitionVO processDefinition = bpmnProcessDefinitionService.getProcessDefinition(execution.getProcessDefinitionId()); + Optional categoryItemVO = categoryService.get(BPM_MODEL_CATEGORY, processDefinition.getKey()); Map variables = execution.getVariables(); ListFlowTaskAssignerReq req = ListFlowTaskAssignerReq.builder() .procInstId(execution.getProcessInstanceId()) From e85cf6cde507af2b23f58d43f54629094b91df2f Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 19 Sep 2024 17:52:36 +0800 Subject: [PATCH 105/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8DNPE=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/BasedRoleTaskAssigneeSelector.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index f05d1b81b..cba156eba 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -16,7 +16,9 @@ import org.flowable.bpmn.model.FlowElement; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -69,7 +71,7 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec ListFlowTaskAssignerReq req = ListFlowTaskAssignerReq.builder() .procInstId(execution.getProcessInstanceId()) .procInstType(Integer.valueOf(Objects.requireNonNull(categoryItemVO.map(CategoryItemVO::getWorkspaceTypeCode).orElse(null)))) - .orgScopes(scopeDto.getOrgScopes().stream() + .orgScopes(CollectionUtils.isEmpty(scopeDto.getOrgScopes()) ? Collections.emptyList() : scopeDto.getOrgScopes().stream() .map(os -> ListFlowTaskAssignerReq.OrgScope.builder() .ouId(os.getOuId()) .nodeId(os.getNodeId()) @@ -77,7 +79,7 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec .workspaceType(os.getWorkspaceType()) .build()) .collect(Collectors.toList())) - .workerTeamScopes(scopeDto.getWorkerTeamScopes().stream() + .workerTeamScopes(CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes()) ? Collections.emptyList() : scopeDto.getWorkerTeamScopes().stream() .map(ot -> ListFlowTaskAssignerReq.OrgScope.builder() .workspaceId(ot.getWorkspaceId()) .ouId(ot.getOuId()) From 1cc46a40cfa3231e9a2d773f4415476996b2f603 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 19 Sep 2024 18:58:22 +0800 Subject: [PATCH 106/139] =?UTF-8?q?REQ-2924-=E5=8E=BB=E6=8E=89=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/BasedRoleTaskAssigneeSelector.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index cba156eba..9932c4c3c 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -37,9 +37,6 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY; @Component public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { - @Autowired - private FlowSupportApi flowSupportApi; - @Autowired private CategoryService categoryService; From 4174e4f4517e14eec4d6a4d6cfe88bdad7301cf8 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 20 Sep 2024 15:39:38 +0800 Subject: [PATCH 107/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E5=A4=8Dtask?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=B6=88=E6=81=AF=E6=B2=A1=E6=9C=89=E9=99=84?= =?UTF-8?q?=E4=BB=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/constant/BpmnConstants.java | 1 + .../model/request/bpmn/task/AttachmentDTO.java | 4 +++- .../core/engine/cmd/CustomApproveTaskCmd.java | 3 ++- .../core/engine/cmd/CustomRejectionTaskCmd.java | 2 ++ .../task/RocketMqBpmnTaskEvent_102_Listener.java | 13 +++++-------- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index cfe38712a..49661639a 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -122,6 +122,7 @@ public interface BpmnConstants { String NUMBER_OF_INSTANCES = "nrOfInstances"; String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter"; String TASK_COMPLETE_OPERATION_TYPE = "_TASK_COMPLETE_TYPE"; + String TASK_ATTACHMENTS_VAR_NAME = "TASK_ATTACHMENTS"; /** * 会签表达式 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java index b71352af2..6fd66819b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/AttachmentDTO.java @@ -10,6 +10,7 @@ import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import java.io.Serializable; /** * 附件模型 @@ -22,8 +23,9 @@ import javax.validation.constraints.NotNull; @Builder @AllArgsConstructor @NoArgsConstructor -public class AttachmentDTO { +public class AttachmentDTO implements Serializable { + private static final long serialVersionUID = 6954179791395744269L; /** * 附件 ID */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index 13e26a173..a8645252a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -28,6 +28,7 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; @@ -140,7 +141,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria nextApprover); } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); - + task.setTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME, attachmentList); executeSynchronous(task, taskService, runtimeService); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index 7d73db2b6..c249e7e8a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -30,6 +30,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_I import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_DELETE_REASON; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; @@ -111,6 +112,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser batchAddAttachment(commandContext, task.getProcessInstanceId(), virtualTask.getId(), attachmentList, approver); completeVirtualTask(commandContext, virtualTask); + task.setTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME, attachmentList); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); finishProcessInstance(commandContext, runtimeService, task, advice); return null; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index d5390b09f..8168aba0b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.server.controller.listener.task; import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.ProcessTaskEventEnum; +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO; import cn.axzo.workflow.core.common.context.TaskOperationContext; @@ -17,7 +18,6 @@ import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.engine.task.Attachment; import org.flowable.task.service.delegate.DelegateTask; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; @@ -26,18 +26,17 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED; import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_COMPLETED; @@ -142,11 +141,9 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene version = FLOW_SERVER_VERSION_121; } dto.setWorkflowEngineVersion(version); - Map> listMap = taskService.getProcessInstanceAttachments(delegateTask.getProcessInstanceId()).stream() - .collect(Collectors.groupingBy(Attachment::getTaskId)); - if (!listMap.isEmpty()) { - List attachments = listMap.getOrDefault(delegateTask.getId(), Collections.emptyList()); - dto.setAttachments(attachmentConverter.toVos(attachments)); + Object attachmentObj = delegateTask.getTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME); + if (attachmentObj != null) { + dto.setAttachments((List) attachmentObj); } return dto; } From 3a826d8fa6984897018197c2d2c379da72733db1 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Fri, 20 Sep 2024 17:34:04 +0800 Subject: [PATCH 108/139] =?UTF-8?q?REQ-2924-=E6=B7=BB=E5=8A=A0=E9=99=84?= =?UTF-8?q?=E4=BB=B6=E8=AE=BE=E7=BD=AE=E5=88=B0=E4=BB=BB=E5=8A=A1=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomApproveTaskCmd.java | 4 +--- .../core/engine/cmd/CustomBackTaskCmd.java | 2 +- .../core/engine/cmd/CustomCommentTaskCmd.java | 2 +- .../engine/cmd/CustomCountersignUserTaskCmd.java | 6 +++--- .../core/engine/cmd/CustomRejectionTaskCmd.java | 14 ++++++-------- .../core/engine/cmd/CustomTransferUserTaskCmd.java | 2 +- .../core/engine/cmd/helper/CustomTaskHelper.java | 10 ++++++---- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java index a8645252a..f04a60914 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java @@ -28,7 +28,6 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; -import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; @@ -128,7 +127,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria Authentication.setAuthenticatedUserId(null); } - batchAddAttachment(commandContext, task.getProcessInstanceId(), taskId, attachmentList, approver); + batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, approver); Authentication.setAuthenticatedUserId(Objects.nonNull(approver) ? approver.buildAssigneeId() : null); addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc); @@ -141,7 +140,6 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria nextApprover); } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); - task.setTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME, attachmentList); executeSynchronous(task, taskService, runtimeService); return null; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java index ddc787e8b..31df9ca27 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java @@ -86,7 +86,7 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ if (!BpmnModelUtils.isReachable(process, (FlowNode) targetFlowElement, (FlowNode) sourceFlowElement)) { throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); } - batchAddAttachment(commandContext, task.getProcessInstanceId(), dto.getTaskId(), dto.getAttachmentList(), dto.getApprover()); + batchAddAttachment(commandContext, task.getProcessInstanceId(), task, dto.getAttachmentList(), dto.getApprover()); Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId()); addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java index 793db2453..cd34b8cf7 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommentTaskCmd.java @@ -125,7 +125,7 @@ public class CustomCommentTaskCmd extends AbstractCommand implements Seria addComment(commandContext, task, COMMENT_TYPE_COMMENT_EXT, JSONUtil.toJsonStr(commentExt)); Authentication.setAuthenticatedUserId(null); // 处理附件 - batchAddAttachment(commandContext, processInstanceId, task.getId(), attachmentList, operator); + batchAddAttachment(commandContext, processInstanceId, task, attachmentList, operator); // 设置快照信息 task.setTransientVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), operator.toJson()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java index 3b604b897..4d5396dd9 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCountersignUserTaskCmd.java @@ -98,7 +98,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen resolveOriginTask(commandContext, extAxHiTaskInstService, taskService, task); - batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, + batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee); switch (countersignType) { @@ -142,7 +142,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen } private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService, - TaskService taskService, Task task) { + TaskService taskService, TaskEntity task) { // 构建评论内容 StringBuilder message = new StringBuilder("添加"); int end = Math.min(targetTaskAssigneeList.size(), COUNTERSIGN_ASSIGNER_SHOW_NUMBER); @@ -156,7 +156,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen message.append("等").append(targetTaskAssigneeList.size()).append("人进行审批"); Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString())); - batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, originTaskAssignee); + batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee); completeVirtualTask(commandContext, virtualTask); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java index c249e7e8a..f73f1ccff 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomRejectionTaskCmd.java @@ -30,7 +30,6 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_I import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_DELETE_REASON; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT; -import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; @@ -104,15 +103,14 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser validTask(historicTaskInstance, task, approver, nodeTypes); task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), DELETED.getStatus()); - Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), - task.getTaskDefinitionKey(), advice, - Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus(), - new AddComment(operationDesc)); + TaskEntity virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), + task.getTaskDefinitionKey(), advice, + Objects.equals(operationDesc, "自动驳回") ? null : approver, REJECTED.getStatus(), + new AddComment(operationDesc)); - batchAddAttachment(commandContext, task.getProcessInstanceId(), virtualTask.getId(), attachmentList, approver); + batchAddAttachment(commandContext, task.getProcessInstanceId(), virtualTask, attachmentList, approver); completeVirtualTask(commandContext, virtualTask); - task.setTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME, attachmentList); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); finishProcessInstance(commandContext, runtimeService, task, advice); return null; @@ -129,7 +127,7 @@ public class CustomRejectionTaskCmd extends AbstractCommand implements Ser runtimeService.setVariables(task.getProcessInstanceId(), variables); CommandContextUtil.getAgenda(commandContext) .planOperation(new DeleteProcessInstanceOperation(commandContext, task.getProcessInstanceId(), - extAxHiTaskInstService, REJECTED)); + extAxHiTaskInstService, REJECTED)); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java index 51778165d..770238200 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomTransferUserTaskCmd.java @@ -92,7 +92,7 @@ public class CustomTransferUserTaskCmd extends AbstractCommand implements // 对被转交的任务进行建议和附件的处理 resolveOriginTask(commandContext, taskService, task); - batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, + batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee); // 生成转交任务 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java index 9a182aa80..5cb212b31 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomTaskHelper.java @@ -55,6 +55,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_R import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VAR_NAME; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; @@ -220,10 +221,10 @@ public class CustomTaskHelper { * * @param commandContext * @param processInstanceId - * @param taskId + * @param task * @param attachmentList */ - public static void batchAddAttachment(CommandContext commandContext, String processInstanceId, String taskId, + public static void batchAddAttachment(CommandContext commandContext, String processInstanceId, TaskEntity task, List attachmentList, BpmnTaskDelegateAssigner assigner) { if (CollectionUtils.isEmpty(attachmentList)) { return; @@ -233,10 +234,11 @@ public class CustomTaskHelper { TaskService taskService = processEngineConfiguration.getTaskService(); Authentication.setAuthenticatedUserId(assigner.buildAssigneeId()); attachmentList.forEach(dto -> { - Attachment attachment = taskService.createAttachment(dto.getType().getType(), taskId, processInstanceId, + Attachment attachment = taskService.createAttachment(dto.getType().getType(), task.getId(), processInstanceId, dto.getName(), dto.getDescription(), dto.getUrl()); taskService.saveAttachment(attachment); }); + task.setTransientVariableLocal(TASK_ATTACHMENTS_VAR_NAME, attachmentList); Authentication.setAuthenticatedUserId(null); } @@ -320,7 +322,7 @@ public class CustomTaskHelper { * @param extTaskInstStatus 节点状态 * @return */ - public static Task createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService + public static TaskEntity createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, BpmnTaskDelegateAssigner assigner, String extTaskInstStatus, AddComment addComment) { From 3e37d3598681124d2fa248ecf6a017d050c80742 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Mon, 23 Sep 2024 17:26:59 +0800 Subject: [PATCH 109/139] =?UTF-8?q?REQ-2924-=E4=BB=BB=E5=8A=A1=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E6=B6=88=E6=81=AF=E5=A2=9E=E5=8A=A0=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/model/response/mq/ProcessTaskDTO.java | 5 +++++ .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java index 275fc6ab0..f93c69ee2 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java @@ -112,4 +112,9 @@ public class ProcessTaskDTO implements Serializable { * 任务关联的附件 */ private List attachments; + + /** + * 评论 + */ + private String operationDesc; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index 8168aba0b..af0dd6529 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; @@ -133,7 +134,8 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene .setVariables(delegateTask.getVariables()) .setStartTime(delegateTask.getCreateTime()) .setTenantId(delegateTask.getTenantId()) - .setBusinessKey(processInstance.getBusinessKey()); + .setBusinessKey(processInstance.getBusinessKey()) + .setOperationDesc(delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE) == null ? null : (String) delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE)); BpmnMetaParserHelper.getNoticeConfig(mainProcess).ifPresent(dto::setNoticeConf); String version = (String) runtimeService.getVariable(delegateTask.getProcessInstanceId(), WORKFLOW_ENGINE_VERSION); From 27d1efaa344a16628cceb24a11b8bbdb86d90ad7 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Mon, 23 Sep 2024 17:29:17 +0800 Subject: [PATCH 110/139] =?UTF-8?q?REQ-2924-=E4=BF=AE=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/model/response/mq/ProcessTaskDTO.java | 4 ++-- .../listener/task/RocketMqBpmnTaskEvent_102_Listener.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java index f93c69ee2..2822419c5 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/mq/ProcessTaskDTO.java @@ -114,7 +114,7 @@ public class ProcessTaskDTO implements Serializable { private List attachments; /** - * 评论 + * 审批意见 */ - private String operationDesc; + private String advice; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java index af0dd6529..0bae0dea6 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/RocketMqBpmnTaskEvent_102_Listener.java @@ -135,7 +135,7 @@ public class RocketMqBpmnTaskEvent_102_Listener extends AbstractBpmnEventListene .setStartTime(delegateTask.getCreateTime()) .setTenantId(delegateTask.getTenantId()) .setBusinessKey(processInstance.getBusinessKey()) - .setOperationDesc(delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE) == null ? null : (String) delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE)); + .setAdvice(delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE) == null ? null : (String) delegateTask.getTransientVariableLocal(COMMENT_TYPE_ADVICE)); BpmnMetaParserHelper.getNoticeConfig(mainProcess).ifPresent(dto::setNoticeConf); String version = (String) runtimeService.getVariable(delegateTask.getProcessInstanceId(), WORKFLOW_ENGINE_VERSION); From 333abc1cb4e6974fba3cba5fbb7120d2c6d6f461 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 14:04:01 +0800 Subject: [PATCH 111/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=B2=97=E4=BD=8D=E3=80=81=E8=A7=92=E8=89=B2=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=BD=AC=E4=BA=A4=E7=9A=84=E8=B6=85=E7=AE=A1?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EngineExecutionStartListener.java | 12 +++++++- .../BasedIdentityTaskAssigneeSelector.java | 2 +- ...edInitiatorLeaderTaskAssigneeSelector.java | 1 - .../BasedRoleTaskAssigneeSelector.java | 1 + .../TransferToAdminTaskAssigneeSelector.java | 30 +++++++++++++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java index 7990cf413..4c60faea3 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.constant.BpmnConstants; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.conf.SupportRefreshProperties; @@ -11,6 +12,8 @@ import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector; import cn.axzo.workflow.core.deletage.BpmnTaskCalculateDTO; import cn.axzo.workflow.core.deletage.BpmnTaskDelegate; import cn.axzo.workflow.core.deletage.MockTaskAssigneeSelector; +import cn.axzo.workflow.core.engine.cmd.CustomAbortProcessInstanceAsyncCmd; +import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; @@ -21,9 +24,9 @@ import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; +import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -183,6 +186,13 @@ public class EngineExecutionStartListener implements ExecutionListener { case transferToAdmin: assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask, execution, true)); + if (CollectionUtils.isEmpty(assigners)) { + BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO(); + abortDTO.setProcessInstanceId(execution.getProcessInstanceId()); + abortDTO.setReason("转交管理员失败,系统中止"); + CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor() + .execute(new CustomAbortProcessInstanceAsyncCmd(abortDTO)); + } break; case specifyAssignee: List emptyAssignees = diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java index d137fa30f..7caae6178 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java @@ -54,7 +54,7 @@ public class BasedIdentityTaskAssigneeSelector extends AbstractBpmnTaskAssigneeS .collect(Collectors.toList())) .identityCodes(super.getTypes(flowElement)) .build(); - + req.setProcInstId(execution.getProcessInstanceId()); List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerByIdentity(req), "审批节点: " + flowElement.getId() + ", 通过身份查询审批人", diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java index 66b0835d6..2b8b8aa0d 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java @@ -68,7 +68,6 @@ public class BasedInitiatorLeaderTaskAssigneeSelector extends AbstractBpmnTaskAs .identityId(Long.valueOf(initiator.getAssignee())) .identityType(Integer.valueOf(initiator.getAssigneeType())).build()) .build(); - List flowTaskAssigners = parseApiResult(() -> organizationalNodeUserApi.listFlowTaskAssigner(req), "审批节点: " + flowElement.getId() + ", 通过发起人主管查询审批人", diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index 9932c4c3c..14d42252d 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -88,6 +88,7 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec .variables(variables) .build(); + req.setProcInstId(execution.getProcessInstanceId()); List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerByRoles(req), "审批节点: " + flowElement.getId() + ", 通过角色查询审批人", "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerByRoles", req); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index a282e55c5..76c29318e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -4,11 +4,13 @@ import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq; import cn.axzo.karma.client.model.response.FlowTaskAssignerResp; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; import cn.axzo.workflow.common.enums.ApproverScopeEnum; +import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; @@ -17,8 +19,12 @@ import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; /** @@ -51,6 +57,13 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne protected List invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { + Optional optSpecify = BpmnMetaParserHelper.getApproverSpecify((UserTask) flowElement); + if (optSpecify.isPresent() + && !Objects.equals(ApproverSpecifyEnum.position, optSpecify.get()) + && !Objects.equals(ApproverSpecifyEnum.role, optSpecify.get())) { + return Collections.emptyList(); + } + ListFlowTaskAssignerReq.ListFlowTaskAssignerReqBuilder builder = ListFlowTaskAssignerReq.builder(); if (!CollectionUtils.isEmpty(scopeDto.getOrgScopes())) { builder.orgScopes(ListUtils.emptyIfNull(scopeDto.getOrgScopes()).stream() @@ -63,6 +76,8 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne .collect(Collectors.toList())); } ListFlowTaskAssignerReq req = builder.workspaceAdmin(false).build(); + req.setProcInstId(execution.getProcessInstanceId()); + req.setCooperateTypes(getCooperationTypes(flowElement)); BpmnMetaParserHelper.getApproverScope((UserTask) flowElement) .ifPresent(i -> { if (Objects.equals(i, ApproverScopeEnum.projectWorkspace)) { @@ -80,4 +95,19 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne } return BeanUtil.copyToList(flowTaskAssigners, BpmnTaskDelegateAssigner.class); } + + public Set getCooperationTypes(FlowElement flowElement) { + return BpmnMetaParserHelper.getApproverSpecifyValue((UserTask) flowElement) + .map(value -> JSON.parseArray(value, String.class) + .stream().map(JSON::parseObject) + .map(i -> i.getString("type")) + .collect(Collectors.toList()) + .stream() + .flatMap(s -> Arrays.stream(s.split(","))) + .map(Integer::parseInt) + .collect(Collectors.toSet()) + ) + .orElse(Collections.emptySet()); + } + } From fb09025440d72d63fe59daf095735d1757447104 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 16:55:26 +0800 Subject: [PATCH 112/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BA=BA=EF=BC=8C=E4=BC=9A=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E4=BA=8C=E6=96=B9=E6=8E=A5=E5=8F=A3=E6=9F=A5=E8=AF=A2=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E6=98=AF=E5=90=A6=E5=9C=A8=E8=81=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BasedFixedPersonTaskAssigneeSelector.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java index 1934a672e..aba25252e 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java @@ -1,16 +1,26 @@ package cn.axzo.workflow.server.controller.delegate; +import cn.axzo.maokai.api.client.OrganizationalNodeUserApi; +import cn.axzo.maokai.api.vo.request.OrganizationalNodeUserSearchReq; +import cn.axzo.maokai.api.vo.response.OrganizationalNodeUserVO; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import com.alibaba.fastjson.JSON; +import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import javax.annotation.Resource; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * 基于"固定人员"查询审批人 @@ -20,6 +30,9 @@ import java.util.List; */ @Component public class BasedFixedPersonTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { + @Resource + private OrganizationalNodeUserApi organizationalNodeUserApi; + @Override public String getType() { return ApproverSpecifyEnum.fixedPerson.getType(); @@ -39,7 +52,31 @@ public class BasedFixedPersonTaskAssigneeSelector extends AbstractBpmnTaskAssign } BpmnMetaParserHelper.getApproverSpecifyValue((UserTask) flowElement) .ifPresent(s -> assigners.addAll(JSON.parseArray(s, BpmnTaskDelegateAssigner.class))); - return assigners; + + Set workspaceIds = assigners.stream() + .map(BpmnTaskDelegateAssigner::getTenantId) + .filter(StringUtils::hasText) + .map(Long::parseLong) + .collect(Collectors.toSet()); + + List personIds = assigners.stream() + .map(BpmnTaskDelegateAssigner::getPersonId) + .filter(StringUtils::hasText) + .map(Long::parseLong) + .collect(Collectors.toList()); + + OrganizationalNodeUserSearchReq searchReq = new OrganizationalNodeUserSearchReq(); + searchReq.setWorkspaceIds(workspaceIds); + searchReq.setPersonIdList(personIds); + List onlineUsers = parseApiResult(() -> organizationalNodeUserApi.list(searchReq), "查询指定人员是否在职", + "cn.axzo.maokai.api.client.OrganizationalNodeUserApi.list", searchReq); + + // 只要有在职的人,不会走审批人为空 + if (ListUtils.emptyIfNull(onlineUsers).stream().anyMatch(i -> Objects.equals(i.getIsDelete(), 0L))) { + return assigners; + } + + return Collections.emptyList(); } } From 3af8822bbae4a2cf1f5b339219bd4f1f2320c8ad Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 17:02:15 +0800 Subject: [PATCH 113/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BA=BA=EF=BC=8C=E4=BC=9A=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E4=BA=8C=E6=96=B9=E6=8E=A5=E5=8F=A3=E6=9F=A5=E8=AF=A2=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E6=98=AF=E5=90=A6=E5=9C=A8=E8=81=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransferToAdminTaskAssigneeSelector.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 76c29318e..d39497a57 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -57,8 +57,10 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne protected List invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { + Optional approverScope = BpmnMetaParserHelper.getApproverScope((UserTask) flowElement); Optional optSpecify = BpmnMetaParserHelper.getApproverSpecify((UserTask) flowElement); - if (optSpecify.isPresent() + if (optSpecify.isPresent() && approverScope.isPresent() + && Objects.equals(ApproverScopeEnum.projectWorkspace, approverScope.get()) && !Objects.equals(ApproverSpecifyEnum.position, optSpecify.get()) && !Objects.equals(ApproverSpecifyEnum.role, optSpecify.get())) { return Collections.emptyList(); @@ -78,12 +80,11 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne ListFlowTaskAssignerReq req = builder.workspaceAdmin(false).build(); req.setProcInstId(execution.getProcessInstanceId()); req.setCooperateTypes(getCooperationTypes(flowElement)); - BpmnMetaParserHelper.getApproverScope((UserTask) flowElement) - .ifPresent(i -> { - if (Objects.equals(i, ApproverScopeEnum.projectWorkspace)) { - req.setWorkspaceAdmin(true); - } - }); + approverScope.ifPresent(i -> { + if (Objects.equals(i, ApproverScopeEnum.projectWorkspace)) { + req.setWorkspaceAdmin(true); + } + }); List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", From 3fcc1e5bbb7681e0f1a07fdc91ec50fe84a5e174 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 17:52:17 +0800 Subject: [PATCH 114/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E4=BA=BA=E4=B8=BB=E7=AE=A1=E7=9A=84=E6=89=BE?= =?UTF-8?q?=E8=B6=85=E7=AE=A1=E7=9A=84=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/TransferToAdminTaskAssigneeSelector.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index d39497a57..1db454aa7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -11,6 +11,7 @@ import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson.JSON; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; @@ -27,6 +28,9 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_WORKSPACE_TYPE; + /** * 基于"转交给管理员"查询审批人 * @@ -59,6 +63,7 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne Optional approverScope = BpmnMetaParserHelper.getApproverScope((UserTask) flowElement); Optional optSpecify = BpmnMetaParserHelper.getApproverSpecify((UserTask) flowElement); + // 如果是项目部,且审批人指定的配法不是岗位或角色,则默认直接返回空集合,走转交管理员后为空的最终兜底逻辑 if (optSpecify.isPresent() && approverScope.isPresent() && Objects.equals(ApproverScopeEnum.projectWorkspace, approverScope.get()) && !Objects.equals(ApproverSpecifyEnum.position, optSpecify.get()) @@ -80,6 +85,12 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne ListFlowTaskAssignerReq req = builder.workspaceAdmin(false).build(); req.setProcInstId(execution.getProcessInstanceId()); req.setCooperateTypes(getCooperationTypes(flowElement)); + // 发起人主管找其超管时,需要将发起人的数据包装进 orgScope + if (Objects.equals(ApproverSpecifyEnum.initiatorLeader, optSpecify.get())) { + BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(execution.getVariable(INTERNAL_INITIATOR, String.class)); + Integer workspaceType = execution.getVariable(INTERNAL_PROCESS_WORKSPACE_TYPE, Integer.class); + req.setOrgScopes(Lists.newArrayList(new ListFlowTaskAssignerReq.OrgScope(workspaceType, Long.parseLong(initiator.getTenantId()), Long.parseLong(initiator.getOuId()), null))); + } approverScope.ifPresent(i -> { if (Objects.equals(i, ApproverScopeEnum.projectWorkspace)) { req.setWorkspaceAdmin(true); From c80f57a0fe319275bcc4d26c5fb6824ae5b3f98d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 20:33:56 +0800 Subject: [PATCH 115/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=A6=BB=E8=81=8C=E7=9A=84=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/BasedFixedPersonTaskAssigneeSelector.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java index aba25252e..ddda169b8 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java @@ -72,7 +72,9 @@ public class BasedFixedPersonTaskAssigneeSelector extends AbstractBpmnTaskAssign "cn.axzo.maokai.api.client.OrganizationalNodeUserApi.list", searchReq); // 只要有在职的人,不会走审批人为空 - if (ListUtils.emptyIfNull(onlineUsers).stream().anyMatch(i -> Objects.equals(i.getIsDelete(), 0L))) { + if (ListUtils.emptyIfNull(onlineUsers).stream().filter(i -> Objects.equals(i.getIsDelete(), 0L)) + .anyMatch(u-> assigners.stream().anyMatch(i-> Objects.equals(i.getPersonId(), String.valueOf(u.getPersonId())) + && Objects.equals(i.getOuId(), String.valueOf(u.getOrganizationalUnitId()))))) { return assigners; } From 1c5acfd728623e1b816efdc5497a29784ded42e3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 24 Sep 2024 21:06:19 +0800 Subject: [PATCH 116/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=A6=BB=E8=81=8C=E7=9A=84=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/TransferToAdminTaskAssigneeSelector.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 1db454aa7..ec554f0ae 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -12,6 +12,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; @@ -84,7 +85,11 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne } ListFlowTaskAssignerReq req = builder.workspaceAdmin(false).build(); req.setProcInstId(execution.getProcessInstanceId()); - req.setCooperateTypes(getCooperationTypes(flowElement)); + if(Objects.equals(ApproverScopeEnum.entWorkspace, approverScope.get()) && Objects.equals(ApproverSpecifyEnum.fixedPerson,optSpecify.get())) { + req.setCooperateTypes(Sets.newHashSet(1,2,3,4,5,6,7,8,9,11,30)); + } else { + req.setCooperateTypes(getCooperationTypes(flowElement)); + } // 发起人主管找其超管时,需要将发起人的数据包装进 orgScope if (Objects.equals(ApproverSpecifyEnum.initiatorLeader, optSpecify.get())) { BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(execution.getVariable(INTERNAL_INITIATOR, String.class)); From 1a90c25252be733b8bae654a54497fdd4b6ab1f8 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 10:08:27 +0800 Subject: [PATCH 117/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=A4=9A=E4=BA=BA=E6=97=B6=E7=9A=84=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/BpmnProcessInstanceServiceImpl.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index 4dc5eaf92..f2f939a33 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1140,7 +1140,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 比对抄送人 logVO.getTaskDetails().stream() .filter(i -> Objects.equals(i.getNodeType(), NODE_CARBON_COPY)) - .flatMap(i -> i.getForecastAssignees().stream()) + .flatMap(i -> ListUtils.emptyIfNull(i.getForecastAssignees()).stream()) .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) .findAny() .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CARBON_COPY))); @@ -1210,9 +1210,19 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic getFutureTasks(forecasting, tasks); // 处理是否加密 handleEncrypt(dto.getEncrypt(), tasks); + // reset field forecastAssignees Empty to null; + resetCollectionToNull(tasks); return tasks; } + private void resetCollectionToNull(List tasks) { + tasks.forEach(i-> { + if(ListUtils.emptyIfNull(i.getForecastAssignees()).isEmpty()) { + i.setForecastAssignees(null); + } + }); + } + private static void handleEncrypt(Boolean encrypt, List tasks) { if (Boolean.FALSE.equals(encrypt)) { return; @@ -1230,7 +1240,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic i.setOperationDesc("已处理"); } // 统一将多人节点数据全部置空 - i.setForecastAssignees(Collections.emptyList()); + i.setForecastAssignees(null); // 统一将签名数据置空 i.setSignatureUrl(null); }); From 8db08de5fe0e9e0f68730282742f2cb8bdb7510a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 11:33:19 +0800 Subject: [PATCH 118/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=BD=AC=E4=BA=A4=E7=AE=A1=E7=90=86=E6=97=B6=E7=9A=84=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20outype=20=E7=9A=84=20NPE=20=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/TransferToAdminTaskAssigneeSelector.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index ec554f0ae..1b7823e41 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -20,6 +20,7 @@ import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.util.Arrays; import java.util.Collections; @@ -118,6 +119,7 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne .map(value -> JSON.parseArray(value, String.class) .stream().map(JSON::parseObject) .map(i -> i.getString("type")) + .filter(StringUtils::hasText) .collect(Collectors.toList()) .stream() .flatMap(s -> Arrays.stream(s.split(","))) From f5a4479b5757537dac7788f98a62482dee43b0e7 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 13:51:56 +0800 Subject: [PATCH 119/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E4=BA=8C=E6=96=B9=E6=8E=A5=E5=8F=A3=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/BasedFixedPersonTaskAssigneeSelector.java | 2 +- .../controller/delegate/BasedIdentityTaskAssigneeSelector.java | 2 +- .../delegate/BasedInitiatorLeaderTaskAssigneeSelector.java | 2 +- .../controller/delegate/BasedPositionTaskAssigneeSelector.java | 2 +- .../controller/delegate/BasedRoleTaskAssigneeSelector.java | 2 +- .../delegate/TransferToAdminTaskAssigneeSelector.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java index ddda169b8..f14c69599 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java @@ -69,7 +69,7 @@ public class BasedFixedPersonTaskAssigneeSelector extends AbstractBpmnTaskAssign searchReq.setWorkspaceIds(workspaceIds); searchReq.setPersonIdList(personIds); List onlineUsers = parseApiResult(() -> organizationalNodeUserApi.list(searchReq), "查询指定人员是否在职", - "cn.axzo.maokai.api.client.OrganizationalNodeUserApi.list", searchReq); + "cn.axzo.maokai.api.client.OrganizationalNodeUserApi#list", searchReq); // 只要有在职的人,不会走审批人为空 if (ListUtils.emptyIfNull(onlineUsers).stream().filter(i -> Objects.equals(i.getIsDelete(), 0L)) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java index 7caae6178..918c871ba 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityTaskAssigneeSelector.java @@ -58,7 +58,7 @@ public class BasedIdentityTaskAssigneeSelector extends AbstractBpmnTaskAssigneeS List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerByIdentity(req), "审批节点: " + flowElement.getId() + ", 通过身份查询审批人", - "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerByIdentity", req); + "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerByIdentity", req); if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java index 2b8b8aa0d..38030c7b3 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java @@ -71,7 +71,7 @@ public class BasedInitiatorLeaderTaskAssigneeSelector extends AbstractBpmnTaskAs List flowTaskAssigners = parseApiResult(() -> organizationalNodeUserApi.listFlowTaskAssigner(req), "审批节点: " + flowElement.getId() + ", 通过发起人主管查询审批人", - "cn.axzo.maokai.api.client.OrganizationalNodeUserApi.listFlowTaskAssigner", req); + "cn.axzo.maokai.api.client.OrganizationalNodeUserApi#listFlowTaskAssigner", req); if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java index cadd12405..c7c6403c8 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java @@ -64,7 +64,7 @@ public class BasedPositionTaskAssigneeSelector extends AbstractBpmnTaskAssigneeS List flowTaskAssigners = parseApiResult(() -> organizationalNodeUserApi.listFlowTaskAssigner(req), "审批节点: " + flowElement.getId() + ", 通过岗位查询审批人", - "cn.axzo.maokai.api.client.OrganizationalNodeUserApi.listFlowTaskAssigner", req); + "cn.axzo.maokai.api.client.OrganizationalNodeUserApi#listFlowTaskAssigner", req); if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java index 14d42252d..d95e677fd 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleTaskAssigneeSelector.java @@ -91,7 +91,7 @@ public class BasedRoleTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelec req.setProcInstId(execution.getProcessInstanceId()); List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerByRoles(req), "审批节点: " + flowElement.getId() + ", 通过角色查询审批人", - "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerByRoles", req); + "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerByRoles", req); if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 1b7823e41..6c7c84393 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -105,7 +105,7 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne List flowTaskAssigners = parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", - "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerAdminV2", req); + "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2", req); if (CollUtil.isEmpty(flowTaskAssigners)) { From 450fa726b452ba97061387297bc1472e8db5613e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 14:34:48 +0800 Subject: [PATCH 120/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=B6=85=E7=AE=A1=E5=BC=82=E5=B8=B8=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- workflow-engine-core/pom.xml | 8 ++++ .../EngineExecutionStartListener.java | 8 ++++ .../workflow/core}/util/DingTalkUtils.java | 44 ++++++++++++------- workflow-engine-server/pom.xml | 5 +-- .../workflow/server/alter/DingTalkAlter.java | 3 +- .../common/annotation/ReporterType.java | 2 +- .../AbstractBpmnTaskAssigneeSelector.java | 3 +- 7 files changed, 49 insertions(+), 24 deletions(-) rename {workflow-engine-server/src/main/java/cn/axzo/workflow/server/common => workflow-engine-core/src/main/java/cn/axzo/workflow/core}/util/DingTalkUtils.java (72%) diff --git a/workflow-engine-core/pom.xml b/workflow-engine-core/pom.xml index 00e1896d7..5b41b626b 100644 --- a/workflow-engine-core/pom.xml +++ b/workflow-engine-core/pom.xml @@ -89,17 +89,25 @@ cn.axzo.workflow workflow-engine-api + cn.axzo.workflow workflow-engine-common + org.apache.maven maven-artifact + jakarta.servlet jakarta.servlet-api + + + com.aliyun + alibaba-dingtalk-service-sdk + diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java index 4c60faea3..6a19b0d77 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java @@ -4,6 +4,7 @@ import cn.axzo.workflow.common.constant.BpmnConstants; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; @@ -14,6 +15,7 @@ import cn.axzo.workflow.core.deletage.BpmnTaskDelegate; import cn.axzo.workflow.core.deletage.MockTaskAssigneeSelector; import cn.axzo.workflow.core.engine.cmd.CustomAbortProcessInstanceAsyncCmd; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import cn.axzo.workflow.core.util.DingTalkUtils; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; @@ -27,6 +29,7 @@ import org.flowable.engine.delegate.ExecutionListener; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -42,6 +45,7 @@ import java.util.Objects; import java.util.Optional; import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER; +import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK; import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE; import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_TYPE; @@ -72,6 +76,8 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDup @Slf4j public class EngineExecutionStartListener implements ExecutionListener { private static final long serialVersionUID = 1L; + @Value("${spring.profiles.active}") + private String profile; @Resource @Deprecated private ObjectProvider bpmTaskDelegate; @@ -187,6 +193,8 @@ public class EngineExecutionStartListener implements ExecutionListener { assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask, execution, true)); if (CollectionUtils.isEmpty(assigners)) { + CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class); + DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes); BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO(); abortDTO.setProcessInstanceId(execution.getProcessInstanceId()); abortDTO.setReason("转交管理员失败,系统中止"); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java similarity index 72% rename from workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java rename to workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java index 7fa8f7838..55f0c5e92 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/DingTalkUtils.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/util/DingTalkUtils.java @@ -1,4 +1,4 @@ -package cn.axzo.workflow.server.common.util; +package cn.axzo.workflow.core.util; import cn.axzo.workflow.common.model.dto.AlterDTO; import cn.hutool.json.JSONObject; @@ -30,7 +30,7 @@ import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC; public class DingTalkUtils { private static final String dingtalk_robot_webhook = "https://oapi.dingtalk" + - ".com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; + ".com/robot/send?access_token=341ee2907f3ebc15dc495fb7771a646230058710999fec7838066c109849878e"; private static final Map ENV_URL_MAPPING = new HashMap<>(); private static final Map WEB_URL_MAPPING = new HashMap<>(); @@ -74,11 +74,11 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice " + title + ", Env: " + profile); String text = "#### [" + profile + "]" + title + "\n" + - "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + - "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : - throwable.getCause().getMessage()) + " \n\n" + - "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + - "> ##### 调用方服务名称:" + invokeServerName + " \n"; + "> 入参: " + JSONUtil.toJsonStr(req) + "\n\n" + + "> ###### 异常信息: " + JSONUtil.toJsonStr(Objects.isNull(throwable.getCause()) ? throwable.getMessage() : + throwable.getCause().getMessage()) + " \n\n" + + "> ##### traceId: " + MDC.get(CTX_LOG_ID_MDC) + " \n" + + "> ##### 调用方服务名称:" + invokeServerName + " \n"; String deadLetterStacktrace = getDeadLetterStacktrace(profile, req); text = text + (StringUtils.hasText(deadLetterStacktrace) ? "> ##### [点击查看异常明细](" + deadLetterStacktrace + ") \n" : ""); markdown.setText(text); @@ -107,9 +107,9 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice 请求二方接口慢 URL, Env: " + profile); markdown.setText("#### [" + profile + "]请求二方接口过慢\n" + - "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + - "> 请求参数: " + JSONUtil.toJsonStr(requestParam) + "\n\n" + - "> ###### 结果: " + JSONUtil.toJsonStr(responseBody) + " \n"); + "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + + "> 请求参数: " + JSONUtil.toJsonStr(requestParam) + "\n\n" + + "> ###### 结果: " + JSONUtil.toJsonStr(responseBody) + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } @@ -121,8 +121,8 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice API 处理耗时报告, Env: " + profile); markdown.setText("#### [" + profile + "]API 处理耗时报告\n" + - "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + - "> ###### 标识: " + uniqueId + " \n"); + "> 接口地址: " + apiUrl + ",经过了" + time + "秒\n\n" + + "> ###### 标识: " + uniqueId + " \n"); request.setMarkdown(markdown); sendDingTalk(request); } @@ -143,9 +143,9 @@ public class DingTalkUtils { OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); markdown.setTitle("Notice 业务节点长时间停止告警, Env: " + profile); markdown.setText("#### [" + profile + "]业务节点长时间停止\n" + - "> 节点相关信息: " + JSONUtil.toJsonStr(alterDTO) + "\n\n" + - "> ##### [点击查看审批日志](" + getWebUrl(profile) + "/#/workflow/examples?processInstanceId=" + processInstanceId + ") \n\n" + - "> ##### 提示:如果以上地址提示未登录,请在对应环境 OMS 系统登录后并点击审批管理的功能后,再使用。或者复制实例 ID 到 OMS 中手动查询"); + "> 节点相关信息: " + JSONUtil.toJsonStr(alterDTO) + "\n\n" + + "> ##### [点击查看审批日志](" + getWebUrl(profile) + "/#/workflow/examples?processInstanceId=" + processInstanceId + ") \n\n" + + "> ##### 提示:如果以上地址提示未登录,请在对应环境 OMS 系统登录后并点击审批管理的功能后,再使用。或者复制实例 ID 到 OMS 中手动查询"); request.setMarkdown(markdown); OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); at.setAtMobiles(atMobiles); @@ -153,4 +153,18 @@ public class DingTalkUtils { request.setAt(at); // sendDingTalk(request); } + + public static void sendDingTalkForTransferToAdminError(String profile, String processInstanceId, String taskDefinitionKey, Object orgScopes) { + OapiRobotSendRequest request = new OapiRobotSendRequest(); + request.setMsgtype("markdown"); + OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); + markdown.setTitle("Notice 转交管理员后的审批人为空, Env: " + profile); + markdown.setText("#### [" + profile + "]转交管理员后的审批人为空\n" + + "> 流程实例 ID: " + processInstanceId + "\n\n" + + "> 节点参数(节点 ID): " + taskDefinitionKey + "\n\n" + + "> OrgScopes 参数信息: " + JSONUtil.toJsonStr(orgScopes) + "\n\n" + + "> ##### 提示:仅作为提示信息,不代表是异常"); + request.setMarkdown(markdown); + sendDingTalk(request); + } } diff --git a/workflow-engine-server/pom.xml b/workflow-engine-server/pom.xml index 8b5c81251..46a9a9419 100644 --- a/workflow-engine-server/pom.xml +++ b/workflow-engine-server/pom.xml @@ -103,10 +103,7 @@ cn.axzo.oss oss-http-api - - com.aliyun - alibaba-dingtalk-service-sdk - + com.taobao.arthas arthas-spring-boot-starter diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java index bee558102..9a6fd7516 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/alter/DingTalkAlter.java @@ -3,12 +3,11 @@ package cn.axzo.workflow.server.alter; import cn.axzo.workflow.common.model.dto.AlterDTO; import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.listener.Alter; -import cn.axzo.workflow.server.common.util.DingTalkUtils; +import cn.axzo.workflow.core.util.DingTalkUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.util.List; /** * 钉钉告警实现 diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java index 034fdfd47..f7cb0d71f 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/annotation/ReporterType.java @@ -1,6 +1,6 @@ package cn.axzo.workflow.server.common.annotation; -import cn.axzo.workflow.server.common.util.DingTalkUtils; +import cn.axzo.workflow.core.util.DingTalkUtils; import lombok.extern.slf4j.Slf4j; import static cn.axzo.workflow.server.common.aspectj.RepeatSubmitAspect.argsArrayToString; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 2a6045c7c..140a42798 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -13,9 +13,8 @@ import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeProcessor; -import cn.axzo.workflow.core.engine.listener.EngineExecutionStartListener; import cn.axzo.workflow.core.engine.model.NoticeFlowElement; -import cn.axzo.workflow.server.common.util.DingTalkUtils; +import cn.axzo.workflow.core.util.DingTalkUtils; import cn.hutool.core.lang.Assert; import cn.hutool.http.HttpStatus; import cn.hutool.json.JSONUtil; From cbc0e3836642f3ed8f88a017fc888660f602ffbd Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 15:41:04 +0800 Subject: [PATCH 121/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=8C=89=E9=92=AE=E9=80=BB=E8=BE=91=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/BpmnProcessInstanceLogVO.java | 6 + .../impl/BpmnProcessInstanceServiceImpl.java | 449 +++++++++--------- 2 files changed, 236 insertions(+), 219 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java index aa580364d..8ddcb835b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/BpmnProcessInstanceLogVO.java @@ -124,6 +124,12 @@ public class BpmnProcessInstanceLogVO { @ApiModelProperty(value = "指定人访问实例日志时,计算其流程应该有权限操作的按钮", notes = "流程有权限,不代表待办消息中一定能看到按钮") private List currentUserButtons; + /** + * 需要隐藏的自定义按钮集合 + */ + @ApiModelProperty(value = "需要隐藏的自定义按钮集合") + private List customHiddenButtons; + /** * 是否支持批量审批 */ diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index f2f939a33..b099d99ef 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -219,7 +219,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic public HistoricProcessInstance getProcessInstanceByBusinessKey(String businessKey, @Nullable String tenantId, @Nullable Boolean hasVariable) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); + historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); if (Boolean.TRUE.equals(hasVariable)) { query.includeProcessVariables(); } @@ -232,7 +232,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Override public BpmPageResult getMyProcessInstancePage(@Valid BpmnProcessInstanceMyPageReqVO dto) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(dto.getTenantId()); + historyService.createHistoricProcessInstanceQuery().processInstanceTenantId(dto.getTenantId()); if (StringUtils.isNotBlank(dto.getName())) { query.processInstanceName(dto.getName()); } @@ -261,7 +261,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic query.processInstanceTenantId(dto.getTenantId()); } List instances = query.orderByProcessInstanceStartTime().desc() - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); if (CollectionUtils.isEmpty(instances)) { return BpmPageResult.empty(); @@ -370,11 +370,11 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置流程名字 ProcessInstanceBuilder instanceBuilder = runtimeService.createProcessInstanceBuilder() - .processDefinitionId(definition.getId()) - .businessKey(dto.getBusinessKey()) - .variables(dto.getVariables()) - .name(name) - .overrideProcessDefinitionTenantId(dto.getTenantId()); + .processDefinitionId(definition.getId()) + .businessKey(dto.getBusinessKey()) + .variables(dto.getVariables()) + .name(name) + .overrideProcessDefinitionTenantId(dto.getTenantId()); ProcessInstance instance; if (dto.getAsync()) { // 异步开始 @@ -390,8 +390,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Override public String createProcessInstanceWithForm(BpmnProcessInstanceCreateWithFormDTO dto) { BpmnProcessDefinitionVO definition = - processDefinitionService.getActiveProcessDefinitionByKey(dto.getProcessDefinitionKey(), - dto.getInitiator().getTenantId()); + processDefinitionService.getActiveProcessDefinitionByKey(dto.getProcessDefinitionKey(), + dto.getInitiator().getTenantId()); // 校验流程定义 if (definition == null) { throw new WorkflowEngineException(PROCESS_DEFINITION_KEY_NOT_EXISTS, dto.getProcessDefinitionKey()); @@ -405,11 +405,11 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置流程实例的开始人,参考https://wenku.baidu.com/view/5538062e7a563c1ec5da50e2524de518964bd3f9.html Authentication.setAuthenticatedUserId(dto.getInitiator().buildAssigneeId()); String name = StringUtils.isNotBlank(dto.getCustomProcessInstanceName()) ? - dto.getCustomProcessInstanceName() - : definition.getName(); + dto.getCustomProcessInstanceName() + : definition.getName(); ProcessInstance instance = runtimeService.startProcessInstanceWithForm(definition.getId(), - dto.getOutcome(), dto.getVariables(), name); + dto.getOutcome(), dto.getVariables(), name); Authentication.setAuthenticatedUserId(null); return instance.getProcessInstanceId(); } @@ -426,7 +426,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic commandExecutor.execute(new CustomCancelProcessInstanceAsyncCmd(dto)); } else { commandExecutor.execute(new CustomCancelProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(), - dto.getReason(), dto.getInitiator(), extAxHiTaskInstService)); + dto.getReason(), dto.getInitiator(), extAxHiTaskInstService)); } return true; } @@ -439,7 +439,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic commandExecutor.execute(new CustomAbortProcessInstanceAsyncCmd(dto)); } else { commandExecutor.execute(new CustomAbortProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(), - dto.getReason(), extAxHiTaskInstService)); + dto.getReason(), extAxHiTaskInstService)); } return true; } @@ -488,13 +488,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery query = historyService.createNativeHistoricProcessInstanceQuery(); String tableName = managementService.getTableName(HistoricProcessInstance.class); StringBuilder baseQuerySql = new StringBuilder("SELECT RES.*, ") - .append("DEF.KEY_ as PROC_DEF_KEY_,") - .append("DEF.NAME_ as PROC_DEF_NAME_,") - .append("DEF.VERSION_ as PROC_DEF_VERSION_,") - .append("DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_") - .append(" FROM ").append(tableName) - .append(" RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_") - .append(" WHERE 1 = 1"); + .append("DEF.KEY_ as PROC_DEF_KEY_,") + .append("DEF.NAME_ as PROC_DEF_NAME_,") + .append("DEF.VERSION_ as PROC_DEF_VERSION_,") + .append("DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_") + .append(" FROM ").append(tableName) + .append(" RES LEFT OUTER JOIN ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_") + .append(" WHERE 1 = 1"); if (StringUtils.isNotBlank(dto.getProcessInstanceId())) { List ids = Lists.newArrayList(dto.getProcessInstanceId().replaceAll(" ", "").split(",")); baseQuerySql.append(" AND RES.PROC_INST_ID_ IN ("); @@ -546,8 +546,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic baseQuerySql.append(" ORDER BY RES.START_TIME_ DESC "); List instances = query.sql(baseQuerySql.toString()) - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), - dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), + dto.getPageSize()); baseQuerySql.replace(7, 163, "count(1)"); NativeHistoricProcessInstanceQuery countSqlQuery = query.sql(baseQuerySql.toString()); @@ -556,8 +556,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } List processingInstanceIds = - instances.stream().filter(i -> Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) - .map(HistoricProcessInstance::getId).distinct().collect(Collectors.toList()); + instances.stream().filter(i -> Objects.equals(PROCESSING.getStatus(), i.getBusinessStatus())) + .map(HistoricProcessInstance::getId).distinct().collect(Collectors.toList()); Map> instanceFlowElementMap = new HashMap<>(); processingInstanceIds.forEach(i -> { // 查询每个流程推测出来的总节点数 @@ -570,13 +570,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic Map leastEndActivityMap = getInstanceLastActivity(processingInstanceIds); List categories = instances.stream().map(HistoricProcessInstance::getProcessDefinitionKey) - .distinct().collect(Collectors.toList()); + .distinct().collect(Collectors.toList()); Map categoryLabelMap = categoryService.listByValue(BPM_MODEL_CATEGORY, categories) - .stream().collect(Collectors.toMap(CategoryItemVO::getValue, Function.identity(), (s, t) -> s)); + .stream().collect(Collectors.toMap(CategoryItemVO::getValue, Function.identity(), (s, t) -> s)); List vos = instanceAdminPageItemConverter.toVos(instances, - instanceFlowElementMap, liveActivityMap, leastEndActivityMap, - categoryLabelMap); + instanceFlowElementMap, liveActivityMap, leastEndActivityMap, + categoryLabelMap); return new BpmPageResult<>(vos, countSqlQuery.count()); } @@ -594,10 +594,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic String tableName = managementService.getTableName(ActivityInstanceEntity.class); StringBuilder querySql = new StringBuilder(); querySql.append("SELECT * FROM (") - .append("SELECT *, ROW_NUMBER() OVER (PARTITION BY PROC_INST_ID_ ORDER BY START_TIME_ DESC) AS rn ") - .append(" FROM ") - .append(tableName) - .append(" WHERE PROC_INST_ID_ in ("); + .append("SELECT *, ROW_NUMBER() OVER (PARTITION BY PROC_INST_ID_ ORDER BY START_TIME_ DESC) AS rn ") + .append(" FROM ") + .append(tableName) + .append(" WHERE PROC_INST_ID_ in ("); for (int i = 0; i < processInstanceIds.size(); i++) { querySql.append("#{processInstanceId_").append(i).append("}"); if (i < processInstanceIds.size() - 1) { @@ -611,8 +611,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } querySql.append(") as t WHERE rn = 1"); return nativeQuery.sql(querySql.toString()).list().stream() - .collect(Collectors.toMap(ActivityInstance::getProcessInstanceId, Function.identity(), - (s, t) -> s)); + .collect(Collectors.toMap(ActivityInstance::getProcessInstanceId, Function.identity(), + (s, t) -> s)); } @@ -628,7 +628,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic public HistoricProcessInstance getHistoricProcessInstanceByBusinessKey(String businessKey, String tenantId) { HistoricProcessInstanceQuery query = - historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); + historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -642,7 +642,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic processInstance = getProcessInstance(dto.getProcessInstanceId(), dto.getTenantId(), dto.getHasVariable()); } else if (StringUtils.isNotBlank(dto.getBusinessKey())) { processInstance = getProcessInstanceByBusinessKey(dto.getBusinessKey(), dto.getTenantId(), - dto.getHasVariable()); + dto.getHasVariable()); } // 获得流程实例 @@ -651,10 +651,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } // 获得流程定义 BpmnProcessDefinitionVO processDefinition = processDefinitionService - .getProcessDefinition(processInstance.getProcessDefinitionId()); + .getProcessDefinition(processInstance.getProcessDefinitionId()); if (Objects.isNull(processDefinition)) { throw new WorkflowEngineException(PROCESS_DEFINITION_ID_NOT_EXISTS, - processInstance.getProcessDefinitionId()); + processInstance.getProcessDefinitionId()); } Object tempAssigner = null; @@ -668,10 +668,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } else { List variableInstances = historyService.createHistoricVariableInstanceQuery() - .processInstanceId(processInstance.getId()).list(); + .processInstanceId(processInstance.getId()).list(); for (HistoricVariableInstance i : variableInstances) { if (Objects.equals(i.getVariableName(), INTERNAL_INITIATOR) || Objects.equals(i.getVariableName(), - OLD_INTERNAL_INITIATOR)) { + OLD_INTERNAL_INITIATOR)) { tempAssigner = i.getValue(); } if (Objects.equals(i.getVariableName(), WORKFLOW_ENGINE_VERSION)) { @@ -685,17 +685,17 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } List runningTasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()) - .active() - .orderByTaskCreateTime() - .desc() - .list(); + .active() + .orderByTaskCreateTime() + .desc() + .list(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); return instanceConverter.toVo(processInstance, processDefinition, - getButtonConfig(bpmnModel.getMainProcess()), - getProcessApproveConf(bpmnModel.getMainProcess()), - BpmnTaskDelegateAssigner.toObjectCompatible(tempAssigner), version, categoryService.get(BPM_MODEL_CATEGORY, - processInstance.getProcessDefinitionKey()), runningTasks); + getButtonConfig(bpmnModel.getMainProcess()), + getProcessApproveConf(bpmnModel.getMainProcess()), + BpmnTaskDelegateAssigner.toObjectCompatible(tempAssigner), version, categoryService.get(BPM_MODEL_CATEGORY, + processInstance.getProcessDefinitionKey()), runningTasks); } /** @@ -706,7 +706,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic */ public Map getProcessInstanceMap(Set ids) { return BpmnCollectionUtils.convertMap(getProcessInstances(ids), - ProcessInstance::getProcessInstanceId); + ProcessInstance::getProcessInstanceId); } @@ -718,19 +718,19 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic */ public Map getHistoricProcessInstanceMap(Set ids) { return BpmnCollectionUtils.convertMap(getHistoricProcessInstances(ids), - HistoricProcessInstance::getId); + HistoricProcessInstance::getId); } public List getHistoricProcessInstances(Set ids) { HistoricProcessInstanceQuery historicProcessInstanceQuery = - historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids); + historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids); return historicProcessInstanceQuery.list(); } @Override public ObjectNode getProcessInstanceGraphical(String processInstanceId, @Nullable String tenantId) { HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery() - .processInstanceId(processInstanceId); + .processInstanceId(processInstanceId); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -741,7 +741,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); List activityInstances = - historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); Set completedActivityInstances = new HashSet<>(); Set currentElements = new HashSet<>(); @@ -756,13 +756,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } // Gather completed flows List completedFlows = graphicService.gatherCompletedFlows(completedActivityInstances, currentElements - , bpmnModel); + , bpmnModel); Set completedElements = new HashSet<>(completedActivityInstances); completedElements.addAll(completedFlows); ObjectNode displayNode = graphicService.processProcessElements(bpmnModel, completedElements, currentElements, - new ArrayList<>(), processInstanceId); + new ArrayList<>(), processInstanceId); if (!CollectionUtils.isEmpty(completedActivityInstances)) { ArrayNode completedActivities = displayNode.putArray("completedActivities"); for (String completed : completedActivityInstances) { @@ -793,30 +793,30 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic StringBuilder baseQuerySql = new StringBuilder("SELECT a.* FROM ").append(tableName).append(" a"); if (StringUtils.isNotBlank(dto.getCategory())) { baseQuerySql.append(" LEFT JOIN ACT_RE_PROCDEF b ON a.PROC_DEF_ID_ = b.ID_ ") - .append(sqlConnectors(baseQuerySql)) - .append(" b.CATEGORY_ = #{category}"); + .append(sqlConnectors(baseQuerySql)) + .append(" b.CATEGORY_ = #{category}"); query.parameter("category", dto.getCategory()); } if (StringUtils.isNotBlank(dto.getSearchKey())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" (a.BUSINESS_KEY_ LIKE #{searchKey}") - .append(" or") - .append(" a.NAME_ LIKE #{searchKey})"); + .append(" (a.BUSINESS_KEY_ LIKE #{searchKey}") + .append(" or") + .append(" a.NAME_ LIKE #{searchKey})"); query.parameter("searchKey", "%" + dto.getSearchKey() + "%"); } if (StringUtils.isNotBlank(dto.getResult())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.BUSINESS_STATUS_ = #{result}"); + .append(" a.BUSINESS_STATUS_ = #{result}"); query.parameter("result", dto.getResult()); } if (Objects.nonNull(dto.getTenantId())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.TENANT_ID_ = #{tenantId}"); + .append(" a.TENANT_ID_ = #{tenantId}"); query.parameter("tenantId", dto.getTenantId()); } if (!CollectionUtils.isEmpty(dto.getUserIds())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.START_USER_ID_ in ("); + .append(" a.START_USER_ID_ in ("); for (int i = 0; i < dto.getUserIds().size(); i++) { baseQuerySql.append("#{userId").append(i).append("}"); if (i < dto.getUserIds().size() - 1) { @@ -828,20 +828,20 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } if (Objects.nonNull(dto.getStartBeginTime()) && Objects.nonNull(dto.getStartEndTime())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.START_TIME_ between #{startBeginTime} and #{startEndTime}"); + .append(" a.START_TIME_ between #{startBeginTime} and #{startEndTime}"); query.parameter("startBeginTime", dto.getStartBeginTime()); query.parameter("startEndTime", dto.getStartEndTime()); } if (Objects.nonNull(dto.getFinishedBeginTime()) && Objects.nonNull(dto.getFinishedEndTime())) { baseQuerySql.append(sqlConnectors(baseQuerySql)) - .append(" a.END_TIME_ between #{finishedBeginTime} and #{finishedEndTime}"); + .append(" a.END_TIME_ between #{finishedBeginTime} and #{finishedEndTime}"); query.parameter("finishedBeginTime", dto.getFinishedBeginTime()); query.parameter("finishedEndTime", dto.getFinishedEndTime()); } baseQuerySql.append(" ORDER BY a.START_TIME_ DESC"); NativeHistoricProcessInstanceQuery dataSqlQuery = query.sql(baseQuerySql.toString()); List instances = dataSqlQuery - .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); + .listPage((dto.getPageNo() - 1) * dto.getPageSize(), dto.getPageSize()); if (CollectionUtils.isEmpty(instances)) { return BpmPageResult.empty(); } @@ -849,17 +849,17 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery countSqlQuery = query.sql(countSql(baseQuerySql)); if (StringUtils.isNotBlank(dto.getCategory())) { return new BpmPageResult(historicProcessInstanceConverter.toVos(instances, dto.getCategory()), - countSqlQuery.count()); + countSqlQuery.count()); } else { Set procDefIds = new HashSet<>(); instances.forEach(i -> procDefIds.add(i.getProcessDefinitionId())); Map defCategoryMap = - repositoryService.createProcessDefinitionQuery().processDefinitionIds(procDefIds).list() - .stream().collect(Collectors.toMap(ProcessDefinition::getId, - ProcessDefinition::getCategory, (s, t) -> s)); + repositoryService.createProcessDefinitionQuery().processDefinitionIds(procDefIds).list() + .stream().collect(Collectors.toMap(ProcessDefinition::getId, + ProcessDefinition::getCategory, (s, t) -> s)); List vos = new ArrayList<>(); instances.forEach(i -> vos.add(historicProcessInstanceConverter.toVo(i, - defCategoryMap.getOrDefault(i.getProcessDefinitionId(), "")))); + defCategoryMap.getOrDefault(i.getProcessDefinitionId(), "")))); return new BpmPageResult(vos, countSqlQuery.count()); } } @@ -879,7 +879,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic Boolean checkAliveThrowException) { if (Objects.isNull(instance)) { instance = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId).singleResult(); + .processInstanceId(processInstanceId).singleResult(); if (Objects.isNull(instance)) { if (checkAliveThrowException) { throw new WorkflowEngineException(RUNNING_INSTANCE_ONLY_FORECAST); @@ -898,7 +898,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic @Override public List getProcessInstanceNodeFilterForecast(String processInstanceId, String tenantId, List nodeDefinitionKeys) { ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId); + .processInstanceId(processInstanceId); if (StringUtils.isNotBlank(tenantId)) { query.processInstanceTenantId(tenantId); } @@ -916,27 +916,27 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic List resultList = new ArrayList<>(flowElements.size()); // 发起人节点,也是一个 UserTask 节点, 所以这里默认就包含了发起人节点 flowElements.stream() - .filter(i -> (i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)) - .forEach(i -> { - ProcessNodeDetailVO node = new ProcessNodeDetailVO(); - node.setForecastAssigners(Collections.emptyList()); - // 每个节点设置的按钮配置 - getButtonConfig(bpmnModel.getMainProcess(), i.getId()).ifPresent(node::setButtonConf); - // 设置审批方式 - getApprovalMethod(i).ifPresent(node::setApprovalMethod); - getNodeType(i).ifPresent(node::setNodeType); - if (Objects.equals(NODE_STARTER.getType(), i.getId())) { - node.setNodeType(NODE_STARTER); - } - node.setNodeMode(GENERAL); - node.setId(i.getId()).setName(i.getName()); - if (i instanceof UserTask) { - parseUserTask(processInstanceId, (UserTask) i, node, nodeDefinitionKeys); - } else if (i instanceof ServiceTask) { - parseServiceTask(processInstanceId, (ServiceTask) i, node, nodeDefinitionKeys); - } - resultList.add(node); - }); + .filter(i -> (i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)) + .forEach(i -> { + ProcessNodeDetailVO node = new ProcessNodeDetailVO(); + node.setForecastAssigners(Collections.emptyList()); + // 每个节点设置的按钮配置 + getButtonConfig(bpmnModel.getMainProcess(), i.getId()).ifPresent(node::setButtonConf); + // 设置审批方式 + getApprovalMethod(i).ifPresent(node::setApprovalMethod); + getNodeType(i).ifPresent(node::setNodeType); + if (Objects.equals(NODE_STARTER.getType(), i.getId())) { + node.setNodeType(NODE_STARTER); + } + node.setNodeMode(GENERAL); + node.setId(i.getId()).setName(i.getName()); + if (i instanceof UserTask) { + parseUserTask(processInstanceId, (UserTask) i, node, nodeDefinitionKeys); + } else if (i instanceof ServiceTask) { + parseServiceTask(processInstanceId, (ServiceTask) i, node, nodeDefinitionKeys); + } + resultList.add(node); + }); return resultList; } @@ -947,10 +947,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic return; } getCarbonCopyConfigs(i).ifPresent(carbons -> - node.setForecastAssigners(springProcessEngineConfiguration.getCommandExecutor() - .execute(new CustomCarbonCopyUserSelectorCmd(processInstanceId, carbons, - i, engineExecutionStartListener, - historicTaskInstanceConverter, serviceVersion)))); + node.setForecastAssigners(springProcessEngineConfiguration.getCommandExecutor() + .execute(new CustomCarbonCopyUserSelectorCmd(processInstanceId, carbons, + i, engineExecutionStartListener, + historicTaskInstanceConverter, serviceVersion)))); } private void parseUserTask(String processInstanceId, UserTask i, ProcessNodeDetailVO node, List skipTaskDefinitionKeys) { @@ -958,10 +958,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 设置审批模式, if (i.getBehavior() instanceof MultiInstanceActivityBehavior) { MultiInstanceActivityBehavior behavior = - (MultiInstanceActivityBehavior) i.getBehavior(); + (MultiInstanceActivityBehavior) i.getBehavior(); node.setNodeMode(Objects.equals(AND_SIGN_EXPRESSION, - behavior.getCompletionCondition()) ? - AND : OR); + behavior.getCompletionCondition()) ? + AND : OR); } else { node.setNodeMode(BpmnFlowNodeMode.GENERAL); } @@ -972,9 +972,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic if (Objects.equals(node.getApprovalMethod(), human)) { // 推测当前节点的审批人,并且如果审批人为空,也会根据审批人为空的策略去找人 List forecastAssigners = - springProcessEngineConfiguration.getCommandExecutor() - .execute(new CustomForecastUserTaskAssigneeCmd(processInstanceId, - i, engineExecutionStartListener)); + springProcessEngineConfiguration.getCommandExecutor() + .execute(new CustomForecastUserTaskAssigneeCmd(processInstanceId, + i, engineExecutionStartListener)); node.setForecastAssigners(forecastAssigners); if (CollectionUtils.isEmpty(forecastAssigners)) { getApproverEmptyHandleType(i).ifPresent(emptyHandleType -> { @@ -999,7 +999,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic NativeHistoricProcessInstanceQuery query = historyService.createNativeHistoricProcessInstanceQuery(); String tableName = managementService.getTableName(HistoricProcessInstance.class); String baseQuerySql = "SELECT DISTINCT TENANT_ID_ FROM " + tableName + - " WHERE TENANT_ID_ IS NOT NULL AND TENANT_ID_ != '' AND TENANT_ID_ != 0 AND TENANT_ID_ != 'NULL'"; + " WHERE TENANT_ID_ IS NOT NULL AND TENANT_ID_ != '' AND TENANT_ID_ != 0 AND TENANT_ID_ != 'NULL'"; NativeHistoricProcessInstanceQuery dataSqlQuery = query.sql(baseQuerySql); return ListUtils.emptyIfNull(dataSqlQuery.list()).stream().map(HistoricProcessInstance::getTenantId).distinct().collect(Collectors.toList()); } @@ -1010,18 +1010,18 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getApprover().setOuId(null); } List list = taskService.createTaskQuery() - .processInstanceId(dto.getProcessInstanceId()) - .taskAssigneeLikeIgnoreCase(dto.getApprover().buildAssigneeId()) - .active() - .list(); + .processInstanceId(dto.getProcessInstanceId()) + .taskAssigneeLikeIgnoreCase(dto.getApprover().buildAssigneeId()) + .active() + .list(); return !CollectionUtils.isEmpty(list); } @Override public BpmnProcessInstanceLogVO getProcessInstanceLog(BpmnProcessInstanceLogQueryDTO dto) { HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() - .processInstanceId(dto.getProcessInstanceId()) - .includeProcessVariables().singleResult(); + .processInstanceId(dto.getProcessInstanceId()) + .includeProcessVariables().singleResult(); if (Objects.isNull(historicProcessInstance)) { throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, dto.getProcessInstanceId()); } @@ -1029,18 +1029,18 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic ExtAxProcessLog query = new ExtAxProcessLog(); query.setProcessInstanceId(dto.getProcessInstanceId()); List logs = processLogService.genericQuery(query).stream() - .sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder()))) - .collect(Collectors.toList()); + .sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder()))) + .collect(Collectors.toList()); List forecasting = new ArrayList<>(); // 只有还在运行中的实例才需要推测后续节点 if (Objects.equals(historicProcessInstance.getBusinessStatus(), PROCESSING.getStatus())) { ProcessInstance instance = runtimeService.createProcessInstanceQuery() - .processInstanceId(dto.getProcessInstanceId()) - .includeProcessVariables() - .singleResult(); + .processInstanceId(dto.getProcessInstanceId()) + .includeProcessVariables() + .singleResult(); logs.stream().reduce((f, s) -> s).ifPresent(e -> forecasting.addAll( - getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false)) + getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false)) ); } @@ -1048,25 +1048,25 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic Map variables = historicProcessInstance.getProcessVariables(); BpmnProcessInstanceLogVO logVO = BpmnProcessInstanceLogVO.builder() - .id(historicProcessInstance.getId()) - .name(historicProcessInstance.getName()) - .result(BpmnProcessInstanceResultEnum.valueOfStatus(historicProcessInstance.getBusinessStatus())) - .startTime(historicProcessInstance.getStartTime()) - .endTime(historicProcessInstance.getEndTime()) - .processDefinitionKey(historicProcessInstance.getProcessDefinitionKey()) - .processDefinitionId(historicProcessInstance.getProcessDefinitionId()) - .businessKey(historicProcessInstance.getBusinessKey()) - .businessStatus(historicProcessInstance.getBusinessStatus()) - .initiator(BpmnTaskDelegateAssigner.toObjectCompatible(Optional.ofNullable(variables.getOrDefault(INTERNAL_INITIATOR, null)) - .orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)))) - .tenantId(historicProcessInstance.getTenantId()) - .agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false)) - .taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto)) - .defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf())) - .supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation()) - .userAgreeSignature(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getUserAgreeSignature()) - .workflowEngineVersion((String) variables.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121)) - .build(); + .id(historicProcessInstance.getId()) + .name(historicProcessInstance.getName()) + .result(BpmnProcessInstanceResultEnum.valueOfStatus(historicProcessInstance.getBusinessStatus())) + .startTime(historicProcessInstance.getStartTime()) + .endTime(historicProcessInstance.getEndTime()) + .processDefinitionKey(historicProcessInstance.getProcessDefinitionKey()) + .processDefinitionId(historicProcessInstance.getProcessDefinitionId()) + .businessKey(historicProcessInstance.getBusinessKey()) + .businessStatus(historicProcessInstance.getBusinessStatus()) + .initiator(BpmnTaskDelegateAssigner.toObjectCompatible(Optional.ofNullable(variables.getOrDefault(INTERNAL_INITIATOR, null)) + .orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)))) + .tenantId(historicProcessInstance.getTenantId()) + .agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false)) + .taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto)) + .defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf())) + .supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation()) + .userAgreeSignature(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getUserAgreeSignature()) + .workflowEngineVersion((String) variables.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121)) + .build(); categoryService.get(BPM_MODEL_CATEGORY, historicProcessInstance.getProcessDefinitionKey()).ifPresent(category -> { @@ -1082,7 +1082,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic private void calcAuthorizedButtons(BpmnProcessInstanceLogVO logVO, BpmnTaskDelegateAssigner visitor) { List authorizedButtons = new ArrayList<>(); if (Objects.nonNull(logVO.getDefaultButtonConf()) - && CollectionUtils.isEmpty(logVO.getDefaultButtonConf().getCarbonCopy())) { + && CollectionUtils.isEmpty(logVO.getDefaultButtonConf().getCarbonCopy())) { authorizedButtons.addAll(logVO.getDefaultButtonConf().getCarbonCopy()); } @@ -1092,60 +1092,71 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic // 运行到的当前节点的按钮配置 logVO.getTaskDetails().stream() - .filter(i -> Objects.equals(PROCESSING, i.getResult())) - .findFirst() - .ifPresent(i -> logVO.setCalculatingButtonConf(i.getButtonConf())); + .filter(i -> Objects.equals(PROCESSING, i.getResult())) + .findFirst() + .ifPresent(i -> logVO.setCalculatingButtonConf(i.getButtonConf())); // 比对发起人 if (Objects.nonNull(logVO.getInitiator()) && - (Objects.equals(logVO.getInitiator().buildAssigneeId_1_2_1(), le130Assignee) - || logVO.getInitiator().buildAssigneeId().contains(ge130Assignee))) { + (Objects.equals(logVO.getInitiator().buildAssigneeId_1_2_1(), le130Assignee) + || logVO.getInitiator().buildAssigneeId().contains(ge130Assignee))) { authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_INITIATOR)); } // 比对当前审批人 logVO.getTaskDetails().stream().filter(i -> Objects.equals(PROCESSING, i.getResult()) - || (Objects.equals(DELETED, i.getResult()) && Objects.isNull(i.getEndTime()))) - .findFirst() - .map(i -> { - List list = new ArrayList<>(); - if (Objects.nonNull(i.getAssigneeSnapshot())) { - list.add(i.getAssigneeSnapshot()); - } - if (!CollectionUtils.isEmpty(i.getForecastAssignees())) { - list.addAll(i.getForecastAssignees()); - } - return list; - }) - .orElse(Collections.emptyList()) - .stream() - .filter(Objects::nonNull) - .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) - .findAny() - .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CURRENT))); + || (Objects.equals(DELETED, i.getResult()) && Objects.isNull(i.getEndTime()))) + .findFirst() + .map(i -> { + List list = new ArrayList<>(); + if (Objects.nonNull(i.getAssigneeSnapshot())) { + list.add(i.getAssigneeSnapshot()); + } + if (!CollectionUtils.isEmpty(i.getForecastAssignees())) { + list.addAll(i.getForecastAssignees()); + } + return list; + }) + .orElse(Collections.emptyList()) + .stream() + .filter(Objects::nonNull) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CURRENT))); // 比对历史审批人 logVO.getTaskDetails().stream() - .filter(i -> Objects.equals(i.getNodeType(), NODE_TASK) || Objects.equals(i.getNodeType(), NODE_BUSINESS)) - .filter(i -> !Objects.equals(PROCESSING, i.getResult())) - .map(BpmnTaskInstanceLogVO::getAssigneeSnapshot) - .filter(Objects::nonNull) - .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) - .findAny() - .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_HISTORY))); + .filter(i -> Objects.equals(i.getNodeType(), NODE_TASK) || Objects.equals(i.getNodeType(), NODE_BUSINESS)) + .filter(i -> !Objects.equals(PROCESSING, i.getResult())) + .map(BpmnTaskInstanceLogVO::getAssigneeSnapshot) + .filter(Objects::nonNull) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_HISTORY))); // 比对抄送人 logVO.getTaskDetails().stream() - .filter(i -> Objects.equals(i.getNodeType(), NODE_CARBON_COPY)) - .flatMap(i -> ListUtils.emptyIfNull(i.getForecastAssignees()).stream()) - .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) - .findAny() - .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CARBON_COPY))); + .filter(i -> Objects.equals(i.getNodeType(), NODE_CARBON_COPY)) + .flatMap(i -> ListUtils.emptyIfNull(i.getForecastAssignees()).stream()) + .filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee)) + .findAny() + .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CARBON_COPY))); } + logVO.setCurrentUserButtons(authorizedButtons); + // 有权限访问的自定义按钮 + List customButtonKeys = authorizedButtons.stream() + .filter(i -> Objects.equals(i.getType(), "CUSTOM")) + .map(BpmnButtonMetaInfo::getBtnKey) + .distinct().collect(Collectors.toList()); + List customButtons = logVO.getDefaultButtonConf().getInitiator().stream() + .filter(i -> Objects.equals(i.getType(), "CUSTOM")) + .filter(i -> !customButtonKeys.contains(i.getBtnKey())) + .collect(Collectors.toList()); + logVO.setCustomHiddenButtons(customButtons); } /** @@ -1202,8 +1213,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic BpmnProcessInstanceLogQueryDTO dto) { List tasks = new ArrayList<>(); Map> attachmentByTaskMap = - taskService.getProcessInstanceAttachments(processInstanceId).stream() - .collect(Collectors.groupingBy(Attachment::getTaskId)); + taskService.getProcessInstanceAttachments(processInstanceId).stream() + .collect(Collectors.groupingBy(Attachment::getTaskId)); // 已完成的和进行中的 getHistoricTasks(logs, tasks, attachmentByTaskMap, dto.getVisitor()); // 未来节点 @@ -1216,8 +1227,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } private void resetCollectionToNull(List tasks) { - tasks.forEach(i-> { - if(ListUtils.emptyIfNull(i.getForecastAssignees()).isEmpty()) { + tasks.forEach(i -> { + if (ListUtils.emptyIfNull(i.getForecastAssignees()).isEmpty()) { i.setForecastAssignees(null); } }); @@ -1249,13 +1260,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic private static void getFutureTasks(List forecasting, List tasks) { ListUtils.emptyIfNull(forecasting).forEach(e -> { BpmnTaskInstanceLogVO build = BpmnTaskInstanceLogVO.builder() - .taskDefinitionKey(e.getId()) - .name(e.getName()) - .approvalMethod(e.getApprovalMethod()) - .nodeType(e.getNodeType()) - .nodeMode(e.getNodeMode()) - .forecastAssignees(e.getForecastAssigners()) - .build(); + .taskDefinitionKey(e.getId()) + .name(e.getName()) + .approvalMethod(e.getApprovalMethod()) + .nodeType(e.getNodeType()) + .nodeMode(e.getNodeMode()) + .forecastAssignees(e.getForecastAssigners()) + .build(); if (Objects.nonNull(e.getApprovalMethod())) { switch (e.getApprovalMethod()) { case bizSpecify: @@ -1292,14 +1303,14 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic BpmnTaskDelegateAssigner visitor) { ListUtils.emptyIfNull(logs).forEach(e -> { Optional processingTask = tasks.stream().filter(i -> Objects.equals(PROCESSING, i.getResult())) - .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); + .filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny(); if (processingTask.isPresent()) { // 多实例的情况,需要合并节点 processingTask.ifPresent(i -> { List assigners = new ArrayList<>(ListUtils.emptyIfNull(i.getForecastAssignees())); - if(CollectionUtils.isEmpty(assigners)) { - if(Objects.nonNull(i.getAssigneeSnapshot())) { + if (CollectionUtils.isEmpty(assigners)) { + if (Objects.nonNull(i.getAssigneeSnapshot())) { assigners.add(i.getAssigneeSnapshot()); } } @@ -1319,31 +1330,31 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic i.setForecastAssignees(assigners); i.setButtonConf(e.getButtonConf()); // 根据当前登录人重设聚合后的节点 taskId - assigners.stream().filter(user-> Objects.equals(user.getPersonId(), visitor.getPersonId())).findFirst() - .ifPresent(user-> i.setTaskId(e.getTaskId())); + assigners.stream().filter(user -> Objects.equals(user.getPersonId(), visitor.getPersonId())).findFirst() + .ifPresent(user -> i.setTaskId(e.getTaskId())); }); } else { tasks.add(BpmnTaskInstanceLogVO.builder() - .taskId(e.getTaskId()) - .taskDefinitionKey(e.getActivityId()) - .name(e.getActivityName()) - .createTime(e.getStartTime()) - .endTime(e.getEndTime()) - .approvalMethod(ApprovalMethodEnum.valueOfType(e.getApprovalMethod())) - .nodeType(BpmnFlowNodeType.valueOfType(e.getNodeType())) - .nodeMode(BpmnFlowNodeMode.valueOfType(e.getNodeMode())) - .result(BpmnProcessInstanceResultEnum.valueOfStatus(e.getStatus())) - .operationDesc(e.getOperationDesc()) - .advice(e.getAdvice()) - .commentExt("") - .buttonConf(e.getButtonConf()) - .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) - .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) - .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) - .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : - BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))) - .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? ListUtils.emptyIfNull(e.getAssigneeFull()) : Collections.emptyList()) - .build()); + .taskId(e.getTaskId()) + .taskDefinitionKey(e.getActivityId()) + .name(e.getActivityName()) + .createTime(e.getStartTime()) + .endTime(e.getEndTime()) + .approvalMethod(ApprovalMethodEnum.valueOfType(e.getApprovalMethod())) + .nodeType(BpmnFlowNodeType.valueOfType(e.getNodeType())) + .nodeMode(BpmnFlowNodeMode.valueOfType(e.getNodeMode())) + .result(BpmnProcessInstanceResultEnum.valueOfStatus(e.getStatus())) + .operationDesc(e.getOperationDesc()) + .advice(e.getAdvice()) + .commentExt("") + .buttonConf(e.getButtonConf()) + .imageList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.image)) + .fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file)) + .signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) + .assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null : + BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0))) + .forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? ListUtils.emptyIfNull(e.getAssigneeFull()) : Collections.emptyList()) + .build()); } }); @@ -1351,15 +1362,15 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic public List getAttachmentByType(Map> attachmentByTaskMap, String taskId, AttachmentTypeEnum type) { return ListUtils.emptyIfNull(attachmentByTaskMap.get(taskId)).stream() - .filter(attachment -> Objects.equals(type.getType(), attachment.getType())) - .map(e -> AttachmentDTO.builder() - .id(e.getId()) - .type(type) - .name(e.getName()) - .description(e.getDescription()) - .url(e.getUrl()) - .build()) - .collect(Collectors.toList()); + .filter(attachment -> Objects.equals(type.getType(), attachment.getType())) + .map(e -> AttachmentDTO.builder() + .id(e.getId()) + .type(type) + .name(e.getName()) + .description(e.getDescription()) + .url(e.getUrl()) + .build()) + .collect(Collectors.toList()); } } From 619b9a52a132cc1283b39534438b3dde143d275d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 25 Sep 2024 16:45:42 +0800 Subject: [PATCH 122/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StarterBroadcastMQConfiguration.java | 3 -- .../StarterFeignClientConfiguration.java | 37 ------------------- .../StarterRPCInvokeMQConfiguration.java | 2 - .../feign/ext/ComplexInvokeClient.java | 1 - .../ext/WorkflowEngineStarterDecoder.java | 1 - ...rkflowEngineStarterFeignConfiguration.java | 2 - .../MetaFeignClientEnableSelector.java | 3 -- 7 files changed, 49 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java index bb1d862c7..ec17bb5ac 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterBroadcastMQConfiguration.java @@ -19,14 +19,12 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; -import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -39,7 +37,6 @@ import java.util.List; import java.util.function.Consumer; import static cn.axzo.workflow.starter.StarterRPCInvokeMQConfiguration.DEFAULT_EVENT; -import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration.ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME; /** * 配置监听流程引擎服务广播消息的 RocketMQ 相关配置 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java index 663778004..3051b32c6 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterFeignClientConfiguration.java @@ -1,49 +1,12 @@ package cn.axzo.workflow.starter; -import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.starter.api.WorkflowCoreService; import cn.axzo.workflow.starter.api.WorkflowManageService; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.beans.factory.config.BeanExpressionResolver; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignClientFactoryBean; -import org.springframework.context.EnvironmentAware; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; /** * 根据参数动态实例化可用 Bean diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java index 7ae0fdca4..47c044d40 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/StarterRPCInvokeMQConfiguration.java @@ -27,7 +27,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -43,7 +42,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import static cn.axzo.framework.rocketmq.RocketMQEventProducer.MQ_MESSAGE_ID; -import static org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration.ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME; /** * 配置 RPC 动作的 RocketMQ 消息的发送方和消息方等配置信息 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index ac138e139..37c780918 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.starter.feign.ext; -import cn.axzo.framework.rocketmq.EventProducer; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeDTO; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java index a6aa43f3c..4600ecd24 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterDecoder.java @@ -1,7 +1,6 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.common.model.response.BpmPageResult; -import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.common.exception.WorkflowRpcInvokeException; import cn.azxo.framework.common.model.CommonResponse; import com.google.common.collect.Lists; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java index 197bb466b..1d59f0371 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/WorkflowEngineStarterFeignConfiguration.java @@ -3,7 +3,6 @@ package cn.axzo.workflow.starter.feign.ext; import cn.axzo.workflow.common.enums.RpcInvokeModeEnum; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; -import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; import cn.azxo.framework.common.constatns.Constants; import feign.Client; import feign.RequestInterceptor; @@ -16,7 +15,6 @@ import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignBuilderCustomizer; diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java index 13599b0fd..68a09346a 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java @@ -13,13 +13,10 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled; import org.springframework.cloud.openfeign.FeignClientFactoryBean; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.Environment; From fc81026ee8938f434e9492151dcf08c89f8af846 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 25 Sep 2024 17:59:39 +0800 Subject: [PATCH 123/139] =?UTF-8?q?REQ-2924-=E5=A4=84=E7=90=86=E5=90=88?= =?UTF-8?q?=E5=B9=B6master=E5=88=86=E6=94=AF=E4=BB=A3=E7=A0=81=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/core/conf/FlowableConfiguration.java | 4 ---- .../core/engine/job/AsyncActivityLeaveJobHandler.java | 3 ++- .../core/service/BpmnProcessActivityService.java | 7 ------- .../service/impl/BpmnProcessActivityServiceImpl.java | 1 - .../web/bpmn/BpmnProcessActivityController.java | 10 ---------- .../starter/feign/ext/ComplexInvokeClient.java | 1 + 6 files changed, 3 insertions(+), 23 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 64829b970..195d53b6e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -5,7 +5,6 @@ import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; import cn.axzo.workflow.core.engine.interceptor.CustomRetryInterceptor; -import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler; import cn.axzo.workflow.core.engine.job.AsyncActivityCallbackJobHandler; import cn.axzo.workflow.core.engine.job.AsyncActivityLeaveJobHandler; import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceJobHandler; @@ -99,9 +98,6 @@ public class FlowableConfiguration { configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); configuration.addCustomJobHandler(new AsyncTermNodeAlterJobHandler(refreshProperties)); configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncCancelProcessInstanceHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncAbortProcessInstanceHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncBpmnProcessActivityJobHandler(bpmnProcessActivityService)); configuration.addCustomJobHandler(new AsyncActivityLeaveJobHandler(bpmnProcessActivityService)); configuration.addCustomJobHandler(new AsyncActivityCallbackJobHandler()); // 异步任务异常重试时间间隔 diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityLeaveJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityLeaveJobHandler.java index 399513265..ea5f658eb 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityLeaveJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncActivityLeaveJobHandler.java @@ -1,6 +1,7 @@ package cn.axzo.workflow.core.engine.job; import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,6 @@ public class AsyncActivityLeaveJobHandler extends AbstractJobHandler implements public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { log.warn("AsyncActivityLeaveJobHandler exec start..."); BpmnActivityTimeoutTriggerDTO dto = JSON.parseObject(job.getCustomValues(), BpmnActivityTimeoutTriggerDTO.class); - bpmnProcessActivityService.trigger(dto.getTriggerId()); + bpmnProcessActivityService.trigger(BpmnActivityTriggerDTO.builder().async(false).triggerId(dto.getTriggerId()).build()); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java index c128dbd0e..f47c4bd2e 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessActivityService.java @@ -30,13 +30,6 @@ public interface BpmnProcessActivityService { */ void setAssignee(BpmnActivitySetAssigneeDTO dto); - /** - * 给指定实例的指定节点重设审批人 - * - * @param dto - */ - void setAssigneeAsync(BpmnActivitySetAssigneeDTO dto); - /** * 设置指定业务接口继续往下流转的触发时间 * diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java index 7bc4d8853..838bbf0ed 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessActivityServiceImpl.java @@ -12,7 +12,6 @@ import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskAsyncCmd; import cn.axzo.workflow.core.engine.cmd.CustomBizSpecifyAssigneeToTaskCmd; import cn.axzo.workflow.core.engine.cmd.CustomBusinessNodeTimeoutCallbackCmd; import cn.axzo.workflow.core.engine.cmd.CustomBusinessNodeTimeoutTriggerCmd; -import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import lombok.extern.slf4j.Slf4j; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java index beb45326f..1c4446237 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessActivityController.java @@ -1,8 +1,5 @@ package cn.axzo.workflow.server.controller.web.bpmn; -import cn.axzo.karma.client.feign.FlowSupportApi; -import cn.axzo.karma.client.model.request.PersonProfileQueryReq; -import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi; import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO; import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO; @@ -13,13 +10,11 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.service.BpmnProcessActivityService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.annotation.RepeatSubmit; -import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController; import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; -import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -32,9 +27,6 @@ import javax.annotation.Resource; import javax.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_HAS_REPEAT; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId; @@ -55,8 +47,6 @@ public class BpmnProcessActivityController extends BasicPopulateAvatarController @Resource private BpmnProcessActivityService bpmnProcessActivityService; - @Resource - private FlowSupportApi flowSupportApi; /** * 业务节点唤醒 旧版本使用的接口 diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index a2761dc16..37c780918 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.response.mq.WorkflowEngineStarterRpcInvokeD import cn.axzo.workflow.starter.WorkflowEngineStarterProperties; import cn.axzo.workflow.starter.common.exception.WorkflowEngineStarterException; import cn.axzo.workflow.starter.mq.retry.producer.RpcInvokeEventProducer; +import cn.azxo.framework.common.model.CommonResponse; import com.alibaba.fastjson.JSON; import feign.Client; import feign.MethodMetadata; From 6d48ef59e4139908587a34336332735acb8fbc04 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Wed, 25 Sep 2024 18:01:02 +0800 Subject: [PATCH 124/139] =?UTF-8?q?REQ-2924-=E6=B7=BB=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feign/ext/ComplexInvokeClient.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index 37c780918..bcb377b77 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -221,6 +221,29 @@ public class ComplexInvokeClient implements Client { } static Response.Body body = new Response.Body() { + //Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `cn.azxo.framework.common.model.CommonResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Send MQ Success'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `cn.azxo.framework.common.model.CommonResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Send MQ Success') + // at [Source: (ByteArrayInputStream); line: 1, column: 1] + // at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:389) + // at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:342) + // at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:105) + // at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:57) + // at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:61) + // at cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterDecoder.convert(WorkflowEngineStarterDecoder.java:74) + // at cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterDecoder.decode(WorkflowEngineStarterDecoder.java:42) + // at feign.AsyncResponseHandler.decode(AsyncResponseHandler.java:115) + // at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:87) + // at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) + // at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89) + // at cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterInvocationHandler.invoke(WorkflowEngineStarterInvocationHandler.java:59) + // at com.sun.proxy.$Proxy231.approveTask(Unknown Source) + // at cn.axzo.yoke.server.organizational.service.impl.UnitRegisterServiceImpl.approvedPassUpdateProcess(UnitRegisterServiceImpl.java:334) + // at cn.axzo.yoke.server.organizational.service.impl.UnitRegisterServiceImpl.approvedOuRegister(UnitRegisterServiceImpl.java:276) + // at cn.axzo.yoke.server.organizational.service.impl.UnitRegisterServiceImpl$$FastClassBySpringCGLIB$$6f84f39d.invoke() + // at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) + // at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) + // at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + // at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) + // 只设置为字符串会报错,恢复为设置成CommonResponse final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), "Send MQ Success", null)) .getBytes(UTF_8)); From 727dad23c909ddd340ed37bf26494d4198880e62 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 26 Sep 2024 10:55:31 +0800 Subject: [PATCH 125/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8A=84=E9=80=81=E8=8A=82=E7=82=B9=E7=9A=84=20ru=5Ftask=20?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomServiceTaskDelegateExpressionActivityBehavior.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index 2b9c306df..8af0b540f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -90,6 +90,8 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), execution.getCurrentActivityId(), serviceTask.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); + + taskService.complete(serviceTask.getId()); } else { log.warn("ServiceTask is null, executionId: {}, activityId: {}", execution.getId(), execution.getCurrentActivityId()); From 3da94cced2402868a91b05cd7ad64515ba28ee7b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 26 Sep 2024 13:07:32 +0800 Subject: [PATCH 126/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=B5=8B=E8=AF=95=20BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...askDelegateExpressionActivityBehavior.java | 3 +- .../EngineExecutionStartListener.java | 33 ++++++++------ .../BasedFixedPersonTaskAssigneeSelector.java | 44 ++++++++++++------- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index 8af0b540f..96f01cfaf 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -90,8 +90,7 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), execution.getCurrentActivityId(), serviceTask.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); - - taskService.complete(serviceTask.getId()); + TaskHelper.deleteTask(serviceTask, "", false, false, false); } else { log.warn("ServiceTask is null, executionId: {}, activityId: {}", execution.getId(), execution.getCurrentActivityId()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java index 6a19b0d77..9f9ecb166 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java @@ -183,6 +183,7 @@ public class EngineExecutionStartListener implements ExecutionListener { } log.info("当前节点id: [{}], name: [{}] 审批人为空, 将执行审批人为空的兜底配置!", userTask.getId(), userTask.getName()); getApproverEmptyHandleType(userTask).ifPresent(type -> { + log.info("节点兜底的配置模式:[{}]", type.getType()); switch (type) { case autoPassed: case autoRejection: @@ -192,28 +193,32 @@ public class EngineExecutionStartListener implements ExecutionListener { case transferToAdmin: assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask, execution, true)); - if (CollectionUtils.isEmpty(assigners)) { - CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class); - DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes); - BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO(); - abortDTO.setProcessInstanceId(execution.getProcessInstanceId()); - abortDTO.setReason("转交管理员失败,系统中止"); - CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor() - .execute(new CustomAbortProcessInstanceAsyncCmd(abortDTO)); - } + finalEmptyAssigneeHandle(assigners, userTask, execution); break; case specifyAssignee: - List emptyAssignees = - BpmnMetaParserHelper.getEmptyApproverSpecify(userTask) - .map(listStr -> JSON.parseArray(listStr, BpmnTaskDelegateAssigner.class)) - .orElse(Collections.emptyList()); - assigners.addAll(emptyAssignees); + assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.specifyAssignee.getType(), userTask, + execution, true)); + finalEmptyAssigneeHandle(assigners, userTask, execution); default: break; } + }); } + private void finalEmptyAssigneeHandle(List assigners, UserTask userTask, DelegateExecution execution) { + if (CollectionUtils.isEmpty(assigners)) { + CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class); + DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes); + BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO(); + abortDTO.setProcessInstanceId(execution.getProcessInstanceId()); + abortDTO.setReason("转交管理员失败,系统中止"); + CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor() + .execute(new CustomAbortProcessInstanceAsyncCmd(abortDTO)); + } + } + + /** * 根据审批人指定类型查询审批人 * diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java index f14c69599..2af518941 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedFixedPersonTaskAssigneeSelector.java @@ -5,6 +5,7 @@ import cn.axzo.maokai.api.vo.request.OrganizationalNodeUserSearchReq; import cn.axzo.maokai.api.vo.response.OrganizationalNodeUserVO; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.common.exception.WorkflowEngineException; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import com.alibaba.fastjson.JSON; import org.apache.commons.collections4.ListUtils; @@ -22,6 +23,8 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_CALC_ERROR; + /** * 基于"固定人员"查询审批人 * @@ -51,30 +54,39 @@ public class BasedFixedPersonTaskAssigneeSelector extends AbstractBpmnTaskAssign return super.select(flowElement, execution, throwException); } BpmnMetaParserHelper.getApproverSpecifyValue((UserTask) flowElement) - .ifPresent(s -> assigners.addAll(JSON.parseArray(s, BpmnTaskDelegateAssigner.class))); + .ifPresent(s -> assigners.addAll(JSON.parseArray(s, BpmnTaskDelegateAssigner.class))); Set workspaceIds = assigners.stream() - .map(BpmnTaskDelegateAssigner::getTenantId) - .filter(StringUtils::hasText) - .map(Long::parseLong) - .collect(Collectors.toSet()); + .map(BpmnTaskDelegateAssigner::getTenantId) + .filter(StringUtils::hasText) + .map(Long::parseLong) + .collect(Collectors.toSet()); List personIds = assigners.stream() - .map(BpmnTaskDelegateAssigner::getPersonId) - .filter(StringUtils::hasText) - .map(Long::parseLong) - .collect(Collectors.toList()); - - OrganizationalNodeUserSearchReq searchReq = new OrganizationalNodeUserSearchReq(); - searchReq.setWorkspaceIds(workspaceIds); - searchReq.setPersonIdList(personIds); - List onlineUsers = parseApiResult(() -> organizationalNodeUserApi.list(searchReq), "查询指定人员是否在职", + .map(BpmnTaskDelegateAssigner::getPersonId) + .filter(StringUtils::hasText) + .map(Long::parseLong) + .collect(Collectors.toList()); + List onlineUsers = new ArrayList<>(); + try { + OrganizationalNodeUserSearchReq searchReq = new OrganizationalNodeUserSearchReq(); + searchReq.setWorkspaceIds(workspaceIds); + searchReq.setPersonIdList(personIds); + onlineUsers = parseApiResult(() -> organizationalNodeUserApi.list(searchReq), "查询指定人员是否在职", "cn.axzo.maokai.api.client.OrganizationalNodeUserApi#list", searchReq); + } catch (Exception e) { + if (throwException) { + throw new WorkflowEngineException(ENGINE_USER_TASK_CALC_ERROR, flowElement.getId(), + this.getType(), e.getMessage()); + } else { + return Collections.emptyList(); + } + } // 只要有在职的人,不会走审批人为空 if (ListUtils.emptyIfNull(onlineUsers).stream().filter(i -> Objects.equals(i.getIsDelete(), 0L)) - .anyMatch(u-> assigners.stream().anyMatch(i-> Objects.equals(i.getPersonId(), String.valueOf(u.getPersonId())) - && Objects.equals(i.getOuId(), String.valueOf(u.getOrganizationalUnitId()))))) { + .anyMatch(u -> assigners.stream().anyMatch(i -> Objects.equals(i.getPersonId(), String.valueOf(u.getPersonId())) + && Objects.equals(i.getOuId(), String.valueOf(u.getOrganizationalUnitId()))))) { return assigners; } From 058562a5aefa166231399129ce7b2bd9bdb7fd65 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Thu, 26 Sep 2024 13:40:09 +0800 Subject: [PATCH 127/139] =?UTF-8?q?REQ-2924-=E6=96=B0=E5=BB=BAjob=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=9E=E4=BE=8B=E4=B8=8D=E5=AD=98=E5=9C=A8=EF=BC=8C?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E9=99=8D=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/engine/cmd/CustomCommandContext.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java index 1e70e2247..5af132216 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCommandContext.java @@ -1,12 +1,16 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; +import org.apache.ibatis.exceptions.PersistenceException; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableOptimisticLockingException; import org.flowable.common.engine.impl.interceptor.Command; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.util.Arrays; /** * 对 CommandContext 中的 WorkflowEngineException 进行日志降级 @@ -17,6 +21,8 @@ import org.slf4j.LoggerFactory; public class CustomCommandContext extends CommandContext { private static final Logger LOGGER = LoggerFactory.getLogger(CustomCommandContext.class); + private static final String[] PERSISTENCE_EXCEPTION_WARN_MESSAGE = new String[]{"act_ru_job"}; + public CustomCommandContext(Command command) { super(command); } @@ -36,6 +42,10 @@ public class CustomCommandContext extends CommandContext { LOGGER.info("Error while closing command context", exception); } else if (exception instanceof WorkflowEngineException) { LOGGER.warn("Workflow error while closing command context", exception); + } else if (exception instanceof PersistenceException && + StringUtils.hasText(exception.getMessage()) && + Arrays.stream(PERSISTENCE_EXCEPTION_WARN_MESSAGE).anyMatch(m -> exception.getMessage().contains(m))) { + LOGGER.warn("persistence error while closing command context", exception); } else { LOGGER.error("Error while closing command context", exception); From 7d61d29d953a50383a1d0647d76dc0371118ae05 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 26 Sep 2024 15:59:15 +0800 Subject: [PATCH 128/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8A=84=E9=80=81=E6=97=B6,=E5=A4=84=E7=90=86=E7=9A=84?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E4=BB=BB=E5=8A=A1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomServiceTaskDelegateExpressionActivityBehavior.java | 2 +- ...owEnginApplication.java => WorkflowEngineApplication.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename workflow-engine-server/src/main/java/cn/axzo/workflow/server/{WorkflowEnginApplication.java => WorkflowEngineApplication.java} (88%) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index 96f01cfaf..a2c26ba4b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -90,7 +90,7 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(), execution.getCurrentActivityId(), serviceTask.getId(), APPROVED), processEngineConfiguration.getEngineCfgKey()); - TaskHelper.deleteTask(serviceTask, "", false, false, false); + TaskHelper.deleteTask(serviceTask, "complete carbon", false, true, true); } else { log.warn("ServiceTask is null, executionId: {}, activityId: {}", execution.getId(), execution.getCurrentActivityId()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java similarity index 88% rename from workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java rename to workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java index 1e1d7729a..a05fdf236 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEnginApplication.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java @@ -16,9 +16,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication(exclude = RabbitAutoConfiguration.class) @EnableTransactionManagement @EnableCaching -public class WorkflowEnginApplication { +public class WorkflowEngineApplication { public static void main(String[] args) { - SpringApplication.run(WorkflowEnginApplication.class, args); + SpringApplication.run(WorkflowEngineApplication.class, args); } } From a3881085c03ee6ed479b70e100baa2e66633365b Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 26 Sep 2024 17:35:32 +0800 Subject: [PATCH 129/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=9A=84=E8=AF=84=E8=AE=BA=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/impl/BpmnProcessInstanceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java index b099d99ef..426b1f7d6 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java @@ -1082,7 +1082,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic private void calcAuthorizedButtons(BpmnProcessInstanceLogVO logVO, BpmnTaskDelegateAssigner visitor) { List authorizedButtons = new ArrayList<>(); if (Objects.nonNull(logVO.getDefaultButtonConf()) - && CollectionUtils.isEmpty(logVO.getDefaultButtonConf().getCarbonCopy())) { + && !CollectionUtils.isEmpty(logVO.getDefaultButtonConf().getCarbonCopy())) { authorizedButtons.addAll(logVO.getDefaultButtonConf().getCarbonCopy()); } From c3c38151809648419990613fe7581d5a11643092 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 26 Sep 2024 17:39:33 +0800 Subject: [PATCH 130/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=E4=B8=BA=E7=A9=BA=E5=90=8E,=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=B8=AD=E6=AD=A2=E7=9A=84=E6=96=87=E6=A1=88=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/listener/EngineExecutionStartListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java index 9f9ecb166..4a8e8ff8b 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/EngineExecutionStartListener.java @@ -193,12 +193,12 @@ public class EngineExecutionStartListener implements ExecutionListener { case transferToAdmin: assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask, execution, true)); - finalEmptyAssigneeHandle(assigners, userTask, execution); + finalEmptyAssigneeHandle(assigners, userTask, execution, "转交管理员失败,系统中止"); break; case specifyAssignee: assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.specifyAssignee.getType(), userTask, execution, true)); - finalEmptyAssigneeHandle(assigners, userTask, execution); + finalEmptyAssigneeHandle(assigners, userTask, execution, "转交指定人员失败,系统自动中止"); default: break; } @@ -206,7 +206,7 @@ public class EngineExecutionStartListener implements ExecutionListener { }); } - private void finalEmptyAssigneeHandle(List assigners, UserTask userTask, DelegateExecution execution) { + private void finalEmptyAssigneeHandle(List assigners, UserTask userTask, DelegateExecution execution, String operationDesc) { if (CollectionUtils.isEmpty(assigners)) { CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class); DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes); From 25b0bb16df9d9537d11301ff0a764ab353bee25d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sun, 29 Sep 2024 16:30:22 +0800 Subject: [PATCH 131/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E4=BD=A3?= =?UTF-8?q?=E4=BA=8C=E6=96=B9=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=E5=AE=9E=E4=BE=8B=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/BasedInitiatorLeaderTaskAssigneeSelector.java | 1 + .../controller/delegate/BasedPositionTaskAssigneeSelector.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java index 38030c7b3..3d72630af 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderTaskAssigneeSelector.java @@ -68,6 +68,7 @@ public class BasedInitiatorLeaderTaskAssigneeSelector extends AbstractBpmnTaskAs .identityId(Long.valueOf(initiator.getAssignee())) .identityType(Integer.valueOf(initiator.getAssigneeType())).build()) .build(); + req.setProcInstId(execution.getProcessInstanceId()); List flowTaskAssigners = parseApiResult(() -> organizationalNodeUserApi.listFlowTaskAssigner(req), "审批节点: " + flowElement.getId() + ", 通过发起人主管查询审批人", diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java index c7c6403c8..b799530d4 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionTaskAssigneeSelector.java @@ -60,7 +60,7 @@ public class BasedPositionTaskAssigneeSelector extends AbstractBpmnTaskAssigneeS List workerTeamScopes = ListUtils.emptyIfNull(scopeDto.getWorkerTeamScopes()).stream() .map(e -> BeanUtil.copyProperties(e, FlowTaskAssignerReq.OrgScope.class)).collect(Collectors.toList()); req.getOrgScopes().addAll(workerTeamScopes); - + req.setProcInstId(execution.getProcessInstanceId()); List flowTaskAssigners = parseApiResult(() -> organizationalNodeUserApi.listFlowTaskAssigner(req), "审批节点: " + flowElement.getId() + ", 通过岗位查询审批人", From 7b81228bdb94c36d665d149d9560c48fc79cbaf9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sun, 29 Sep 2024 17:13:36 +0800 Subject: [PATCH 132/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E8=B6=85=E7=AE=A1=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/SupportRefreshProperties.java | 6 ++++++ .../TransferToAdminTaskAssigneeSelector.java | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java index 1074a85c5..cc4db9e20 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/SupportRefreshProperties.java @@ -68,4 +68,10 @@ public class SupportRefreshProperties { @Value(value = "${workflow.alter.mobiles:}") private List alterMobiles; + + /** + * 用于控制转交管理员的 API + */ + @Value("${workflow.useNewToAdminApi:true}") + private Boolean useNewToAdminApi; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 6c7c84393..8cae870db 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -7,6 +7,7 @@ import cn.axzo.workflow.common.enums.ApproverScopeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; @@ -18,10 +19,13 @@ import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import javax.annotation.Resource; +import javax.validation.Valid; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -43,6 +47,9 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_WO @Component public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector { + @Resource + private SupportRefreshProperties supportRefreshProperties; + @Override public String getType() { return ApproverEmptyHandleTypeEnum.transferToAdmin.getType(); @@ -102,10 +109,12 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne req.setWorkspaceAdmin(true); } }); + List flowTaskAssigners = - parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), + parseApiResult(() -> supportRefreshProperties.getUseNewToAdminApi() ? flowSupportApi.listTaskAssignerAdminV2(req) : flowSupportApi.listTaskAssignerAdmin(req), "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", - "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2", req); + supportRefreshProperties.getUseNewToAdminApi() ? "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2":"cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdmin", + req); if (CollUtil.isEmpty(flowTaskAssigners)) { From d19e63c07795f8ba3a25952bd8f9cfe832e0b63e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 11:29:14 +0800 Subject: [PATCH 133/139] =?UTF-8?q?feat(REQ-2752)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransferToAdminTaskAssigneeSelector.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java index 8cae870db..75ece3542 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/TransferToAdminTaskAssigneeSelector.java @@ -70,6 +70,46 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne protected List invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { + if(supportRefreshProperties.getUseNewToAdminApi()) { + return invokeNewQuery(flowElement, execution, scopeDto); + } else { + return invokeOldQuery(flowElement, execution, scopeDto); + } + + } + + private List invokeOldQuery(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { + ListFlowTaskAssignerReq.ListFlowTaskAssignerReqBuilder builder = ListFlowTaskAssignerReq.builder(); + if (!CollectionUtils.isEmpty(scopeDto.getOrgScopes())) { + builder.orgScopes(ListUtils.emptyIfNull(scopeDto.getOrgScopes()).stream() + .map(e -> BeanUtil.copyProperties(e, ListFlowTaskAssignerReq.OrgScope.class)) + .collect(Collectors.toList())); + } + if (!CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes())) { + builder.workerTeamScopes(ListUtils.emptyIfNull(scopeDto.getOrgScopes()).stream() + .map(w -> BeanUtil.copyProperties(w, ListFlowTaskAssignerReq.OrgScope.class)) + .collect(Collectors.toList())); + } + ListFlowTaskAssignerReq req = builder.workspaceAdmin(false).build(); + BpmnMetaParserHelper.getApproverScope((UserTask) flowElement) + .ifPresent(i -> { + if (Objects.equals(i, ApproverScopeEnum.projectWorkspace)) { + req.setWorkspaceAdmin(true); + } + }); + List flowTaskAssigners = + parseApiResult(() -> flowSupportApi.listTaskAssignerAdmin(req), + "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", + "cn.axzo.karma.client.feign.FlowSupportApi.listTaskAssignerAdmin", req); + + + if (CollUtil.isEmpty(flowTaskAssigners)) { + return super.invokeService(flowElement, execution, scopeDto); + } + return BeanUtil.copyToList(flowTaskAssigners, BpmnTaskDelegateAssigner.class); + } + + private List invokeNewQuery(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) { Optional approverScope = BpmnMetaParserHelper.getApproverScope((UserTask) flowElement); Optional optSpecify = BpmnMetaParserHelper.getApproverSpecify((UserTask) flowElement); // 如果是项目部,且审批人指定的配法不是岗位或角色,则默认直接返回空集合,走转交管理员后为空的最终兜底逻辑 @@ -111,12 +151,11 @@ public class TransferToAdminTaskAssigneeSelector extends AbstractBpmnTaskAssigne }); List flowTaskAssigners = - parseApiResult(() -> supportRefreshProperties.getUseNewToAdminApi() ? flowSupportApi.listTaskAssignerAdminV2(req) : flowSupportApi.listTaskAssignerAdmin(req), + parseApiResult(() -> flowSupportApi.listTaskAssignerAdminV2(req), "审批节点: " + flowElement.getId() + ", 通过管理员查询审批人", - supportRefreshProperties.getUseNewToAdminApi() ? "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2":"cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdmin", + "cn.axzo.karma.client.feign.FlowSupportApi#listTaskAssignerAdminV2", req); - if (CollUtil.isEmpty(flowTaskAssigners)) { return super.invokeService(flowElement, execution, scopeDto); } From 97ac409d002981a392424fb4cd8764a5d91dd41e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 15:10:46 +0800 Subject: [PATCH 134/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=20ERROR=20=E7=BA=A7=E5=88=AB=E7=9A=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomServiceTaskDelegateExpressionActivityBehavior.java | 2 -- .../common/interceptor/RequestHeaderContextInterceptor.java | 2 -- .../starter/selector/MetaFeignClientEnableSelector.java | 1 - 3 files changed, 5 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java index a2c26ba4b..b7aa7ce82 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/behavior/CustomServiceTaskDelegateExpressionActivityBehavior.java @@ -62,7 +62,6 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service task.setPropagatedStageInstanceId(execution.getPropagatedStageInstanceId()); task.setName(serviceTask.getName()); TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false); - log.error("ServiceTask execute taskId: {}", task.getId()); // 添加 taskInst 扩展表数据 FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher(); @@ -82,7 +81,6 @@ public class CustomServiceTaskDelegateExpressionActivityBehavior extends Service org.flowable.engine.TaskService taskService = processEngineConfiguration.getTaskService(); TaskEntity serviceTask = (TaskEntity) taskService.createTaskQuery().taskId(task.getId()) .taskDefinitionKey(execution.getCurrentActivityId()).singleResult(); - log.error("ServiceTask leave taskId: {}", serviceTask.getId()); if (Objects.nonNull(serviceTask)) { // 用于新版日志 serviceTask.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + serviceTask.getId(), APPROVED.getStatus()); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java index 5db983a43..b37c37216 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/interceptor/RequestHeaderContextInterceptor.java @@ -61,9 +61,7 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor { return true; } else { - log.info("request uri 1 : {}", request.getRequestURI()); printHeader(request); - log.error(CLIENT_VERSION_SUPPORT.getMessage(), serviceVersion, headerClientVersion); throw new WorkflowEngineException(CLIENT_VERSION_SUPPORT, serviceVersion, headerClientVersion); } } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java index 68a09346a..627a11d7b 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/selector/MetaFeignClientEnableSelector.java @@ -126,7 +126,6 @@ public class MetaFeignClientEnableSelector implements ImportBeanDefinitionRegist @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Boolean metaFeignEnabled = environment.getProperty("workflow.engine.starter.meta-feign", Boolean.class); - log.error("current meta-feign result: {}", metaFeignEnabled); if(!Boolean.TRUE.equals(metaFeignEnabled)){ return; } From 1b11d7ce4a73b49026476f483d7ca79366d53d44 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 17:30:32 +0800 Subject: [PATCH 135/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=87=BA=E6=9D=A5=E7=9A=84=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=EF=BC=8C=E9=9C=80=E8=A6=81=E5=85=88=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E4=BF=A1=E6=81=AF=EF=BC=8C=E4=BD=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8D=E5=90=88=E8=A7=84=E5=AF=BC=E8=87=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegate/AbstractBpmnTaskAssigneeSelector.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 140a42798..eeb254cfb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -37,6 +37,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; @@ -101,6 +102,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return populateNameAndAvatar(invokeService(flowElement, execution, scopeDto), flowSupportApi, refreshProperties, applicationContext); } catch (Throwable t) { if (throwException) { + log.warn("执行查询候选审批人时发现异常, 审批节点:{}, 异常信息:{}", flowElement.getId(), t.getMessage()); if (!(t instanceof WorkflowEngineException)) { throw new WorkflowEngineException(ENGINE_USER_TASK_CALC_ERROR, flowElement.getId(), this.getType(), t.getMessage()); @@ -199,9 +201,12 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign } List personIds = assigners.stream() .map(BpmnTaskDelegateAssigner::getPersonId) - .filter(StringUtils::hasText) + .filter(e-> Objects.nonNull(e) && StringUtils.hasText(e)) .map(Long::parseLong) .distinct().collect(Collectors.toList()); + if(CollectionUtils.isEmpty(personIds)) { + return assigners; + } Map personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()), "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds) .stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s)); From 4dcd90795607b4a81ba4a6781e485c3d00b866df Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 17:38:33 +0800 Subject: [PATCH 136/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=87=BA=E6=9D=A5=E7=9A=84=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=EF=BC=8C=E9=9C=80=E8=A6=81=E5=85=88=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E4=BF=A1=E6=81=AF=EF=BC=8C=E4=BD=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8D=E5=90=88=E8=A7=84=E5=AF=BC=E8=87=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/AbstractBpmnTaskAssigneeSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index eeb254cfb..3ec8f95a1 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -201,7 +201,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign } List personIds = assigners.stream() .map(BpmnTaskDelegateAssigner::getPersonId) - .filter(e-> Objects.nonNull(e) && StringUtils.hasText(e)) + .filter(e-> Objects.nonNull(e) && StringUtils.hasText(e) && !Objects.equals("null", e)) .map(Long::parseLong) .distinct().collect(Collectors.toList()); if(CollectionUtils.isEmpty(personIds)) { From 42f11e17f3ec60ac1b572b97718d65669d9a3389 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 18:09:59 +0800 Subject: [PATCH 137/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=87=BA=E6=9D=A5=E7=9A=84=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=EF=BC=8C=E9=9C=80=E8=A6=81=E5=85=88=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E4=BF=A1=E6=81=AF=EF=BC=8C=E4=BD=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8D=E5=90=88=E8=A7=84=E5=AF=BC=E8=87=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/AbstractBpmnTaskAssigneeSelector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 3ec8f95a1..1bc229308 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -211,6 +211,9 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds) .stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s)); assigners.forEach(assigner -> { + if (!StringUtils.hasText(assigner.getPersonId()) && Objects.equals("null", assigner.getPersonId())) { + return; + } long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1")); if (personProfileMap.containsKey(personId)) { log.warn("查询到的人员信息:{}", JSON.toJSONString(personProfileMap.getOrDefault(personId, null))); From 2e289303a51f28077b88e95d1c3d3d7661e83f71 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 11 Oct 2024 18:23:15 +0800 Subject: [PATCH 138/139] =?UTF-8?q?feat(REQ-2924)=20-=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E5=A4=84=E7=90=86=20=E2=80=9Cnull=E2=80=9D=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/delegate/AbstractBpmnTaskAssigneeSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java index 1bc229308..03343e679 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/AbstractBpmnTaskAssigneeSelector.java @@ -211,7 +211,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign "根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds) .stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s)); assigners.forEach(assigner -> { - if (!StringUtils.hasText(assigner.getPersonId()) && Objects.equals("null", assigner.getPersonId())) { + if (!StringUtils.hasText(assigner.getPersonId()) || Objects.equals("null", assigner.getPersonId())) { return; } long personId = Long.parseLong(Optional.ofNullable(assigner.getPersonId()).orElse("-1")); From d6a5513c47ac12a63556e1b0888c94c036eb4603 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Mon, 28 Oct 2024 14:43:00 +0800 Subject: [PATCH 139/139] =?UTF-8?q?=E5=BC=82=E6=AD=A5=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E8=BF=94=E5=9B=9E=E5=80=BC=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/starter/feign/ext/ComplexInvokeClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java index bcb377b77..81e7c81d2 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/feign/ext/ComplexInvokeClient.java @@ -244,8 +244,8 @@ public class ComplexInvokeClient implements Client { // at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) // at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) // 只设置为字符串会报错,恢复为设置成CommonResponse - final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), "Send MQ Success", null)) - .getBytes(UTF_8)); + final ByteArrayInputStream inputStream = new ByteArrayInputStream(JSON.toJSONString(CommonResponse.success(HttpStatus.OK.value(), null, null)) + .getBytes(UTF_8)); @Override public Integer length() {