From fb790b724fd96b3bdda327d0d4420d1b0a3e65aa Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 29 Sep 2025 14:21:41 +0800 Subject: [PATCH 01/58] =?UTF-8?q?feat=20-=20=E6=96=B0=E5=A2=9E=E5=89=8D?= =?UTF-8?q?=E5=90=8E=E5=8A=A0=E7=AD=BE=E7=9A=84=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomCountersignUserTaskCmd.java | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) 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 4d5f0a7ec..1719d3d5f 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 @@ -22,6 +22,7 @@ import org.flowable.task.api.TaskInfo; 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.flowable.task.service.impl.persistence.entity.TaskEntityImpl; import org.springframework.util.CollectionUtils; import java.io.Serializable; @@ -35,6 +36,7 @@ import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; 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.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; @@ -130,9 +132,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen switch (countersignType) { case FORWARD_COUNTERSIGN: // 加签的一种方式:前加签,具体定义由后续产品需求来定 + forwardCountSign(commandContext, task, valuTargetAssigneeList); break; case BACK_COUNTERSIGN: // 加签的另一种方式 + backCountSign(commandContext, task, valuTargetAssigneeList); break; default: // 共享签,不区分顺序 @@ -143,6 +147,42 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen return null; } + /** + * 前加签 + * + * @param commandContext + * @param task + * @param valuTargetAssigneeList + */ + private void forwardCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskService taskService = processEngineConfiguration.getTaskService(); + if (task instanceof TaskEntityImpl) { + TaskEntityImpl taskEntity = (TaskEntityImpl) task; + taskEntity.setCountEnabled(true); + taskEntity.setOwner(task.getAssignee()); + taskEntity.setAssignee(null); + taskEntity.setScopeType(FORWARD_COUNTERSIGN.getType()); + taskService.saveTask(taskEntity); + + valuTargetAssigneeList.forEach(e -> { + // TODO 创建新的任务 + }); + } + } + + /** + * 后加签 + * + * @param commandContext + * @param task + * @param valuTargetAssigneeList + */ + private void backCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { + + } + /** * 共享签 * @@ -167,8 +207,19 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService, TaskService taskService, TaskEntity task) { - // 构建评论内容 - StringBuilder message = new StringBuilder("添加"); + StringBuilder message = new StringBuilder(); + switch (countersignType) { + case FORWARD_COUNTERSIGN: + message.append("向前加签,添加"); + break; + case BACK_COUNTERSIGN: + message.append("向后加签,添加"); + break; + default: + // 构建评论内容 + message.append("添加"); + break; + } int end = Math.min(targetTaskAssigneeList.size(), COUNTERSIGN_ASSIGNER_SHOW_NUMBER); //加签人员数量显示指定个数 for (int i = 0; i < end; i++) { From 678e19c3a6c3201a896b083dd6c0225af4e5f4fb Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 10 Oct 2025 15:00:36 +0800 Subject: [PATCH 02/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E5=89=8D=E5=90=8E?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=E5=8A=9F=E8=83=BD=E6=96=87=E6=A1=88=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomCountersignUserTaskCmd.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) 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 1719d3d5f..d977c674b 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 @@ -207,19 +207,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService, TaskService taskService, TaskEntity task) { - StringBuilder message = new StringBuilder(); - switch (countersignType) { - case FORWARD_COUNTERSIGN: - message.append("向前加签,添加"); - break; - case BACK_COUNTERSIGN: - message.append("向后加签,添加"); - break; - default: - // 构建评论内容 - message.append("添加"); - break; - } + StringBuilder message = new StringBuilder("添加"); int end = Math.min(targetTaskAssigneeList.size(), COUNTERSIGN_ASSIGNER_SHOW_NUMBER); //加签人员数量显示指定个数 for (int i = 0; i < end; i++) { @@ -232,6 +220,19 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen message.append("等"); } message.append(targetTaskAssigneeList.size()).append("人进行审批"); + + switch (countersignType) { + case FORWARD_COUNTERSIGN: + message.append("(前加签)"); + break; + case BACK_COUNTERSIGN: + message.append("(后加签)"); + break; + default: + message.append("(并加签)"); + break; + } + Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(), task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString())); batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee); From f461d17d2c914bed6b6c3bd23f1d4b63dffb520c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 10 Oct 2025 15:27:19 +0800 Subject: [PATCH 03/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=89=8D=E5=8A=A0=E7=AD=BE=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E8=87=AA=E6=B5=8B=E6=B5=81=E7=A8=8B=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=86=85=E9=83=A8=E6=98=AF=E5=90=A6=E6=AD=A3=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomCountersignUserTaskCmd.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 d977c674b..853c99ab4 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 @@ -11,6 +11,7 @@ import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.cfg.IdGenerator; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; @@ -27,6 +28,7 @@ import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -157,6 +159,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private void forwardCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); + IdGenerator idGenerator = processEngineConfiguration.getIdGenerator(); TaskService taskService = processEngineConfiguration.getTaskService(); if (task instanceof TaskEntityImpl) { TaskEntityImpl taskEntity = (TaskEntityImpl) task; @@ -168,6 +171,20 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen valuTargetAssigneeList.forEach(e -> { // TODO 创建新的任务 + TaskEntityImpl subTask = (TaskEntityImpl) taskService.newTask(idGenerator.getNextId()); + subTask.setName(task.getName()); + subTask.setDescription(task.getDescription()); + subTask.setCategory(task.getCategory()); + subTask.setParentTaskId(task.getId()); + subTask.setProcessDefinitionId(task.getProcessDefinitionId()); + subTask.setProcessInstanceId(task.getProcessInstanceId()); + subTask.setTaskDefinitionKey(task.getTaskDefinitionKey()); + subTask.setTaskDefinitionId(task.getTaskDefinitionId()); + subTask.setPriority(task.getPriority()); + subTask.setCreateTime(new Date()); + subTask.setTenantId(task.getTenantId()); + subTask.setAssignee(e.buildAssigneeId()); + taskService.saveTask(subTask); }); } } From 0a1be99b3e9f0542d8e86cd4b5b4f9a2357757de Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Sat, 11 Oct 2025 18:06:12 +0800 Subject: [PATCH 04/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=89=8D=E5=8A=A0=E7=AD=BE=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E8=87=AA=E6=B5=8B=E6=B5=81=E7=A8=8B=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=86=85=E9=83=A8=E6=98=AF=E5=90=A6=E6=AD=A3=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomCountersignUserTaskCmd.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 853c99ab4..90a49129c 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 @@ -38,6 +38,7 @@ import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; 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.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion; @@ -170,7 +171,6 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen taskService.saveTask(taskEntity); valuTargetAssigneeList.forEach(e -> { - // TODO 创建新的任务 TaskEntityImpl subTask = (TaskEntityImpl) taskService.newTask(idGenerator.getNextId()); subTask.setName(task.getName()); subTask.setDescription(task.getDescription()); @@ -183,8 +183,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen subTask.setPriority(task.getPriority()); subTask.setCreateTime(new Date()); subTask.setTenantId(task.getTenantId()); - subTask.setAssignee(e.buildAssigneeId()); +// subTask.setAssignee(e.buildAssigneeId()); taskService.saveTask(subTask); + // 设置快照信息 + subTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + subTask.getId(), e.toJson()); + taskService.setAssignee(subTask.getParentTaskId(), e.buildAssigneeId()); }); } } From 5187af00cdbc74dcaa08f526bc206ac458dc9102 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 14 Oct 2025 20:03:59 +0800 Subject: [PATCH 05/58] =?UTF-8?q?feat=20-=20=E5=A2=9E=E5=8A=A0=E5=90=8E?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=E7=9A=84=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=BE=85?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 2 + .../cmd/CustomCountersignUserTaskCmd.java | 54 +++++++++++++++++-- .../engine/cmd/helper/CustomTaskHelper.java | 16 +++--- .../ext/listener/TaskEntityEventHandle.java | 19 +++++-- 4 files changed, 77 insertions(+), 14 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 6d30f47be..ddfa76766 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 @@ -42,6 +42,8 @@ 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 INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN = "[_FORWARD_COUNTERSIGN_]"; + String INTERNAL_ACTIVITY_BACK_COUNTERSIGN = "[_BACK_COUNTERSIGN_]"; String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]"; String INITIATOR_SPECIFY = "[_INITIATOR_SPECIFY_]"; String SIGNATURE_COLLECTION = "[_SIGNATURE_COLLECTION_]"; 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 90a49129c..4d889fc54 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 @@ -1,6 +1,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; @@ -11,6 +12,8 @@ import cn.hutool.json.JSONUtil; 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.UserTask; import org.flowable.common.engine.impl.cfg.IdGenerator; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; @@ -32,19 +35,24 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; +import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN; 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.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion; +import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addMultiTask; 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.deleteMultiTasks; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getDuplicatePendingTasks; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount; @@ -105,6 +113,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen TaskService taskService = processEngineConfiguration.getTaskService(); TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult(); + // 1.5.4 版本,要求审批人必须回传 nodeId validTargetAssigneeNodeId(task.getProcessDefinitionId()); validTask(historicTaskInstance, task, originTaskAssignee, null); @@ -139,7 +148,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen break; case BACK_COUNTERSIGN: // 加签的另一种方式 - backCountSign(commandContext, task, valuTargetAssigneeList); + backCountSign(commandContext, historicTaskInstance, task, valuTargetAssigneeList); break; default: // 共享签,不区分顺序 @@ -162,6 +171,9 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen CommandContextUtil.getProcessEngineConfiguration(commandContext); IdGenerator idGenerator = processEngineConfiguration.getIdGenerator(); TaskService taskService = processEngineConfiguration.getTaskService(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + // 记录前加签的审批人快照 + runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN + task.getId(), valuTargetAssigneeList); if (task instanceof TaskEntityImpl) { TaskEntityImpl taskEntity = (TaskEntityImpl) task; taskEntity.setCountEnabled(true); @@ -187,7 +199,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen taskService.saveTask(subTask); // 设置快照信息 subTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + subTask.getId(), e.toJson()); - taskService.setAssignee(subTask.getParentTaskId(), e.buildAssigneeId()); + taskService.setAssignee(subTask.getId(), e.buildAssigneeId()); }); } } @@ -196,11 +208,47 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen * 后加签 * * @param commandContext + * @param historicTaskInstance * @param task * @param valuTargetAssigneeList */ - private void backCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { + private void backCountSign(CommandContext commandContext, + HistoricTaskInstance historicTaskInstance, + TaskEntity task, + List valuTargetAssigneeList) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskService taskService = processEngineConfiguration.getTaskService(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(historicTaskInstance.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); + if (flowElement instanceof UserTask) { + UserTask userTask = (UserTask) flowElement; + BpmnFlowNodeMode nodeMode = Objects.equals(userTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; + switch (nodeMode) { + case AND: + // 这里仅是加签,还需要再触发当前人的同意 + shareCountSign(commandContext, task, valuTargetAssigneeList); + break; + case OR: + // 修改审批人快照 + List originAssigners = runtimeService.getVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class); + originAssigners.removeIf(e -> !Objects.equals(e.buildAssigneeId(), originTaskAssignee.buildAssigneeId())); + originAssigners.addAll(valuTargetAssigneeList); + runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), originAssigners); + // 后加签的人 + valuTargetAssigneeList.forEach(e -> addMultiTask(commandContext, task, e)); + + // 删除除当前审批人的task + List currentTasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).taskDefinitionKey(task.getTaskDefinitionKey()).active().list(); + currentTasks.removeIf(e -> Objects.equals(e.getAssignee(), originTaskAssignee.buildAssigneeId())); + deleteMultiTasks(commandContext, currentTasks); + break; + default: + break; + } + } } /** 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 ab58d0007..7588f104f 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 @@ -1,10 +1,10 @@ package cn.axzo.workflow.core.engine.cmd.helper; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.exception.WorkflowEngineException; 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.bpmn.task.BpmnHistoricTaskInstanceVO; -import cn.axzo.workflow.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; @@ -51,6 +51,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.ASSIGNEE_HAS_BEEN_EXISTS; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_TYPE_MISMATCH; import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; @@ -61,12 +67,6 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ATTACHMENTS_VA 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; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.ASSIGNEE_HAS_BEEN_EXISTS; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE; -import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_TYPE_MISMATCH; import static org.flowable.task.api.Task.DEFAULT_PRIORITY; /** @@ -225,7 +225,7 @@ public class CustomTaskHelper { } /** - * 校验人员数量是否超过限制 + * 校验人员数量是否超过60个人的限制 * * @param runtimeService * @param taskEntity diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java index 5baa7408d..228eedc08 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java @@ -41,6 +41,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; @@ -51,12 +52,16 @@ 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_BACK_COUNTERSIGN; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN; 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.SUPPORT_UPGRADE_VARIABLE; 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.BpmnCountersignTypeEnum.BACK_COUNTERSIGN; +import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; 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; @@ -145,9 +150,17 @@ public class TaskEntityEventHandle implements EntityEventHandle { } else { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - @SuppressWarnings("unchecked") - List assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(), - INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class); + List assigneeList = new ArrayList<>(); + if (Objects.equals(FORWARD_COUNTERSIGN.getType(), taskEntity.getScopeType())) { + assigneeList.addAll(runtimeService.getVariable(taskEntity.getProcessInstanceId(), + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN + taskEntity.getParentTaskId(), List.class)); + } else if (Objects.equals(BACK_COUNTERSIGN.getType(), taskEntity.getScopeType())) { + assigneeList.addAll(runtimeService.getVariable(taskEntity.getProcessInstanceId(), + INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_BACK_COUNTERSIGN + taskEntity.getParentTaskId(), List.class)); + } else { + assigneeList.addAll(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 -> { ExtAxProcessLog queryLog = new ExtAxProcessLog(); From c8238ba1bac0f7390c098ed124500c9decf51184 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 15 Oct 2025 20:46:11 +0800 Subject: [PATCH 06/58] =?UTF-8?q?feat=20-=20=E5=A2=9E=E5=8A=A0=E5=89=8D?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=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 --- .../common/code/ConvertorRespCode.java | 2 + .../common/constant/BpmnConstants.java | 5 + .../common/enums/BpmnFlowNodeMode.java | 1 + .../converter/json/UserTaskJsonConverter.java | 4 +- .../cmd/CustomCountersignUserTaskCmd.java | 68 +++---- .../cmd/helper/CustomBpmnModelHelper.java | 178 ++++++++++++++++++ .../engine/cmd/helper/CustomTaskHelper.java | 8 +- 7 files changed, 225 insertions(+), 41 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/ConvertorRespCode.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/ConvertorRespCode.java index 073d3e6b6..bf6a142e3 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/ConvertorRespCode.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/ConvertorRespCode.java @@ -21,6 +21,8 @@ public enum ConvertorRespCode implements IModuleRespCode { CONVERTOR_OPERATION_NUMBER_TYPE_ERROR("006", "条件节点(数字)运算符【{}】暂不支持"), CONVERTOR_OPERATION_RADIO_TYPE_ERROR("007", "条件节点(单选)运算符【{}】暂不支持"), CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR("008", "条件节点(复选)运算符【{}】暂不支持"), + CREATE_BPMN_USER_TASK_ERROR("009", "创建 UserTask 失败, 不支持的节点模式【{}】"), + CREATE_BPMN_PRE_SIGN_ERROR("010", "创建前加签节点失败,原因:【{}】"), ; private final String code; 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 ddfa76766..524d25c88 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 @@ -47,6 +47,7 @@ public interface BpmnConstants { String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]"; String INITIATOR_SPECIFY = "[_INITIATOR_SPECIFY_]"; String SIGNATURE_COLLECTION = "[_SIGNATURE_COLLECTION_]"; + String FORWARD_COUNTERSIGN_COUNT = "[_FORWARD_COUNTERSIGN_COUNT_]"; String PROCESS_PREFIX = "Flowable"; @Deprecated String OLD_TASK_ASSIGNEE_SKIP_FLAT = "taskSkip"; @@ -264,4 +265,8 @@ public interface BpmnConstants { * 提级审批变量标识 */ String SUPPORT_UPGRADE_VARIABLE = "[_SUPPORT_UPGRADE_]"; + /** + * 前加签节点 ID 片段 + */ + String FORWARD_ACTIVITY_FRAGMENT = "[forward_sign]"; } 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 00bad8570..803613b1c 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 @@ -8,6 +8,7 @@ public enum BpmnFlowNodeMode { GENERAL("GENERAL", "普通节点"), OR("OR", "或签节点"), AND("AND", "会签节点"), + SEQUENCE("SEQUENCE", "顺序节点"), EXCEPTIONAL("EXCEPTIONAL", "异常"), ; diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java index 02d58e8b2..79547bb07 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java @@ -686,7 +686,7 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { * @param node * @param userTask */ - private static void setExecutionListeners(BpmnJsonNode node, UserTask userTask) { + public static void setExecutionListeners(BpmnJsonNode node, UserTask userTask) { List executionListeners = new ArrayList<>(); // 设置执行监听 @@ -725,7 +725,7 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { * * @param userTask */ - private static void setTaskListeners(UserTask userTask) { + public static void setTaskListeners(UserTask userTask) { List taskListeners = new ArrayList<>(); // 设置任务监听 FlowableListener taskListener = new FlowableListener(); 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 4d889fc54..68449a29a 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 @@ -5,6 +5,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.exception.WorkflowEngineException; 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.CustomBpmnModelHelper; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.engine.model.AddComment; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; @@ -13,25 +14,24 @@ 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.Process; import org.flowable.bpmn.model.UserTask; -import org.flowable.common.engine.impl.cfg.IdGenerator; 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.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.flowable.task.api.TaskInfo; 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.flowable.task.service.impl.persistence.entity.TaskEntityImpl; import org.springframework.util.CollectionUtils; import java.io.Serializable; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -42,10 +42,9 @@ import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER; -import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN; +import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT; +import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_COUNTERSIGN_COUNT; 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.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addMultiTask; @@ -169,39 +168,34 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private void forwardCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); - IdGenerator idGenerator = processEngineConfiguration.getIdGenerator(); - TaskService taskService = processEngineConfiguration.getTaskService(); - RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - // 记录前加签的审批人快照 - runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + INTERNAL_ACTIVITY_FORWARD_COUNTERSIGN + task.getId(), valuTargetAssigneeList); - if (task instanceof TaskEntityImpl) { - TaskEntityImpl taskEntity = (TaskEntityImpl) task; - taskEntity.setCountEnabled(true); - taskEntity.setOwner(task.getAssignee()); - taskEntity.setAssignee(null); - taskEntity.setScopeType(FORWARD_COUNTERSIGN.getType()); - taskService.saveTask(taskEntity); - valuTargetAssigneeList.forEach(e -> { - TaskEntityImpl subTask = (TaskEntityImpl) taskService.newTask(idGenerator.getNextId()); - subTask.setName(task.getName()); - subTask.setDescription(task.getDescription()); - subTask.setCategory(task.getCategory()); - subTask.setParentTaskId(task.getId()); - subTask.setProcessDefinitionId(task.getProcessDefinitionId()); - subTask.setProcessInstanceId(task.getProcessInstanceId()); - subTask.setTaskDefinitionKey(task.getTaskDefinitionKey()); - subTask.setTaskDefinitionId(task.getTaskDefinitionId()); - subTask.setPriority(task.getPriority()); - subTask.setCreateTime(new Date()); - subTask.setTenantId(task.getTenantId()); -// subTask.setAssignee(e.buildAssigneeId()); - taskService.saveTask(subTask); - // 设置快照信息 - subTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + subTask.getId(), e.toJson()); - taskService.setAssignee(subTask.getId(), e.buildAssigneeId()); - }); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); + Process process = ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId()); + UserTask originalUserTask = (UserTask) process.getFlowElement(task.getTaskDefinitionKey()); + + // 获取当前实例前加签次数 + Long forwardCounterSignCount = runtimeService.getVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, Long.class); + if (Objects.isNull(forwardCounterSignCount)) { + forwardCounterSignCount = 0L; + } else { + forwardCounterSignCount = forwardCounterSignCount + 1; } + + BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; + // 创建前加签节点 + UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, originalUserTask.getId() + FORWARD_ACTIVITY_FRAGMENT + forwardCounterSignCount, nodeMode, valuTargetAssigneeList); + // 加入模型 + process.addFlowElement(newUserTask); + + // 重新连接顺序流 (Sequence Flow) + CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask); + + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) +// .moveExecutionsToSingleActivityId(Collections.singletonList(task.getExecutionId()), newUserTask.getId()) + .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) + .changeState(); } /** diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java new file mode 100644 index 000000000..4fe429fde --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java @@ -0,0 +1,178 @@ +package cn.axzo.workflow.core.engine.cmd.helper; + +import cn.axzo.workflow.common.enums.ApprovalMethodEnum; +import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; +import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.exception.WorkflowEngineException; +import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.hutool.core.lang.UUID; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.ExtensionAttribute; +import org.flowable.bpmn.model.ExtensionElement; +import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.bpmn.parser.factory.ActivityBehaviorFactory; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.springframework.util.StringUtils; + +import java.util.List; + +import static cn.axzo.workflow.common.code.ConvertorRespCode.CREATE_BPMN_PRE_SIGN_ERROR; +import static cn.axzo.workflow.common.code.ConvertorRespCode.CREATE_BPMN_USER_TASK_ERROR; +import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_SPECIFY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DESC; +import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO; +import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONLY_ONE; +import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setExecutionListeners; +import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setTaskListeners; + +/** + * 动态操作 BPMN 定义内容的帮助类 + * + * @author wangli + * @since 2025-10-15 17:05 + */ +@Slf4j +public class CustomBpmnModelHelper { + + private CustomBpmnModelHelper() { + + } + + /** + * 创建 BPMN 中的 UserTask + * + * @param processEngineConfiguration + * @param originalUserTask + * @param nodeMode + */ + public static UserTask createUserTask(ProcessEngineConfigurationImpl processEngineConfiguration, UserTask originalUserTask, String customActivityId, BpmnFlowNodeMode nodeMode, List assigners) { + UserTask newUserTask = new UserTask(); + if (StringUtils.hasText(customActivityId)) { + newUserTask.setId(customActivityId); + } else { + newUserTask.setId(originalUserTask.getId()); + } + newUserTask.setName(originalUserTask.getName()); + newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点前加签生成"); + + MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); + loopCharacteristics.setInputDataItem(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId()); + loopCharacteristics.setElementVariable("assigneeName"); + newUserTask.setLoopCharacteristics(loopCharacteristics); + newUserTask.setAssignee("${assigneeName}"); + + switch (nodeMode) { + case AND: + loopCharacteristics.setSequential(false); + loopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION); + break; + case OR: + loopCharacteristics.setSequential(false); + loopCharacteristics.setCompletionCondition(OR_SIGN_EXPRESSION_ONLY_ONE); + break; + case SEQUENCE: + loopCharacteristics.setSequential(true); + loopCharacteristics.setCompletionCondition(AND_SIGN_EXPRESSION); + break; + default: + throw new WorkflowEngineException(CREATE_BPMN_USER_TASK_ERROR, nodeMode.getType()); + } + + setTaskListeners(newUserTask); + setExecutionListeners(new BpmnJsonNode(), newUserTask); + + ExtensionElement approvalMethodElement = new ExtensionElement(); + approvalMethodElement.setName(CONFIG_APPROVAL_METHOD); + + ExtensionAttribute approvalMethodValueAttribute = new ExtensionAttribute(); + approvalMethodValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE); + approvalMethodValueAttribute.setValue(ApprovalMethodEnum.human.getType()); + approvalMethodElement.addAttribute(approvalMethodValueAttribute); + + ExtensionAttribute approvalMethodDescAttribute = new ExtensionAttribute(); + approvalMethodDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC); + approvalMethodDescAttribute.setValue("审批方式"); + approvalMethodElement.addAttribute(approvalMethodDescAttribute); + newUserTask.addExtensionElement(approvalMethodElement); + + ExtensionElement approverSpecifyElement = new ExtensionElement(); + approverSpecifyElement.setName(CONFIG_APPROVER_SPECIFY); + ExtensionAttribute approverSpecifyValueAttribute = new ExtensionAttribute(); + approverSpecifyValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE); + approverSpecifyValueAttribute.setValue(ApproverSpecifyEnum.fixedPerson.getType()); + approverSpecifyElement.addAttribute(approverSpecifyValueAttribute); + ExtensionAttribute approverSpecifyDescAttribute = new ExtensionAttribute(); + approverSpecifyDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC); + approverSpecifyDescAttribute.setValue("审批人指定"); + approverSpecifyElement.addAttribute(approverSpecifyDescAttribute); + approverSpecifyElement.setElementText(JSON.toJSONString(assigners)); + newUserTask.addExtensionElement(approverSpecifyElement); + + ExtensionElement nodeTypeElement = new ExtensionElement(); + nodeTypeElement.setName(CONFIG_NODE_TYPE); + nodeTypeElement.setElementText(BpmnFlowNodeType.NODE_TASK.getType()); + newUserTask.addExtensionElement(nodeTypeElement); + + // TODO 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空 + // 审批人为空时 + ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement(); + approverEmptyHandleTypeElement.setName(CONFIG_APPROVER_EMPTY_HANDLE_TYPE); + ExtensionAttribute approverEmptyHandleTypeValueAttribute = new ExtensionAttribute(); + approverEmptyHandleTypeValueAttribute.setName(ELEMENT_ATTRIBUTE_VALUE); + approverEmptyHandleTypeValueAttribute.setValue(ApproverEmptyHandleTypeEnum.autoPassed.getType()); + approverEmptyHandleTypeElement.setElementText("[]"); + approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeValueAttribute); + + ExtensionAttribute approverEmptyHandleTypeDescAttribute = new ExtensionAttribute(); + approverEmptyHandleTypeDescAttribute.setName(ELEMENT_ATTRIBUTE_DESC); + approverEmptyHandleTypeDescAttribute.setValue("审批人为空时"); + approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeDescAttribute); + newUserTask.addExtensionElement(approverEmptyHandleTypeElement); + + ActivityBehaviorFactory activityBehaviorFactory = processEngineConfiguration.getActivityBehaviorFactory(); + UserTaskActivityBehavior userTaskActivityBehavior = activityBehaviorFactory.createUserTaskActivityBehavior(newUserTask); + // TODO 这里设置的 userTaskActivityBehavior 似乎是不对的。需要 + ParallelMultiInstanceBehavior behavior = activityBehaviorFactory.createParallelMultiInstanceBehavior(newUserTask, userTaskActivityBehavior); + + behavior.setCollectionVariable(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId()); + behavior.setCollectionElementVariable("assigneeName"); + behavior.setCompletionCondition(loopCharacteristics.getCompletionCondition()); + newUserTask.setBehavior(behavior); + return newUserTask; + } + + public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask newUserTask) { + // 1. 找到所有指向原始节点的输入流 + List incomingFlows = originalUserTask.getIncomingFlows(); + if (incomingFlows.isEmpty()) { + throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输入流,无法进行前加签"); + } + + // 2. 将这些输入流的目标从 originalUserTask 修改为 newUserTask + for (SequenceFlow incomingFlow : incomingFlows) { + incomingFlow.setTargetRef(newUserTask.getId()); + // 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可 + } + + // 3. 创建一个新的顺序流,从 newUserTask 指向 originalUserTask + SequenceFlow newSequenceFlow = new SequenceFlow(); + newSequenceFlow.setId("pre_sign_dynamic" + UUID.fastUUID()); + newSequenceFlow.setSourceRef(newUserTask.getId()); + newSequenceFlow.setTargetRef(originalUserTask.getId()); + process.addFlowElement(newSequenceFlow); + } +} 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 7588f104f..b202b9ccb 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 @@ -78,6 +78,10 @@ import static org.flowable.task.api.Task.DEFAULT_PRIORITY; @Slf4j public class CustomTaskHelper { + private CustomTaskHelper() { + + } + public static void addMultiTask(CommandContext commandContext, TaskEntity originTask, BpmnTaskDelegateAssigner newTaskAssignee) { if (Objects.isNull(originTask)) { @@ -352,8 +356,8 @@ public class CustomTaskHelper { */ public static TaskEntity createVirtualTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService , String processInstanceId, String nodeName, String taskDefinitionKey, String advice, - BpmnTaskDelegateAssigner assigner, - String extTaskInstStatus, AddComment addComment) { + BpmnTaskDelegateAssigner assigner, + String extTaskInstStatus, AddComment addComment) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); HistoryService historyService = processEngineConfiguration.getHistoryService(); From 565e6d320dde607bd808430c01f7ab3c7c817ddb Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 17 Oct 2025 16:26:22 +0800 Subject: [PATCH 07/58] =?UTF-8?q?feat=20-=20=E6=B5=8B=E8=AF=95=E5=89=8D?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=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 --- .../engine/cmd/helper/CustomBpmnModelHelper.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java index 4fe429fde..0e596015d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java @@ -8,7 +8,6 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; -import cn.hutool.core.lang.UUID; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.ExtensionAttribute; @@ -23,6 +22,7 @@ import org.flowable.engine.impl.bpmn.parser.factory.ActivityBehaviorFactory; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.springframework.util.StringUtils; +import java.util.Collections; import java.util.List; import static cn.axzo.workflow.common.code.ConvertorRespCode.CREATE_BPMN_PRE_SIGN_ERROR; @@ -36,6 +36,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_D import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONLY_ONE; +import static cn.axzo.workflow.common.constant.BpmnConstants.SEQUENCE_FLOW_ID; +import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.id; import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setExecutionListeners; import static cn.axzo.workflow.core.converter.json.UserTaskJsonConverter.setTaskListeners; @@ -167,12 +169,19 @@ public class CustomBpmnModelHelper { incomingFlow.setTargetRef(newUserTask.getId()); // 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可 } + newUserTask.setIncomingFlows(incomingFlows); // 3. 创建一个新的顺序流,从 newUserTask 指向 originalUserTask SequenceFlow newSequenceFlow = new SequenceFlow(); - newSequenceFlow.setId("pre_sign_dynamic" + UUID.fastUUID()); + newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_PreSign")); newSequenceFlow.setSourceRef(newUserTask.getId()); + newSequenceFlow.setSourceFlowElement(newUserTask); newSequenceFlow.setTargetRef(originalUserTask.getId()); + newSequenceFlow.setTargetFlowElement(originalUserTask); + + newUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow)); process.addFlowElement(newSequenceFlow); + + originalUserTask.setIncomingFlows(Collections.singletonList(newSequenceFlow)); } } From 4d1193d333dfebe2acf34feae7f06fd00010a173 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 17 Oct 2025 18:39:14 +0800 Subject: [PATCH 08/58] =?UTF-8?q?feat=20-=20=E6=96=B0=E5=A2=9E=E4=B8=80?= =?UTF-8?q?=E5=BC=A0=E5=8A=A0=E7=AD=BE=E8=AE=B0=E5=BD=95=E8=A1=A8=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=20JVM=20=E5=AE=9E=E4=BE=8B=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E5=8A=A8=E6=80=81=E6=A8=A1=E5=9E=8B=E9=87=8D?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomCountersignUserTaskCmd.java | 1 - .../entity/ExtAxDynamicSignRecord.java | 48 +++++++++++++++++ .../mapper/ExtAxDynamicSignRecordMapper.java | 14 +++++ .../ExtAxDynamicSignRecordService.java | 13 +++++ .../ExtAxDynamicSignRecordServiceImpl.java | 24 +++++++++ .../RecoverDynamicCounterSignProcess.java | 51 +++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxDynamicSignRecordMapper.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxDynamicSignRecordService.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxDynamicSignRecordServiceImpl.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java 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 68449a29a..be5d10ea1 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 @@ -193,7 +193,6 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) -// .moveExecutionsToSingleActivityId(Collections.singletonList(task.getExecutionId()), newUserTask.getId()) .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) .changeState(); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java new file mode 100644 index 000000000..b561e703b --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java @@ -0,0 +1,48 @@ +package cn.axzo.workflow.core.repository.entity; + +import cn.axzo.framework.data.mybatisplus.model.BaseEntity; +import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.core.conf.handler.ListAssigneeTypeHandler; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * 扩展动态前后加签记录,用于应用重启后的模型内容恢复 + * + * @author wangli + * @since 2025-10-17 18:23 + */ +@EqualsAndHashCode(callSuper = true) +@TableName(value = "ext_ax_dynamic_sign_record", autoResultMap = true) +@Data +@ToString(callSuper = true) +public class ExtAxDynamicSignRecord extends BaseEntity { + /** + * 流程实例 ID + */ + private String processInstanceId; + /** + * 流程实例对应的流程定义 ID + */ + private String processDefinitionId; + /** + * 加签次数 + */ + private Integer counterSignCount; + /** + * 加签类型,前加签/后加签 + * {@link BpmnCountersignTypeEnum} + */ + private String counterSignType; + /** + * 被加签的审批人 + */ + @TableField(value = "assigner_list", typeHandler = ListAssigneeTypeHandler.class) + private List assignerList; +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxDynamicSignRecordMapper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxDynamicSignRecordMapper.java new file mode 100644 index 000000000..bde632d7a --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/mapper/ExtAxDynamicSignRecordMapper.java @@ -0,0 +1,14 @@ +package cn.axzo.workflow.core.repository.mapper; + +import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; +import org.apache.ibatis.annotations.Mapper; + +/** + * 动态前后加签记录 Mapper + * + * @author wangli + * @since 2025-10-17 18:28 + */ +@Mapper +public interface ExtAxDynamicSignRecordMapper extends BaseMapperX { +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxDynamicSignRecordService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxDynamicSignRecordService.java new file mode 100644 index 000000000..48ba5b43c --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxDynamicSignRecordService.java @@ -0,0 +1,13 @@ +package cn.axzo.workflow.core.service; + +import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 动态前后加签记录服务接口 + * + * @author wangli + * @since 2025-10-17 18:30 + */ +public interface ExtAxDynamicSignRecordService extends IService { +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxDynamicSignRecordServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxDynamicSignRecordServiceImpl.java new file mode 100644 index 000000000..9b62d2e8b --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxDynamicSignRecordServiceImpl.java @@ -0,0 +1,24 @@ +package cn.axzo.workflow.core.service.impl; + +import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; +import cn.axzo.workflow.core.repository.mapper.ExtAxDynamicSignRecordMapper; +import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 流程签署业务信息记录 + * + * @author wangli + * @since 2025-04-02 10:06 + */ +@Service +@Slf4j +public class ExtAxDynamicSignRecordServiceImpl extends ServiceImpl implements ExtAxDynamicSignRecordService { + + @Resource + private ExtAxDynamicSignRecordMapper extAxDynamicSignRecordMapper; +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java new file mode 100644 index 000000000..2883600f6 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java @@ -0,0 +1,51 @@ +package cn.axzo.workflow.server.initializer; + +import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; +import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.SmartLifecycle; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 在框架提供 Web 服务前,恢复动态前后加签的流程实例的内存中的模型 + * + * @author wangli + * @since 2025-10-17 17:43 + */ +@Slf4j +@Component +public class RecoverDynamicCounterSignProcess implements SmartLifecycle { + private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService; + private boolean isRunning = false; + + public RecoverDynamicCounterSignProcess(ExtAxDynamicSignRecordService extAxDynamicSignRecordService) { + this.extAxDynamicSignRecordService = extAxDynamicSignRecordService; + } + + + @Override + public void start() { + // TODO 恢复动态会签中的流程实例 + log.info("executing before web server start"); + List list = extAxDynamicSignRecordService.list(); + + isRunning = true; + } + + @Override + public void stop() { + isRunning = false; + } + + @Override + public boolean isRunning() { + return isRunning; + } + + @Override + public int getPhase() { + return Integer.MAX_VALUE - 2; // 确保在Web服务器启动前执行 + } +} From 1e4d9e2ea90c7818dacdf07f7b5f14d0be646547 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 11:15:41 +0800 Subject: [PATCH 09/58] =?UTF-8?q?feat=20-=20=E9=A1=B9=E7=9B=AE=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=AE=8C=E6=88=90=E5=90=8E=EF=BC=8C=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=20web=20=E6=9C=8D=E5=8A=A1=E5=89=8D=EF=BC=8C=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=8A=A0=E7=AD=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/FlowableConfiguration.java | 5 +- .../cmd/CustomCountersignUserTaskCmd.java | 18 ++++- .../AsyncCountersignUserTaskJobHandler.java | 9 ++- .../entity/ExtAxDynamicSignRecord.java | 9 ++- .../RecoverDynamicCounterSignProcess.java | 79 ++++++++++++++++++- 5 files changed, 112 insertions(+), 8 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 b65829847..75c71c629 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 @@ -27,6 +27,7 @@ import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncJobLogClearT import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncRunnableExceptionExceptionHandler; import cn.axzo.workflow.core.engine.persistence.CustomMybatisHistoricProcessInstanceDataManager; import cn.axzo.workflow.core.service.BpmnProcessActivityService; +import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.azxo.framework.common.constatns.Constants; import cn.hutool.core.util.ReflectUtil; @@ -83,6 +84,7 @@ public class FlowableConfiguration { ObjectProvider listeners, CustomActivityBehaviorFactory customActivityBehaviorFactory, ExtAxHiTaskInstService extAxHiTaskInstService, + ExtAxDynamicSignRecordService extAxDynamicSignRecordService, BpmnProcessActivityService bpmnProcessActivityService, List jobProcessors, NacosServiceManager nacosServiceManager, @@ -110,12 +112,11 @@ public class FlowableConfiguration { configuration.addCustomJobHandler(new AsyncApproveTaskJobHandler()); configuration.addCustomJobHandler(new AsyncBackTaskJobHandler()); configuration.addCustomJobHandler(new AsyncCancelProcessInstanceJobHandler(extAxHiTaskInstService)); - configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService)); + configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService, extAxDynamicSignRecordService)); configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler()); configuration.addCustomJobHandler(new AsyncTermNodeAlterJobHandler(refreshProperties)); - configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService)); configuration.addCustomJobHandler(new AsyncActivityLeaveJobHandler(bpmnProcessActivityService)); configuration.addCustomJobHandler(new AsyncActivityCallbackJobHandler()); configuration.addCustomJobHandler(new AsyncApproveTaskWithFormJobHandler()); 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 be5d10ea1..dc25c6beb 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 @@ -8,6 +8,8 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper; import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper; import cn.axzo.workflow.core.engine.model.AddComment; +import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; +import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; @@ -45,6 +47,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNE import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT; import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_COUNTERSIGN_COUNT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; +import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addMultiTask; @@ -75,11 +78,14 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen private final List attachmentList; private final List targetTaskAssigneeList; private final ExtAxHiTaskInstService extAxHiTaskInstService; + private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService; public CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum countersignType, String originTaskId, BpmnTaskDelegateAssigner originTaskAssignee, String advice, List attachmentList, - List targetTaskAssigneeList, ExtAxHiTaskInstService extAxHiTaskInstService) { + List targetTaskAssigneeList, + ExtAxHiTaskInstService extAxHiTaskInstService, + ExtAxDynamicSignRecordService extAxDynamicSignRecordService) { this.countersignType = countersignType; this.originTaskId = originTaskId; this.originTaskAssignee = originTaskAssignee; @@ -87,6 +93,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen this.attachmentList = attachmentList; this.targetTaskAssigneeList = targetTaskAssigneeList; this.extAxHiTaskInstService = extAxHiTaskInstService; + this.extAxDynamicSignRecordService = extAxDynamicSignRecordService; } @Override @@ -191,6 +198,15 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen // 重新连接顺序流 (Sequence Flow) CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask); + ExtAxDynamicSignRecord entity = new ExtAxDynamicSignRecord(); + entity.setProcessInstanceId(processInstance.getProcessInstanceId()); + entity.setProcessDefinitionId(processInstance.getProcessDefinitionId()); + entity.setOriginalActivityId(originalUserTask.getId()); + entity.setTargetActivityId(newUserTask.getId()); + entity.setCounterSignType(FORWARD_COUNTERSIGN.getType()); + entity.setAssignerList(valuTargetAssigneeList); + extAxDynamicSignRecordService.saveOrUpdate(entity); + runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCountersignUserTaskJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCountersignUserTaskJobHandler.java index 5d0013b03..454bc099d 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCountersignUserTaskJobHandler.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncCountersignUserTaskJobHandler.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.job; import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; import cn.axzo.workflow.core.engine.cmd.CustomCountersignUserTaskCmd; +import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; @@ -19,9 +20,12 @@ public class AsyncCountersignUserTaskJobHandler extends AbstractJobHandler imple public static final String TYPE = "async-countersign-task"; private final ExtAxHiTaskInstService extAxHiTaskInstService; + private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService; - public AsyncCountersignUserTaskJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService) { + public AsyncCountersignUserTaskJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService, + ExtAxDynamicSignRecordService extAxDynamicSignRecordService) { this.extAxHiTaskInstService = extAxHiTaskInstService; + this.extAxDynamicSignRecordService = extAxDynamicSignRecordService; } @Override @@ -42,6 +46,7 @@ public class AsyncCountersignUserTaskJobHandler extends AbstractJobHandler imple dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssignerList(), - extAxHiTaskInstService)); + extAxHiTaskInstService, + extAxDynamicSignRecordService)); } } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java index b561e703b..f10a30aba 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java @@ -32,9 +32,14 @@ public class ExtAxDynamicSignRecord extends BaseEntity { */ private String processDefinitionId; /** - * 加签次数 + * 加签原节点 */ - private Integer counterSignCount; + private String originalActivityId; + /** + * 加签目标节点 + */ + private String targetActivityId; + /** * 加签类型,前加签/后加签 * {@link BpmnCountersignTypeEnum} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java index 2883600f6..a71f8bd2a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java @@ -1,12 +1,32 @@ package cn.axzo.workflow.server.initializer; +import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; +import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper; import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.persistence.deploy.DeploymentManager; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.BACK_COUNTERSIGN; +import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; /** * 在框架提供 Web 服务前,恢复动态前后加签的流程实例的内存中的模型 @@ -18,10 +38,13 @@ import java.util.List; @Component public class RecoverDynamicCounterSignProcess implements SmartLifecycle { private final ExtAxDynamicSignRecordService extAxDynamicSignRecordService; + private final SpringProcessEngineConfiguration springProcessEngineConfiguration; private boolean isRunning = false; - public RecoverDynamicCounterSignProcess(ExtAxDynamicSignRecordService extAxDynamicSignRecordService) { + public RecoverDynamicCounterSignProcess(ExtAxDynamicSignRecordService extAxDynamicSignRecordService, + SpringProcessEngineConfiguration springProcessEngineConfiguration) { this.extAxDynamicSignRecordService = extAxDynamicSignRecordService; + this.springProcessEngineConfiguration = springProcessEngineConfiguration; } @@ -29,7 +52,61 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { public void start() { // TODO 恢复动态会签中的流程实例 log.info("executing before web server start"); + // 查询有过加签的审批实例 List list = extAxDynamicSignRecordService.list(); + if (CollectionUtils.isEmpty(list)) { + return; + } + + RuntimeService runtimeService = springProcessEngineConfiguration.getRuntimeService(); + // 获取还在审批中的实例 + Set processInstanceIds = list.stream().map(ExtAxDynamicSignRecord::getProcessInstanceId).collect(Collectors.toSet()); + Set runningProcessIds = runtimeService.createProcessInstanceQuery() + .processInstanceIds(processInstanceIds) + .active() + .list().stream().map(ProcessInstance::getProcessInstanceId).collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(runningProcessIds)) { + return; + } + + Map> grouped = list.stream() + .collect(Collectors.groupingBy( + ExtAxDynamicSignRecord::getProcessInstanceId, + Collectors.collectingAndThen( + Collectors.toList(), + l -> { + l.sort(Comparator.comparing( + ExtAxDynamicSignRecord::getCreateAt, + Comparator.nullsFirst(Comparator.naturalOrder()) + )); + return l; + } + ) + )); + + RepositoryService repositoryService = springProcessEngineConfiguration.getRepositoryService(); + DeploymentManager deploymentManager = springProcessEngineConfiguration.getDeploymentManager(); + grouped.forEach((k, v) -> { + if (runningProcessIds.contains(k)) { + log.info("recover dynamic counter sign process instance id: {}", k); + + ProcessDefinition processDefinitionEntity = deploymentManager.findDeployedProcessDefinitionById(v.get(0).getProcessDefinitionId()); + Process process = deploymentManager.resolveProcessDefinition(processDefinitionEntity).getProcess(); + v.forEach(sign -> { + if (Objects.equals(sign.getCounterSignType(), FORWARD_COUNTERSIGN.getType())) { + UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId()); + BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; + // 创建前加签节点 + UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList()); + process.addFlowElement(newUserTask); + CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask); + } else if (Objects.equals(sign.getCounterSignType(), BACK_COUNTERSIGN.getType())) { + + } + }); + } + }); + isRunning = true; } From 7ac49ca86389625caf19aeaacda11f712b6a9f87 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 11:22:38 +0800 Subject: [PATCH 10/58] =?UTF-8?q?feat=20-=20=E8=A7=A3=E5=86=B3=E7=BC=96?= =?UTF-8?q?=E8=AF=91=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 | 5 ++++- 1 file changed, 4 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 b7e2d8907..547338425 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 @@ -53,6 +53,7 @@ import cn.axzo.workflow.core.engine.cmd.CustomTransferUserTaskCmd; 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.ExtAxDynamicSignRecordService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.axzo.workflow.core.service.ExtAxProcessLogService; import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter; @@ -187,6 +188,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { private ExtAxProcessLogService processLogService; @Resource private SupportRefreshProperties refreshProperties; + @Resource + private ExtAxDynamicSignRecordService extAxDynamicSignRecordService; @Override public BpmPageResult getTodoTaskPage(BpmnTaskPageSearchDTO dto) { @@ -862,7 +865,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService { } else { commandExecutor.execute(new CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum.valueOfType(dto.getCountersignType()), dto.getTaskId(), dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssignerList(), - extAxHiTaskInstService)); + extAxHiTaskInstService, extAxDynamicSignRecordService)); } } From ad1efc673ac6e39bf7ecfcc6f5f43d3b2f8943ed Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 13:38:44 +0800 Subject: [PATCH 11/58] =?UTF-8?q?feat=20-=20=E5=8A=A0=E7=AD=BE=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E8=B0=83=E6=95=B4=E6=96=B0=E8=8A=82=E7=82=B9=E7=9A=84?= =?UTF-8?q?=20ID=20=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomCountersignUserTaskCmd.java | 8 +++++++- .../core/repository/entity/ExtAxDynamicSignRecord.java | 5 ++++- .../initializer/RecoverDynamicCounterSignProcess.java | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) 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 dc25c6beb..3e982f632 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 @@ -191,7 +191,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; // 创建前加签节点 - UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, originalUserTask.getId() + FORWARD_ACTIVITY_FRAGMENT + forwardCounterSignCount, nodeMode, valuTargetAssigneeList); + String newActivityId = originalUserTask.getId(); + if (newActivityId.contains(FORWARD_ACTIVITY_FRAGMENT)) { + newActivityId = newActivityId.substring(0, newActivityId.indexOf(FORWARD_ACTIVITY_FRAGMENT)); + } + UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId + FORWARD_ACTIVITY_FRAGMENT + forwardCounterSignCount, nodeMode, valuTargetAssigneeList); // 加入模型 process.addFlowElement(newUserTask); @@ -204,9 +208,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen entity.setOriginalActivityId(originalUserTask.getId()); entity.setTargetActivityId(newUserTask.getId()); entity.setCounterSignType(FORWARD_COUNTERSIGN.getType()); + entity.setTargetNodeMode(nodeMode.getType()); entity.setAssignerList(valuTargetAssigneeList); extAxDynamicSignRecordService.saveOrUpdate(entity); + runtimeService.setVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, forwardCounterSignCount); runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java index f10a30aba..bc24c784f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxDynamicSignRecord.java @@ -39,12 +39,15 @@ public class ExtAxDynamicSignRecord extends BaseEntity { * 加签目标节点 */ private String targetActivityId; - /** * 加签类型,前加签/后加签 * {@link BpmnCountersignTypeEnum} */ private String counterSignType; + /** + * 目标节点的审批方式(会签、或签、顺序签) + */ + private String targetNodeMode; /** * 被加签的审批人 */ diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java index a71f8bd2a..29ae3278a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java @@ -16,6 +16,7 @@ import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.util.Comparator; import java.util.List; @@ -96,6 +97,9 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { if (Objects.equals(sign.getCounterSignType(), FORWARD_COUNTERSIGN.getType())) { UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId()); BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; + if (StringUtils.hasText(sign.getTargetNodeMode())) { + nodeMode = BpmnFlowNodeMode.valueOfType(sign.getTargetNodeMode()); + } // 创建前加签节点 UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList()); process.addFlowElement(newUserTask); From 7479f983f27a2de29516c3152d1246cfee547cef Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 13:48:02 +0800 Subject: [PATCH 12/58] =?UTF-8?q?feat=20-=20=E8=B0=83=E6=95=B4=E5=8A=A0?= =?UTF-8?q?=E7=AD=BE=E6=AC=A1=E6=95=B0=E8=AE=B0=E5=BD=95=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/common/constant/BpmnConstants.java | 2 +- .../core/engine/cmd/CustomCountersignUserTaskCmd.java | 6 +++--- 2 files changed, 4 insertions(+), 4 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 524d25c88..587e774b3 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 @@ -47,7 +47,7 @@ public interface BpmnConstants { String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]"; String INITIATOR_SPECIFY = "[_INITIATOR_SPECIFY_]"; String SIGNATURE_COLLECTION = "[_SIGNATURE_COLLECTION_]"; - String FORWARD_COUNTERSIGN_COUNT = "[_FORWARD_COUNTERSIGN_COUNT_]"; + String COUNTERSIGN_COUNT = "[_COUNTERSIGN_COUNT_]"; String PROCESS_PREFIX = "Flowable"; @Deprecated String OLD_TASK_ASSIGNEE_SKIP_FLAT = "taskSkip"; 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 3e982f632..e562c6c11 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 @@ -44,8 +44,8 @@ import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER; +import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_COUNT; import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT; -import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_COUNTERSIGN_COUNT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT; import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN; @@ -182,7 +182,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen UserTask originalUserTask = (UserTask) process.getFlowElement(task.getTaskDefinitionKey()); // 获取当前实例前加签次数 - Long forwardCounterSignCount = runtimeService.getVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, Long.class); + Long forwardCounterSignCount = runtimeService.getVariable(processInstance.getId(), COUNTERSIGN_COUNT, Long.class); if (Objects.isNull(forwardCounterSignCount)) { forwardCounterSignCount = 0L; } else { @@ -212,7 +212,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen entity.setAssignerList(valuTargetAssigneeList); extAxDynamicSignRecordService.saveOrUpdate(entity); - runtimeService.setVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, forwardCounterSignCount); + runtimeService.setVariable(processInstance.getId(), COUNTERSIGN_COUNT, forwardCounterSignCount); runtimeService.createChangeActivityStateBuilder() .processInstanceId(task.getProcessInstanceId()) .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) From a422f44c699a9dac22b3c43c9a8f29994942ede5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 14:39:25 +0800 Subject: [PATCH 13/58] =?UTF-8?q?feat=20-=20=E4=BF=AE=E6=94=B9=E5=90=8E?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=E5=AE=9E=E7=8E=B0=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E9=87=87=E7=94=A8=E5=89=8D=E5=8A=A0=E7=AD=BE=E7=9B=B8=E5=90=8C?= =?UTF-8?q?=E5=8E=9F=E7=90=86=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 4 + .../cmd/CustomCountersignUserTaskCmd.java | 84 ++++++++++++----- .../cmd/helper/CustomBpmnModelHelper.java | 89 +++++++++++++------ .../RecoverDynamicCounterSignProcess.java | 27 +++--- 4 files changed, 138 insertions(+), 66 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 587e774b3..f3f701af5 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 @@ -269,4 +269,8 @@ public interface BpmnConstants { * 前加签节点 ID 片段 */ String FORWARD_ACTIVITY_FRAGMENT = "[forward_sign]"; + /** + * 后加签节点 ID 片段 + */ + String BACK_ACTIVITY_FRAGMENT = "[back_sign]"; } 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 e562c6c11..705c3ebfe 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 @@ -43,6 +43,7 @@ import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; +import static cn.axzo.workflow.common.constant.BpmnConstants.BACK_ACTIVITY_FRAGMENT; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER; import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_COUNT; import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT; @@ -150,11 +151,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen switch (countersignType) { case FORWARD_COUNTERSIGN: // 加签的一种方式:前加签,具体定义由后续产品需求来定 - forwardCountSign(commandContext, task, valuTargetAssigneeList); + forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList); break; case BACK_COUNTERSIGN: // 加签的另一种方式 - backCountSign(commandContext, historicTaskInstance, task, valuTargetAssigneeList); + forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList); break; default: // 共享签,不区分顺序 @@ -166,13 +167,15 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen } /** - * 前加签 + * 前、后加签 + *

+ * 使用内存动态变更模型连接实现前加签功能 * * @param commandContext * @param task * @param valuTargetAssigneeList */ - private void forwardCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { + private void forwardAndBackCountSign(CommandContext commandContext, TaskEntity task, List valuTargetAssigneeList) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext); @@ -182,51 +185,90 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen UserTask originalUserTask = (UserTask) process.getFlowElement(task.getTaskDefinitionKey()); // 获取当前实例前加签次数 - Long forwardCounterSignCount = runtimeService.getVariable(processInstance.getId(), COUNTERSIGN_COUNT, Long.class); - if (Objects.isNull(forwardCounterSignCount)) { - forwardCounterSignCount = 0L; + Long counterSignCount = runtimeService.getVariable(processInstance.getId(), COUNTERSIGN_COUNT, Long.class); + if (Objects.isNull(counterSignCount)) { + counterSignCount = 0L; } else { - forwardCounterSignCount = forwardCounterSignCount + 1; + counterSignCount = counterSignCount + 1; } + runtimeService.setVariable(processInstance.getId(), COUNTERSIGN_COUNT, counterSignCount); BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; - // 创建前加签节点 + + // 生成加签节点ID String newActivityId = originalUserTask.getId(); - if (newActivityId.contains(FORWARD_ACTIVITY_FRAGMENT)) { - newActivityId = newActivityId.substring(0, newActivityId.indexOf(FORWARD_ACTIVITY_FRAGMENT)); + switch (countersignType) { + case FORWARD_COUNTERSIGN: + newActivityId = processActivityId(newActivityId, FORWARD_ACTIVITY_FRAGMENT, counterSignCount); + break; + case BACK_COUNTERSIGN: + newActivityId = processActivityId(newActivityId, BACK_ACTIVITY_FRAGMENT, counterSignCount); + default: + break; } - UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId + FORWARD_ACTIVITY_FRAGMENT + forwardCounterSignCount, nodeMode, valuTargetAssigneeList); + + // 创建被加签节点 + UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId, nodeMode, valuTargetAssigneeList); // 加入模型 process.addFlowElement(newUserTask); - // 重新连接顺序流 (Sequence Flow) - CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask); + CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, countersignType); + saveCounterSignRecord(valuTargetAssigneeList, processInstance, originalUserTask, newUserTask, nodeMode); + + if (Objects.equals(FORWARD_COUNTERSIGN, countersignType)) { + log.info("前加签任务处理完成,原任务ID:{},新任务ID:{}", task.getId(), newUserTask.getId()); + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(task.getProcessInstanceId()) + .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) + .changeState(); + + } else { + } + } + + /** + * 前后加签动作记录,用于 JVM 重启后的动态恢复 + * + * @param valuTargetAssigneeList + * @param processInstance + * @param originalUserTask + * @param newUserTask + * @param nodeMode + */ + private void saveCounterSignRecord(List valuTargetAssigneeList, ProcessInstance processInstance, UserTask originalUserTask, UserTask newUserTask, BpmnFlowNodeMode nodeMode) { ExtAxDynamicSignRecord entity = new ExtAxDynamicSignRecord(); entity.setProcessInstanceId(processInstance.getProcessInstanceId()); entity.setProcessDefinitionId(processInstance.getProcessDefinitionId()); entity.setOriginalActivityId(originalUserTask.getId()); entity.setTargetActivityId(newUserTask.getId()); - entity.setCounterSignType(FORWARD_COUNTERSIGN.getType()); + entity.setCounterSignType(countersignType.getType()); entity.setTargetNodeMode(nodeMode.getType()); entity.setAssignerList(valuTargetAssigneeList); extAxDynamicSignRecordService.saveOrUpdate(entity); - - runtimeService.setVariable(processInstance.getId(), COUNTERSIGN_COUNT, forwardCounterSignCount); - runtimeService.createChangeActivityStateBuilder() - .processInstanceId(task.getProcessInstanceId()) - .moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId()) - .changeState(); } + // 提取公共处理方法 + private String processActivityId(String originalId, String fragment, long count) { + if (originalId.contains(fragment)) { + int fragmentIndex = originalId.indexOf(fragment); + return originalId.substring(0, fragmentIndex) + fragment + count; + } + return originalId; // 不包含目标片段时,返回原字符串 + } + + /** * 后加签 + *

+ * 基于当前节点的后加签,内部实现主要依靠加减签的能力实现 * * @param commandContext * @param historicTaskInstance * @param task * @param valuTargetAssigneeList */ + @Deprecated private void backCountSign(CommandContext commandContext, HistoricTaskInstance historicTaskInstance, TaskEntity task, diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java index 0e596015d..dcb7a0ddf 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/helper/CustomBpmnModelHelper.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd.helper; import cn.axzo.workflow.common.enums.ApprovalMethodEnum; import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; +import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.exception.WorkflowEngineException; @@ -69,7 +70,7 @@ public class CustomBpmnModelHelper { newUserTask.setId(originalUserTask.getId()); } newUserTask.setName(originalUserTask.getName()); - newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点前加签生成"); + newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点加签生成"); MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); loopCharacteristics.setInputDataItem(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId()); @@ -129,7 +130,7 @@ public class CustomBpmnModelHelper { nodeTypeElement.setElementText(BpmnFlowNodeType.NODE_TASK.getType()); newUserTask.addExtensionElement(nodeTypeElement); - // TODO 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空 + // 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空 // 审批人为空时 ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement(); approverEmptyHandleTypeElement.setName(CONFIG_APPROVER_EMPTY_HANDLE_TYPE); @@ -147,7 +148,6 @@ public class CustomBpmnModelHelper { ActivityBehaviorFactory activityBehaviorFactory = processEngineConfiguration.getActivityBehaviorFactory(); UserTaskActivityBehavior userTaskActivityBehavior = activityBehaviorFactory.createUserTaskActivityBehavior(newUserTask); - // TODO 这里设置的 userTaskActivityBehavior 似乎是不对的。需要 ParallelMultiInstanceBehavior behavior = activityBehaviorFactory.createParallelMultiInstanceBehavior(newUserTask, userTaskActivityBehavior); behavior.setCollectionVariable(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId()); @@ -157,31 +157,64 @@ public class CustomBpmnModelHelper { return newUserTask; } - public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask newUserTask) { - // 1. 找到所有指向原始节点的输入流 - List incomingFlows = originalUserTask.getIncomingFlows(); - if (incomingFlows.isEmpty()) { - throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输入流,无法进行前加签"); + public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask targetUserTask, BpmnCountersignTypeEnum countersignType) { + switch (countersignType) { + case FORWARD_COUNTERSIGN: + // 1. 找到所有指向原始节点的输入流 + List incomingFlows = originalUserTask.getIncomingFlows(); + if (incomingFlows.isEmpty()) { + throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输入流,无法进行前加签"); + } + + // 2. 将这些输入流的目标从 originalUserTask 修改为 targetUserTask + for (SequenceFlow incomingFlow : incomingFlows) { + incomingFlow.setTargetRef(targetUserTask.getId()); + // 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可 + } + targetUserTask.setIncomingFlows(incomingFlows); + + // 3. 创建一个新的顺序流,从 targetUserTask 指向 originalUserTask + SequenceFlow newSequenceFlow = new SequenceFlow(); + newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_ForwardSign")); + newSequenceFlow.setSourceRef(targetUserTask.getId()); + newSequenceFlow.setSourceFlowElement(targetUserTask); + newSequenceFlow.setTargetRef(originalUserTask.getId()); + newSequenceFlow.setTargetFlowElement(originalUserTask); + + targetUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow)); + process.addFlowElement(newSequenceFlow); + + originalUserTask.setIncomingFlows(Collections.singletonList(newSequenceFlow)); + break; + case BACK_COUNTERSIGN: + // 1. 找到所有指向原始节点的输出流 + List outgoingFlows = originalUserTask.getOutgoingFlows(); + if (outgoingFlows.isEmpty()) { + throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输出流,无法进行后加签"); + } + + // 2. 将这些输出流的源从 originalUserTask 修改为 targetUserTask + for (SequenceFlow outgoingFlow : outgoingFlows) { + outgoingFlow.setSourceRef(targetUserTask.getId()); + // 如果需要,也可以更新FlowElement中的引用,但通常改SourceRef即可 + } + targetUserTask.setOutgoingFlows(outgoingFlows); + + // 3. 创建一个新的顺序流,从 originalUserTask 指向 targetUserTask + SequenceFlow backSequenceFlow = new SequenceFlow(); + backSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_BackSign")); + backSequenceFlow.setSourceRef(originalUserTask.getId()); + backSequenceFlow.setSourceFlowElement(originalUserTask); + backSequenceFlow.setTargetRef(targetUserTask.getId()); + backSequenceFlow.setTargetFlowElement(targetUserTask); + + originalUserTask.setOutgoingFlows(Collections.singletonList(backSequenceFlow)); + process.addFlowElement(backSequenceFlow); + + targetUserTask.setIncomingFlows(Collections.singletonList(backSequenceFlow)); + break; + default: + break; } - - // 2. 将这些输入流的目标从 originalUserTask 修改为 newUserTask - for (SequenceFlow incomingFlow : incomingFlows) { - incomingFlow.setTargetRef(newUserTask.getId()); - // 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可 - } - newUserTask.setIncomingFlows(incomingFlows); - - // 3. 创建一个新的顺序流,从 newUserTask 指向 originalUserTask - SequenceFlow newSequenceFlow = new SequenceFlow(); - newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_PreSign")); - newSequenceFlow.setSourceRef(newUserTask.getId()); - newSequenceFlow.setSourceFlowElement(newUserTask); - newSequenceFlow.setTargetRef(originalUserTask.getId()); - newSequenceFlow.setTargetFlowElement(originalUserTask); - - newUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow)); - process.addFlowElement(newSequenceFlow); - - originalUserTask.setIncomingFlows(Collections.singletonList(newSequenceFlow)); } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java index 29ae3278a..07de639d0 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.server.initializer; +import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper; import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; @@ -7,7 +8,6 @@ import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.persistence.deploy.DeploymentManager; import org.flowable.engine.repository.ProcessDefinition; @@ -26,8 +26,6 @@ import java.util.Set; import java.util.stream.Collectors; import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION; -import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.BACK_COUNTERSIGN; -import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; /** * 在框架提供 Web 服务前,恢复动态前后加签的流程实例的内存中的模型 @@ -51,7 +49,7 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { @Override public void start() { - // TODO 恢复动态会签中的流程实例 + // 恢复动态会签中的流程实例 log.info("executing before web server start"); // 查询有过加签的审批实例 List list = extAxDynamicSignRecordService.list(); @@ -85,7 +83,6 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { ) )); - RepositoryService repositoryService = springProcessEngineConfiguration.getRepositoryService(); DeploymentManager deploymentManager = springProcessEngineConfiguration.getDeploymentManager(); grouped.forEach((k, v) -> { if (runningProcessIds.contains(k)) { @@ -94,19 +91,15 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { ProcessDefinition processDefinitionEntity = deploymentManager.findDeployedProcessDefinitionById(v.get(0).getProcessDefinitionId()); Process process = deploymentManager.resolveProcessDefinition(processDefinitionEntity).getProcess(); v.forEach(sign -> { - if (Objects.equals(sign.getCounterSignType(), FORWARD_COUNTERSIGN.getType())) { - UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId()); - BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; - if (StringUtils.hasText(sign.getTargetNodeMode())) { - nodeMode = BpmnFlowNodeMode.valueOfType(sign.getTargetNodeMode()); - } - // 创建前加签节点 - UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList()); - process.addFlowElement(newUserTask); - CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask); - } else if (Objects.equals(sign.getCounterSignType(), BACK_COUNTERSIGN.getType())) { - + UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId()); + BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; + if (StringUtils.hasText(sign.getTargetNodeMode())) { + nodeMode = BpmnFlowNodeMode.valueOfType(sign.getTargetNodeMode()); } + // 创建加签节点 + UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList()); + process.addFlowElement(newUserTask); + CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, Objects.requireNonNull(BpmnCountersignTypeEnum.valueOfType(sign.getCounterSignType()))); }); } }); From a37fc25db593f5bf5727426c1d76799b25b86080 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 15:41:22 +0800 Subject: [PATCH 14/58] =?UTF-8?q?feat=20-=20=E4=BF=AE=E6=94=B9=E5=8A=A0?= =?UTF-8?q?=E7=AD=BE=E9=80=BB=E8=BE=91=E4=B8=AD=E7=9A=84=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E5=A4=84=E7=90=86=E7=94=9F=E6=88=90=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 --- .../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 705c3ebfe..e91988449 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 @@ -254,7 +254,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand implemen int fragmentIndex = originalId.indexOf(fragment); return originalId.substring(0, fragmentIndex) + fragment + count; } - return originalId; // 不包含目标片段时,返回原字符串 + return originalId + fragment + count; // 不包含目标片段时,返回原字符串 } From edaeb9101c95c004fc89081d379ed1559ecb3e09 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 16:29:42 +0800 Subject: [PATCH 15/58] =?UTF-8?q?feat=20-=20=E5=AE=A1=E6=89=B9=E4=BA=BA?= =?UTF-8?q?=E5=90=8C=E6=84=8F=E6=97=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=A5=E6=9C=9F=E5=92=8C=E5=AE=A1=E6=89=B9=E7=BB=93?= =?UTF-8?q?=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/common/model/dto/SignatureDTO.java | 4 ++++ .../axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java index 183722818..6eb129612 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.common.model.dto; +import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -7,6 +8,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; +import java.util.Date; import java.util.List; /** @@ -41,5 +43,7 @@ public class SignatureDTO implements Serializable { private static final long serialVersionUID = 1L; private String signature; private String advice; + private BpmnProcessTaskResultEnum result; + private Date operationTime; } } 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 112c9413e..3829b5c25 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 @@ -2,6 +2,7 @@ package cn.axzo.workflow.core.engine.cmd; import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum; import cn.axzo.workflow.common.model.dto.SignatureDTO; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; @@ -28,6 +29,7 @@ import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -202,7 +204,9 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria .ifPresent(attachment -> dto.getSignatures().add(0, new SignatureDTO.SignDetail() .setSignature(attachment.getUrl()) - .setAdvice(advice))); + .setAdvice(advice) + .setResult(BpmnProcessTaskResultEnum.APPROVED) + .setOperationTime(new Date()))); if (!any.isPresent()) { signatures.add(dto); } From 3b771aa153c5c04dd9e21bed36f6206db55af76e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 17:30:13 +0800 Subject: [PATCH 16/58] =?UTF-8?q?feat=20-=20=E8=A1=A8=E5=8D=95=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=94=A8=E4=BA=8E=E6=89=93=E5=8D=B0=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=EF=BC=8C=E6=96=87=E6=A1=A3=E6=A8=A1=E6=9D=BF=E5=B7=A6=E4=BE=A7?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=98=AF=E5=90=A6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=89=93=E5=8D=B0=E7=9A=84=E5=8F=82=E6=95=B0=E6=8E=A7?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpmn/print/PrintFieldQueryDTO.java | 5 +++ .../web/manage/PrintAdminController.java | 35 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintFieldQueryDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintFieldQueryDTO.java index 3775f63e5..3c6deb6df 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintFieldQueryDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintFieldQueryDTO.java @@ -35,6 +35,11 @@ public class PrintFieldQueryDTO { @ApiModelProperty(value = "租户 ID") private String tenantId; + /** + * 是否过滤仅支持打印字段 + */ + @ApiModelProperty(value = "是否过滤仅支持打印字段") + private Boolean filterEnablePrint; /** * 是否抛出内部异常 */ diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 38d4cd32f..0ba207c04 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -162,6 +162,7 @@ public class PrintAdminController implements PrintAdminApi { bpmnProcessModelService.printTemplateConfig(dto); return success(); } + /** * 获取打印模板中可打印的字段, 或者是 WPS 模板中可配置的变量字段 * @@ -180,17 +181,29 @@ public class PrintAdminController implements PrintAdminApi { List formFields = ((SimpleFormModel) formModel.getFormModel()).getFields(); formFields.forEach(formField -> { FormContainer formContainer = (FormContainer) formField; - printFields.addAll(formContainer.getFields().get(0).stream().map(field -> { - PrintFieldDTO printFieldDTO = new PrintFieldDTO() - .setName(field.getName()) - .setCode(field.getId()) - .setFieldCategoryType(form) - .setFieldFormType(field.getType()); - switchAmount(field, printFieldDTO); - switchFormContainer(field, printFieldDTO); - return printFieldDTO; - } - ).collect(Collectors.toList())); + printFields.addAll(formContainer.getFields().get(0).stream() + .filter(field -> { + if (Objects.equals(Boolean.TRUE, dto.getFilterEnablePrint())) { + if (!CollectionUtils.isEmpty(field.getParams())) { + Optional optEnablePrint = Optional.ofNullable(field.getParam("enablePrint")); + return optEnablePrint.map(obj -> Boolean.parseBoolean(obj.toString())).orElse(Boolean.TRUE); + } + return true; + } else { + return false; + } + }) + .map(field -> { + PrintFieldDTO printFieldDTO = new PrintFieldDTO() + .setName(field.getName()) + .setCode(field.getId()) + .setFieldCategoryType(form) + .setFieldFormType(field.getType()); + switchAmount(field, printFieldDTO); + switchFormContainer(field, printFieldDTO); + return printFieldDTO; + } + ).collect(Collectors.toList())); }); } catch (FlowableObjectNotFoundException e) { log.warn("can't found form model"); From 1070085454146fed5cfdc91e08317b20f5e02704 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 18:12:03 +0800 Subject: [PATCH 17/58] =?UTF-8?q?feat=20-=20=E5=AE=A1=E6=89=B9=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=A2=9E=E5=8A=A0=E8=8A=82=E7=82=B9=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/common/constant/VariableConstants.java | 8 ++++++++ .../controller/web/manage/PrintAdminController.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java index b0ae9caa8..e9853631b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java @@ -45,8 +45,12 @@ public interface VariableConstants { String PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC = "发起人岗位"; String PRINT_VAR_PROCESS_INITIATOR_PHONE = "initiatorPhone"; String PRINT_VAR_PROCESS_INITIATOR_PHONE_DESC = "发起人联系方式"; + String PRINT_VAR_PROCESS_INITIATOR_UNIT = "initiatorUnit"; + String PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC = "发起人单位"; String PRINT_VAR_PROCESS_LOGS = "processLogs"; String PRINT_VAR_PROCESS_LOGS_DESC = "审批日志"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE = "activityNodeType"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE_DESC = "节点类型"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME = "activityName"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC = "节点名称"; String PRINT_VAR_PROCESS_LOG_APPROVER_NAME = "approverName"; @@ -61,4 +65,8 @@ public interface VariableConstants { String PRINT_VAR_PROCESS_LOG_OPERATION_TIME_DESC = "审批时间"; String PRINT_VAR_PROCESS_LOG_SIGNATURE = "signature"; String PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC = "电子签名"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT = "activityResult"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC = "节点状态"; + String PRINT_VAR_PROCESS_LOG_OPERATION = "operationDesc"; + String PRINT_VAR_PROCESS_LOG_OPERATION_DESC = "操作描述"; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 0ba207c04..c3c7cadfb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -79,16 +79,20 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_PHONE_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_UNIT; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOGS; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOGS_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_APPROVER_NAME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION_TIME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_OPERATION_TIME_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_POSITION; @@ -380,6 +384,7 @@ public class PrintAdminController implements PrintAdminApi { variables.put(PRINT_VAR_PROCESS_INITIATOR_NAME, user.isPresent() ? user.get().getRealName() : ""); variables.put(PRINT_VAR_PROCESS_INITIATOR_POSITION, user.isPresent() && Objects.nonNull(user.get().getJob()) ? user.get().getJob().getName() : ""); variables.put(PRINT_VAR_PROCESS_INITIATOR_PHONE, user.isPresent() ? user.get().getProfile().getPhone() : ""); + variables.put(PRINT_VAR_PROCESS_INITIATOR_UNIT, user.isPresent() ? user.get().getOrganizationalUnitName() : ""); variables.remove(PRINT_VAR_PROCESS_INITIATOR); } // 填充审批日志 @@ -395,11 +400,14 @@ public class PrintAdminController implements PrintAdminApi { .forEach(taskLog -> { Map taskLogMap = new HashMap<>(); taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME, taskLog.getName()); + taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE, taskLog.getNodeType().getType()); Optional user = getUserInfo(taskLog.getAssigneeSnapshot()); taskLogMap.put(PRINT_VAR_PROCESS_LOG_APPROVER_NAME, user.isPresent() ? user.get().getRealName() : ""); taskLogMap.put(PRINT_VAR_PROCESS_LOG_UNIT, user.isPresent() ? user.get().getOrganizationalUnitName() : ""); taskLogMap.put(PRINT_VAR_PROCESS_LOG_POSITION, user.isPresent() && Objects.nonNull(user.get().getJob()) ? user.get().getJob().getName() : ""); taskLogMap.put(PRINT_VAR_PROCESS_LOG_ADVICE, taskLog.getAdvice()); + taskLogMap.put(PRINT_VAR_PROCESS_LOG_OPERATION, taskLog.getOperationDesc()); + taskLogMap.put(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT, taskLog.getResult().getStatus()); taskLogMap.put(PRINT_VAR_PROCESS_LOG_OPERATION_TIME, sdf.format(taskLog.getCreateTime())); taskLogMap.put(PRINT_VAR_PROCESS_LOG_SIGNATURE, taskLog.getSignatureUrl()); taskLogs.add(taskLogMap); From c6c62f2f85d68dbf613b6b4a9dbf449211ccdab3 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 19:31:41 +0800 Subject: [PATCH 18/58] =?UTF-8?q?feat=20-=20=E5=90=8C=E6=84=8F=E7=9A=84?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=88=96=E6=96=B0=E5=A2=9E=E6=B5=81=E7=A8=8B=E5=8F=98=E9=87=8F?= =?UTF-8?q?=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/request/bpmn/task/BpmnTaskAuditDTO.java | 6 ++++++ .../workflow/core/engine/cmd/CustomApproveTaskCmd.java | 4 ++++ .../core/engine/cmd/CustomApproveTaskWithFormCmd.java | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java index 731913a0a..61b1a17bf 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java @@ -16,6 +16,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.List; +import java.util.Map; /** * 审批任务节点的入参模型 @@ -103,4 +104,9 @@ public class BpmnTaskAuditDTO { */ @Deprecated private String operationDesc; + + /** + * 更新或新增流程变量 + */ + private Map variables; } 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 3829b5c25..30bcbcdc9 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 @@ -83,6 +83,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria * 指定节点类型 */ private List nodeTypes; + private Map variables; @Override public String paramToJsonString() { @@ -94,6 +95,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria params.put("approver", JSON.toJSONString(approver)); params.put("nextApprover", JSON.toJSONString(nextApprover)); params.put("nodeTypes", JSON.toJSONString(nodeTypes)); + params.put("variables", JSON.toJSONString(variables)); return JSON.toJSONString(params); } @@ -117,6 +119,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria } else { this.operationDesc = "已同意"; } + this.variables = dto.getVariables(); } @Override @@ -158,6 +161,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 recordSignature(task, runtimeService); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java index 81df46654..050ee28fc 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java @@ -97,6 +97,10 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen * 表单数据 */ private final Map formVariables; + /** + * 更新或新增的流程变量 + */ + private final Map variables; @Override public String paramToJsonString() { @@ -109,6 +113,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen params.put("nextApprover", JSON.toJSONString(nextApprover)); params.put("nodeTypes", JSON.toJSONString(nodeTypes)); params.put("formVariables", JSON.toJSONString(formVariables)); + params.put("variables", JSON.toJSONString(variables)); return JSON.toJSONString(params); } @@ -133,6 +138,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen } else { this.operationDesc = "已同意"; } + this.variables = dto.getVariables(); } @Override @@ -174,7 +180,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen nextApprover); } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); - + runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 recordSignature(task, runtimeService); From 0161cddf034391f6a2b11ff9b69933c1b93d65c5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 20 Oct 2025 19:58:45 +0800 Subject: [PATCH 19/58] =?UTF-8?q?feat=20-=20=E8=B0=83=E6=95=B4=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=97=B6=E7=9A=84=E5=8A=A8=E6=80=81=E5=8A=A0=E7=AD=BE?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=8F=AF=E8=83=BD=E4=BA=A7=E7=94=9F=E7=9A=84?= =?UTF-8?q?=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../initializer/RecoverDynamicCounterSignProcess.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java index 07de639d0..e59f5fb70 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/initializer/RecoverDynamicCounterSignProcess.java @@ -6,11 +6,11 @@ import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper; import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord; import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService; import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; -import org.flowable.engine.impl.persistence.deploy.DeploymentManager; -import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.context.SmartLifecycle; @@ -83,13 +83,13 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle { ) )); - DeploymentManager deploymentManager = springProcessEngineConfiguration.getDeploymentManager(); + RepositoryService repositoryService = springProcessEngineConfiguration.getRepositoryService(); grouped.forEach((k, v) -> { if (runningProcessIds.contains(k)) { log.info("recover dynamic counter sign process instance id: {}", k); + BpmnModel bpmnModel = repositoryService.getBpmnModel(v.get(0).getProcessDefinitionId()); + Process process = bpmnModel.getMainProcess(); - ProcessDefinition processDefinitionEntity = deploymentManager.findDeployedProcessDefinitionById(v.get(0).getProcessDefinitionId()); - Process process = deploymentManager.resolveProcessDefinition(processDefinitionEntity).getProcess(); v.forEach(sign -> { UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId()); BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR; From ba95e4850f3e4737a3cf4e354b387f049e202ec4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 21 Oct 2025 10:51:48 +0800 Subject: [PATCH 20/58] =?UTF-8?q?feat=20-=20=E6=96=B0=E5=A2=9E=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8B=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=9A=E5=8A=A1=E4=BC=A0=E5=85=A5=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 8 +++ .../common/model/dto/CustomDocDTO.java | 49 ++++++++++++++++++ .../process/BpmnProcessInstanceCreateDTO.java | 17 +++++++ .../impl/BpmnProcessInstanceServiceImpl.java | 50 +++++++++++++++++++ ...opyTemplateFileTaskEvent_105_Listener.java | 25 ++++++++++ 5 files changed, 149 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.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 f3f701af5..97f0b30f2 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 @@ -252,6 +252,14 @@ public interface BpmnConstants { * 签署业务发起流程实例时,重新选择的文档tag 集合 */ String SIGN_PROCESS_ENABLE_DOC_IDS = "[_SIGN_PROCESS_ENABLE_DOC_IDS_]"; + /** + * 签署业务自定义业务传入的文档集合 + */ + String SIGN_BIZ_CUSTOM_DOCS = "[_SIGN_BIZ_CUSTOM_DOCS_]"; + /** + * 签署业务自定义文档的顺序位置类型 + */ + String SIGN_BIZ_CUSTOM_DOC_ADD_TYPE = "[_SIGN_BIZ_CUSTOM_DOC_ADD_TYPE_]"; /** * 签署业务,基于业务自定义变量的传入 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java new file mode 100644 index 000000000..73b87367b --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java @@ -0,0 +1,49 @@ +package cn.axzo.workflow.common.model.dto; + +import cn.axzo.workflow.common.enums.FileTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 签署文件记录信息 + * + * @author wangli + * @since 2025-04-03 11:21 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CustomDocDTO implements Serializable { + + private static final long serialVersionUID = -8709597975507074853L; + + /** + * 文件名称,可能会包含变量 + */ + private String fileName; + + /** + * 文件的标签 + */ + private String fileTag; + + /** + * 文件 wps code + *

+ * wps 文件的标识,通过{@link cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi#createFile(cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest)} 接口创建文件后返回的 fileCode + */ + private String fileCode; + + /** + * 文件的类型 + */ + private FileTypeEnum fileType; + +} 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 1b57e3a1a..8e05cd85b 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 @@ -2,6 +2,7 @@ package cn.axzo.workflow.common.model.request.bpmn.process; import cn.axzo.workflow.common.constant.BpmnConstants; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -120,6 +121,22 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF @ApiModelProperty(value = "签署业务发起时,选择的文档") private List docIds; + /** + * "签字业务"专用 + *

+ * 业务自定义的文档 + */ + @ApiModelProperty(value = "业务自定义文档") + private List customDocs; + + /** + * "签字业务"专用,自定义文档的顺序位置信息,在流程模板配置文档之前还是之后 + *

+ * 可选值:first(之前)、last(之后), 如果为空,默认为 last + */ + @ApiModelProperty(value = "自定义文档顺序位置", notes = "可选值:first(之前)、last(之后), 如果为空,默认为 last") + private String docAddType; + /** * 仅针对签署业务,设置审批完成后的最终签署人列表,该属性仅为透传,业务消费时,请从 MQ 广播事件中的 variables 中通过 key= {@link BpmnConstants#SIGNATORIES } 获取 */ 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 4b42ba366..4399045f0 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 @@ -14,6 +14,7 @@ import cn.axzo.workflow.common.enums.BusinessTypeEnum; import cn.axzo.workflow.common.enums.ButtonVisibleScopeEnum; import cn.axzo.workflow.common.enums.WorkspaceType; import cn.axzo.workflow.common.exception.WorkflowEngineException; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.dto.SignFileDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; import cn.axzo.workflow.common.model.request.BpmnApproveConf; @@ -152,8 +153,10 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CREATE_PARAM_ERROR; @@ -187,6 +190,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIA import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATORIES; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_TYPE; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_PROCESS_ENABLE_DOC_IDS; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_VARIABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; @@ -495,6 +500,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getVariables().put(SIGN_PROCESS_ENABLE_DOC_IDS, dto.getDocIds()); dto.getVariables().put(SIGN_VARIABLE, dto.getBizCustomVariables()); dto.getVariables().put(SIGNATORIES, dto.getSignatories()); + dto.getVariables().put(SIGN_BIZ_CUSTOM_DOCS, dto.getCustomDocs()); + dto.getVariables().put(SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, StringUtils.hasText(dto.getDocAddType()) ? dto.getDocAddType() : "last"); } }); dto.getVariables().put(INTERNAL_INITIATOR, dto.getInitiator().toJson()); @@ -1873,6 +1880,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); List docs = commandExecutor.execute(new CustomGetModelDocsCmd(dto.getProcessInstanceId(), true, extAxModelDocMapper, extAxReModelService)); + // 获取业务自定义传入的文档 + getAndAddBizCustomDocs(dto.getProcessInstanceId(), docs); + Map readStatusMap = new HashMap<>(); if (Objects.nonNull(dto.getAssigner())) { readStatusMap.putAll(extAxReadRecordService.queryReadStatus(ApproverReadStatusDTO.builder() @@ -1895,4 +1905,44 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic t.setReadStatus(readStatusMap.getOrDefault(t.getId(), false)); }); } + + private List getAndAddBizCustomDocs(String processInstanceId, List docs) { + List bizCustomDocs = Optional.ofNullable( + runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) + .orElse(Collections.emptyList()); + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, String.class); + + boolean appendLast = "last".equals(customAddType); + Comparator orderComparator = Comparator.comparing( + DocBaseVO::getOrder, Comparator.nullsFirst(Comparator.naturalOrder())); + + Optional baseOpt; + Stream filtered = docs.stream().filter(Objects::nonNull); + if (appendLast) { + baseOpt = filtered.max(orderComparator); + } else { + baseOpt = filtered.min(orderComparator); + } + + int baseOrder = baseOpt.map(DocBaseVO::getOrder).orElse(0); + String tenantId = baseOpt.map(DocBaseVO::getTenantId).orElse(null); + + AtomicInteger orderCounter = new AtomicInteger(baseOrder); + int delta = appendLast ? 1 : -1; + + List docBaseVOS = BeanMapper.copyList(bizCustomDocs, DocBaseVO.class, (s, t) -> { + t.setStatus(true); + t.setTempFile(false); + t.setOrder(orderCounter.addAndGet(delta)); + t.setTenantId(tenantId); + }); + + if (appendLast) { + docs.addAll(docBaseVOS); + } else { + docs.addAll(0, docBaseVOS); + } + return docs; + + } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index a5d8b6e0e..61a003629 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -3,6 +3,7 @@ package cn.axzo.workflow.server.controller.listener.task; import cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi; import cn.axzo.nanopart.doc.api.index.request.CopyNodeRequest; import cn.axzo.workflow.common.enums.FileTypeEnum; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.dto.SignFileDTO; import cn.axzo.workflow.common.model.dto.VariableObjectDTO; import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf; @@ -23,6 +24,7 @@ import cn.axzo.workflow.server.common.util.WpsUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.flowable.engine.RuntimeService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.ProcessDefinitionUtil; @@ -39,6 +41,8 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_TYPE; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; /** @@ -96,6 +100,27 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve } else { // 复制基础模板 List docTemplates = copyTempTemplate(docs); + // 处理业务自定义文档 + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + List customDocs = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class); + List customDocTemplates = new ArrayList<>(); + for (int i = 0; i < customDocs.size(); i++) { + customDocTemplates.add(SignFileDTO.builder() + .id(i - (i + 1L)) // 负数 ID,避免冲突 + .fileName(customDocs.get(i).getFileName()) + .templateName(customDocs.get(i).getFileName()) + .fileTag(customDocs.get(i).getFileTag()) + .fileCode(customDocs.get(i).getFileCode()) + .fileType(customDocs.get(i).getFileType()) + .build()); + } + + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, String.class); + if (Objects.equals("last", customAddType)) { + docTemplates.addAll(customDocTemplates); + } else { + docTemplates.addAll(0, customDocTemplates); + } processSign.setDocTemplate(docTemplates); List archives = replaceTemplateVariable(docTemplates, processEngineConfiguration, processInstanceId); From 5298b5f3206de768f7a457670ea44bb03a141660 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 22 Oct 2025 10:09:38 +0800 Subject: [PATCH 21/58] =?UTF-8?q?feat=20-=20=E4=BF=AE=E5=A4=8D=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BB=85=E4=B8=9A=E5=8A=A1=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=98=AF=E5=8F=91=E7=8E=B0=E7=9A=84=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/CustomDocDTO.java | 11 +++++++- .../process/BpmnProcessInstanceCreateDTO.java | 11 ++++++++ .../impl/BpmnProcessInstanceServiceImpl.java | 8 +++++- .../server/WorkflowEngineApplication.java | 2 +- ...opyTemplateFileTaskEvent_105_Listener.java | 28 +++++++++++-------- .../server/controller/web/TestController.java | 25 +++++++++++++++++ 6 files changed, 70 insertions(+), 15 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java index 73b87367b..40d4f5de5 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import javax.validation.constraints.NotBlank; import java.io.Serializable; /** @@ -23,7 +24,10 @@ import java.io.Serializable; public class CustomDocDTO implements Serializable { private static final long serialVersionUID = -8709597975507074853L; - + /** + * 该属性内部使用,无需赋值 + */ + private Long id; /** * 文件名称,可能会包含变量 */ @@ -40,6 +44,11 @@ public class CustomDocDTO implements Serializable { * wps 文件的标识,通过{@link cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi#createFile(cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest)} 接口创建文件后返回的 fileCode */ private String fileCode; + /** + * oss 地址的文件标识 + */ + @NotBlank(message = "文件的 oss key 不能为空") + private String fileKey; /** * 文件的类型 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 8e05cd85b..88cfab976 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 @@ -11,6 +11,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.util.CollectionUtils; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -149,4 +150,14 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF } return null; } + + public List getCustomDocs() { + if (CollectionUtils.isEmpty(customDocs)) { + return customDocs; + } + for (int i = 0; i < customDocs.size(); i++) { + customDocs.get(i).setId(i - (i + 1L)); // 负数 ID,避免冲突 + } + return customDocs; + } } \ No newline at end of file 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 4399045f0..45d59fca0 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 @@ -1907,6 +1907,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } private List getAndAddBizCustomDocs(String processInstanceId, List docs) { + HistoricProcessInstance processInstance = null; + if (CollectionUtils.isEmpty(docs)) { + processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + } List bizCustomDocs = Optional.ofNullable( runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) .orElse(Collections.emptyList()); @@ -1925,7 +1929,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } int baseOrder = baseOpt.map(DocBaseVO::getOrder).orElse(0); - String tenantId = baseOpt.map(DocBaseVO::getTenantId).orElse(null); + String tenantId = baseOpt.map(DocBaseVO::getTenantId).orElse(Objects.nonNull(processInstance) ? processInstance.getTenantId() : null); AtomicInteger orderCounter = new AtomicInteger(baseOrder); int delta = appendLast ? 1 : -1; @@ -1933,8 +1937,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic List docBaseVOS = BeanMapper.copyList(bizCustomDocs, DocBaseVO.class, (s, t) -> { t.setStatus(true); t.setTempFile(false); + t.setTemplateName(s.getFileName()); t.setOrder(orderCounter.addAndGet(delta)); t.setTenantId(tenantId); + t.setFileRelationId(s.getFileKey()); }); if (appendLast) { diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java index 31e42d3b1..5a3685b65 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/WorkflowEngineApplication.java @@ -12,7 +12,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @MapperScan({"cn.axzo.workflow.core.**.mapper", "cn.axzo.workflow.admin.**.mapper"}) -@ComponentScan({"cn.axzo.workflow"}) +@ComponentScan({"cn.axzo.workflow", "cn.axzo.oss"}) @EnableFeignClients({"cn.axzo.oss", "cn.axzo.riven.client.feign", "cn.axzo.msg.center", "cn.axzo.basics.profiles"}) @SpringBootApplication(exclude = RabbitAutoConfiguration.class) @EnableTransactionManagement diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index 61a003629..29f567740 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -94,24 +94,28 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve processSign.setProcessInstanceId(processInstanceId); processSign.setSignType(signConfig.get().getSignType().getType()); processSign.setPendingMessageId(signConfig.get().getSignPendingProperty().getPendingMessageId()); - if (CollectionUtils.isEmpty(docs)) { + + // 业务自定义文档 + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + List customDocs = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class); + + if (CollectionUtils.isEmpty(docs) && CollectionUtils.isEmpty(customDocs)) { processSign.setDocTemplate(Collections.emptyList()); processSign.setFileArchive(Collections.emptyList()); } else { // 复制基础模板 List docTemplates = copyTempTemplate(docs); - // 处理业务自定义文档 - RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - List customDocs = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class); + List customDocTemplates = new ArrayList<>(); - for (int i = 0; i < customDocs.size(); i++) { + for (CustomDocDTO customDoc : customDocs) { customDocTemplates.add(SignFileDTO.builder() - .id(i - (i + 1L)) // 负数 ID,避免冲突 - .fileName(customDocs.get(i).getFileName()) - .templateName(customDocs.get(i).getFileName()) - .fileTag(customDocs.get(i).getFileTag()) - .fileCode(customDocs.get(i).getFileCode()) - .fileType(customDocs.get(i).getFileType()) + .id(customDoc.getId()) + .fileName(customDoc.getFileName()) + .templateName(customDoc.getFileName()) + .fileTag(customDoc.getFileTag()) + .fileCode(customDoc.getFileCode()) + .fileKey(customDoc.getFileKey()) + .fileType(customDoc.getFileType()) .build()); } @@ -142,7 +146,7 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve signFileDTO.setFileType(template.getFileType()); signFileDTO.setFileCode(template.getFileCode()); if (Objects.equals(template.getFileType(), FileTypeEnum.WORD) || Objects.equals(template.getFileType(), FileTypeEnum.EXCEL)) { - String fileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, template.getFileCode(), null, template.getTemplateName() + template.getFileType().getSuffix()); + String fileKey = wpsUtil.wpsFileVariableReplace(wpsReplaceVariables, template.getFileCode(), template.getFileKey(), template.getTemplateName() + template.getFileType().getSuffix()); signFileDTO.setFileKey(fileKey); } archives.add(signFileDTO); 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 ffd36aa5c..cee43032d 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,6 +1,9 @@ package cn.axzo.workflow.server.controller.web; import cn.axzo.framework.domain.ServiceException; +import cn.axzo.oss.http.api.ServerFileServiceSdk; +import cn.axzo.oss.http.model.ServerFileUploadSdkRequest; +import cn.axzo.oss.http.model.ServerFileUploadSdkResponse; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.model.dto.VariableObjectDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO; @@ -22,6 +25,7 @@ import cn.axzo.workflow.server.xxljob.SpecifyProcessInstanceSyncEsJobHandler; import cn.azxo.framework.common.model.CommonResponse; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.FlowElement; import org.flowable.common.engine.impl.interceptor.CommandExecutor; @@ -53,6 +57,8 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Date; import java.util.List; import java.util.Map; @@ -110,6 +116,10 @@ public class TestController { private SpecifyProcessInstanceSyncEsJobHandler specifyProcessInstanceSyncEsJobHandler; @Resource private TaskService taskService; + @Resource + private SupportRefreshProperties refreshProperties; + @Resource + private ServerFileServiceSdk serverFileServiceSdk; @RepeatSubmit @GetMapping("/test") @@ -397,5 +407,20 @@ public class TestController { taskService.complete(taskId); return CommonResponse.success(true); } + + @GetMapping("/properties/refresh") + public CommonResponse refreshProperties() { + return CommonResponse.success(JSON.toJSONString(refreshProperties)); + } + + @PostMapping("/server/file/upload") + @SneakyThrows + public CommonResponse serverFileUpload(@RequestBody ServerFileUploadSdkRequest request) { + String filePath = "/Users/wangli/Downloads/锦绣碧湖B区B-1工程模板施工专项方案4-30.docx"; + byte[] fileBytes = Files.readAllBytes(Paths.get(filePath)); + request.setFileContent(fileBytes); + ServerFileUploadSdkResponse serverFileUploadSdkResponse = serverFileServiceSdk.uploadFile(request); + return CommonResponse.success(JSON.toJSONString(serverFileUploadSdkResponse)); + } } From a0244b7dca6450634858c92c1f45e6ba8bf1f46e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 23 Oct 2025 16:38:04 +0800 Subject: [PATCH 22/58] =?UTF-8?q?feat=20-=20=E6=96=B0=E5=A2=9E=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E9=85=8D=E7=BD=AE=E9=A1=B5=EF=BC=8C=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E7=9A=84=E4=BA=8C=E7=BA=A7=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/constant/VariableConstants.java | 4 +++- .../controller/web/manage/PrintAdminController.java | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java index e9853631b..770335072 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java @@ -66,7 +66,9 @@ public interface VariableConstants { String PRINT_VAR_PROCESS_LOG_SIGNATURE = "signature"; String PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC = "电子签名"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT = "activityResult"; - String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC = "节点状态"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC = "审批结果"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME = "activityOperationTime"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC = "签名日期"; String PRINT_VAR_PROCESS_LOG_OPERATION = "operationDesc"; String PRINT_VAR_PROCESS_LOG_OPERATION_DESC = "操作描述"; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 0dd28f209..bc2d0fdf9 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -87,7 +87,10 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_NODE_TYPE; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_ADVICE_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_APPROVER_NAME; @@ -322,8 +325,13 @@ public class PrintAdminController implements PrintAdminApi { .setCode(activity.getId()) .setFieldCategoryType(signature) .setFieldFormType("signature") - .setAttributes(Lists.newArrayList(new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_SIGNATURE).setName(PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT), - new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ADVICE).setName(PRINT_VAR_PROCESS_LOG_ADVICE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT)))) + .setAttributes(Lists.newArrayList( + new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_APPROVER_NAME).setName(PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT), + new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT).setName(PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT), + new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ADVICE).setName(PRINT_VAR_PROCESS_LOG_ADVICE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT), + new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_SIGNATURE).setName(PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT), + new FieldAttributeDTO().setCode(PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME).setName(PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC).setFieldFormType(FORM_FIELD_TYPE_INPUT) + ))) .collect(Collectors.toList()) ); From 50ae5ed25b84c6be67513eb5214b8868eeb13551 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 24 Oct 2025 13:47:26 +0800 Subject: [PATCH 23/58] =?UTF-8?q?feat=20-=20=E6=96=B0=E5=A2=9E=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8B=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessInstanceApi.java | 12 ++++ ...BpmnProcessInstanceVariablesUpdateDTO.java | 38 ++++++++++++ .../CustomOverrideProcessVariablesCmd.java | 61 +++++++++++++++++++ .../service/BpmnProcessInstanceService.java | 3 + .../impl/BpmnProcessInstanceServiceImpl.java | 8 +++ .../bpmn/BpmnProcessInstanceController.java | 11 ++++ 6 files changed, 133 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceVariablesUpdateDTO.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomOverrideProcessVariablesCmd.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 82cda512c..a8ada187a 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 @@ -17,6 +17,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre 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.BpmnProcessInstanceVariablesUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO; @@ -180,6 +181,17 @@ public interface ProcessInstanceApi { CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId); + /** + * 更新流程实例中的业务自定义变量集合 + * + * @param dto + * @return + */ + @Operation(summary = "更新流程实例中的业务自定义变量集合") + @PostMapping("/api/process/instance/biz/custom/variables/update") + @InvokeMode(SYNC) + CommonResponse updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto); + /** * 查询所有的审批流 * diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceVariablesUpdateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceVariablesUpdateDTO.java new file mode 100644 index 000000000..758142593 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceVariablesUpdateDTO.java @@ -0,0 +1,38 @@ +package cn.axzo.workflow.common.model.request.bpmn.process; + +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import java.util.Map; + +/** + * 更新流程实例中变量集合的入参模型 + * + * @author wangli + * @since 2025-10-24 10:56 + */ +@ApiModel("更新流程实例中变量集合的入参模型") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BpmnProcessInstanceVariablesUpdateDTO { + + /** + * 流程实例 ID + */ + @NotBlank(message = "流程实例 ID 不能为空") + private String processInstanceId; + + /** + * 业务管理中定义变量的入参, 如果 key 在创建时已存在,则进行覆盖更新,否则新增变量 + *

+ * 对应创建流程实例中的 {@link BpmnProcessInstanceCreateDTO#bizCustomVariables} 属性 + */ + private Map bizCustomVariables; + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomOverrideProcessVariablesCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomOverrideProcessVariablesCmd.java new file mode 100644 index 000000000..c9f57714b --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomOverrideProcessVariablesCmd.java @@ -0,0 +1,61 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.exception.WorkflowEngineException; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +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.ProcessInstance; +import org.springframework.util.CollectionUtils; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS; + +/** + * 覆写指定流程中的变量 + * + * @author wangli + * @since 2025-02-08 10:14 + */ +@Slf4j +public class CustomOverrideProcessVariablesCmd extends AbstractCommand implements Serializable { + private static final long serialVersionUID = 1L; + private final String processInstanceId; + private final Map variables; + + public CustomOverrideProcessVariablesCmd(String processInstanceId, Map variables) { + this.processInstanceId = processInstanceId; + this.variables = variables; + } + + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + params.put("formVariables", variables); + return JSON.toJSONString(params); + } + + @Override + public Void executeInternal(CommandContext commandContext) { + if (CollectionUtils.isEmpty(variables)) { + return null; + } + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + if (Objects.nonNull(processInstance)) { + throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); + } + + runtimeService.setVariables(processInstanceId, variables); + return null; + } +} 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 7432d5fb7..692f8772d 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 @@ -10,6 +10,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre 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.BpmnProcessInstanceVariablesUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO; @@ -211,4 +212,6 @@ public interface BpmnProcessInstanceService { boolean hasPrintTemplate(String processInstanceId, String processDefinitionId); List processInstanceSelectDocs(ProcessDocQueryDTO dto); + + void overrideProcessVariables(BpmnProcessInstanceVariablesUpdateDTO 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 45d59fca0..ff25e1daa 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 @@ -30,6 +30,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre 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.BpmnProcessInstanceVariablesUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; @@ -67,6 +68,7 @@ import cn.axzo.workflow.core.engine.cmd.CustomCarbonCopyUserSelectorCmd; import cn.axzo.workflow.core.engine.cmd.CustomForecastUserTaskAssigneeCmd; import cn.axzo.workflow.core.engine.cmd.CustomGetModelDocsCmd; import cn.axzo.workflow.core.engine.cmd.CustomOverrideFormVariablesByLatestInstanceCmd; +import cn.axzo.workflow.core.engine.cmd.CustomOverrideProcessVariablesCmd; import cn.axzo.workflow.core.engine.listener.EngineExecutionStartListener; import cn.axzo.workflow.core.repository.entity.ExtAxBpmnFormRelation; import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; @@ -1951,4 +1953,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic return docs; } + + @Override + public void overrideProcessVariables(BpmnProcessInstanceVariablesUpdateDTO dto) { + CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); + commandExecutor.execute(new CustomOverrideProcessVariablesCmd(dto.getProcessInstanceId(), dto.getBizCustomVariables())); + } } 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 6cf182166..934b79e15 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 @@ -21,6 +21,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCre 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.BpmnProcessInstanceVariablesUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; @@ -384,6 +385,16 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController return success(processInstance.getProcessVariables()); } + @Override + @Operation(summary = "更新流程实例中的业务自定义变量集合") + @PostMapping("/biz/custom/variables/update") + public CommonResponse updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto) { + log.info("更新流程实例中的业务自定义变量集合 updateProcessBizCustomVariables===>>>参数:{}", JSONUtil.toJsonStr(dto)); + ; + bpmnProcessInstanceService.overrideProcessVariables(dto); + return success(true); + } + /** * 枢智业务(审批台账专用) * From 8d97f6ffc3486a79b59a95356aa420cedb01098c Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 24 Oct 2025 16:12:55 +0800 Subject: [PATCH 24/58] =?UTF-8?q?fix=20-=20=E8=B0=83=E6=95=B4=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E7=9A=84=E5=85=A5=E5=8F=82=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=AE=8C=E6=95=B4=E6=8E=A7=E5=88=B6=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/workflow/common/constant/BpmnConstants.java | 6 +++++- .../axzo/workflow/common/model/dto/CustomDocDTO.java | 9 ++++++--- .../bpmn/process/BpmnProcessInstanceCreateDTO.java | 10 +++++++++- .../service/impl/BpmnProcessInstanceServiceImpl.java | 8 +++++--- .../FirstCopyTemplateFileTaskEvent_105_Listener.java | 4 ++-- 5 files changed, 27 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 97f0b30f2..9b5cc0dcd 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 @@ -259,7 +259,11 @@ public interface BpmnConstants { /** * 签署业务自定义文档的顺序位置类型 */ - String SIGN_BIZ_CUSTOM_DOC_ADD_TYPE = "[_SIGN_BIZ_CUSTOM_DOC_ADD_TYPE_]"; + String SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE = "[_SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE_]"; + /** + * 签署业务,业务对所有文档顺序排序 + */ + String SIGN_BIZ_BASED_FILE_TAG_ORDER = "[_SIGN_BIZ_BASED_FILE_TAG_ORDER_]"; /** * 签署业务,基于业务自定义变量的传入 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java index 40d4f5de5..ffad37e9c 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.io.Serializable; /** @@ -29,8 +30,9 @@ public class CustomDocDTO implements Serializable { */ private Long id; /** - * 文件名称,可能会包含变量 + * 文件名称 */ + @NotBlank(message = "业务自定义文件名称不能为空") private String fileName; /** @@ -39,7 +41,7 @@ public class CustomDocDTO implements Serializable { private String fileTag; /** - * 文件 wps code + * 文件 wps code,如果有则传入 *

* wps 文件的标识,通过{@link cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi#createFile(cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest)} 接口创建文件后返回的 fileCode */ @@ -47,12 +49,13 @@ public class CustomDocDTO implements Serializable { /** * oss 地址的文件标识 */ - @NotBlank(message = "文件的 oss key 不能为空") + @NotBlank(message = "业务自定义文件的 oss key 不能为空") private String fileKey; /** * 文件的类型 */ + @NotNull(message = "业务自定义文件的类型不能为空") private FileTypeEnum fileType; } 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 88cfab976..4d719cde6 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 @@ -136,7 +136,15 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF * 可选值:first(之前)、last(之后), 如果为空,默认为 last */ @ApiModelProperty(value = "自定义文档顺序位置", notes = "可选值:first(之前)、last(之后), 如果为空,默认为 last") - private String docAddType; + private String docAddOrderType = "last"; + + /** + * "签字业务"专用, 该属性与{@link BpmnProcessInstanceCreateDTO#docAddOrderType} 互斥 + *

+ * 业务对所有文档的顺序覆盖,必须对全量文档进行设置 + */ + @ApiModelProperty(value = "业务对所有文档的顺序覆盖") + public List basedFileTagOrder; /** * 仅针对签署业务,设置审批完成后的最终签署人列表,该属性仅为透传,业务消费时,请从 MQ 广播事件中的 variables 中通过 key= {@link BpmnConstants#SIGNATORIES } 获取 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 ff25e1daa..75c6149d8 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 @@ -192,8 +192,9 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIA import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATORIES; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_BASED_FILE_TAG_ORDER; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; -import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_PROCESS_ENABLE_DOC_IDS; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_VARIABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; @@ -503,7 +504,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getVariables().put(SIGN_VARIABLE, dto.getBizCustomVariables()); dto.getVariables().put(SIGNATORIES, dto.getSignatories()); dto.getVariables().put(SIGN_BIZ_CUSTOM_DOCS, dto.getCustomDocs()); - dto.getVariables().put(SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, StringUtils.hasText(dto.getDocAddType()) ? dto.getDocAddType() : "last"); + dto.getVariables().put(SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, StringUtils.hasText(dto.getDocAddOrderType()) ? dto.getDocAddOrderType() : "last"); + dto.getVariables().put(SIGN_BIZ_BASED_FILE_TAG_ORDER, dto.getBasedFileTagOrder()); } }); dto.getVariables().put(INTERNAL_INITIATOR, dto.getInitiator().toJson()); @@ -1916,7 +1918,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic List bizCustomDocs = Optional.ofNullable( runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) .orElse(Collections.emptyList()); - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, String.class); + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); boolean appendLast = "last".equals(customAddType); Comparator orderComparator = Comparator.comparing( diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index 29f567740..b4dd6d9d2 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -42,7 +42,7 @@ import java.util.Objects; import java.util.Optional; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; -import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; /** @@ -119,7 +119,7 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve .build()); } - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_TYPE, String.class); + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); if (Objects.equals("last", customAddType)) { docTemplates.addAll(customDocTemplates); } else { From 06301087d51bf4ddf609e083eaa5b4ff9398598e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 24 Oct 2025 17:39:06 +0800 Subject: [PATCH 25/58] =?UTF-8?q?feat=20-=20=E6=B5=81=E7=A8=8B=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E5=88=9B=E5=BB=BA=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= 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 4d719cde6..dea65772e 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 @@ -131,7 +131,7 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF private List customDocs; /** - * "签字业务"专用,自定义文档的顺序位置信息,在流程模板配置文档之前还是之后 + * "签字业务"专用,自定义文档的顺序位置信息,在流程模板配置文档之前还是之后, 该属性与{@link BpmnProcessInstanceCreateDTO#basedFileTagOrder} 互斥 *

* 可选值:first(之前)、last(之后), 如果为空,默认为 last */ From 5ef2d94adc7a2d3b217bc485e3d31862c7d2de03 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 24 Oct 2025 17:39:23 +0800 Subject: [PATCH 26/58] =?UTF-8?q?feat=20-=20=E6=B5=81=E7=A8=8B=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E5=88=9B=E5=BB=BA=E6=8E=A5=E5=8F=A3=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/api/WorkflowCoreService.java | 37 +++++++++++++++++++ .../starter/api/WorkflowManageService.java | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) 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 883e85801..5bba3119e 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 @@ -3,6 +3,7 @@ package cn.axzo.workflow.starter.api; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.model.dto.SignFileDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; +import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO; import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO; import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; @@ -15,6 +16,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceChe 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.process.BpmnProcessInstanceVariablesUpdateDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO; @@ -36,6 +38,8 @@ import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO; import cn.axzo.workflow.common.model.request.form.definition.StartFormSearchDTO; import cn.axzo.workflow.common.model.request.form.instance.FormDetailDTO; import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO; +import cn.axzo.workflow.common.model.request.form.instance.FromDataSearchDTO; +import cn.axzo.workflow.common.model.request.form.model.WpsFileConfigVariableDTO; 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; @@ -43,6 +47,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.NodesByModelVO; import cn.axzo.workflow.common.model.response.bpmn.process.doc.DocPendingVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo; import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO; +import cn.axzo.workflow.common.model.response.form.instance.FormDataVO; import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO; import cn.axzo.workflow.common.util.ThreadUtil; import cn.axzo.workflow.starter.feign.ext.WorkflowEngineStarterFeignConfiguration; @@ -152,6 +157,7 @@ public interface WorkflowCoreService { /** * 获取指定审批业务的流程表单设置, + * * @param dto * @return */ @@ -172,6 +178,26 @@ public interface WorkflowCoreService { @InvokeMode(SYNC) FormInstanceVO getFormInstance(@Validated @RequestBody FormDetailDTO dto); + /** + * 获取指定表单审批的实例数据 + * + * @param dto + * @return + */ + @PostMapping("/api/form/admin/instance/form/data") + @InvokeMode(SYNC) + List getFormData(@Validated @RequestBody FromDataSearchDTO dto); + + /** + * 获取 WPS 文档中所有可配置的流程相关变量 + * + * @param dto + * @return + */ + @PostMapping("/api/form/admin/wps/file/config/variables") + @InvokeMode(SYNC) + List getWpsFileConfigVariables(@Validated @RequestBody WpsFileConfigVariableDTO dto); + /** * 创建流程前的节点列表 * 用于发起人自选 @@ -283,6 +309,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/biz/custom/variables/update") + @InvokeMode(SYNC) + Boolean updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto); + /** * 校验指定流程实例下,是否存在指定的审批人正处理待审批 * 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 8a7f95145..fc13dd518 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 @@ -120,7 +120,7 @@ public interface WorkflowManageService { @GetMapping("/api/print/admin/field/variables") @Manageable @InvokeMode(SYNC) - Map getPrintFieldVariables(@NotBlank(message = "流程实例不能为空") @RequestParam String processInstanceId); + Map getPrintFieldVariables(@NotBlank(message = "流程实例不能为空") @RequestParam String processInstanceId, @RequestParam(required = false, defaultValue = "true") Boolean throwException); /** * 查询管理员 From bb57f7eb927e2f8f2085c473dbfaa9a54a3a402c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 24 Oct 2025 17:49:47 +0800 Subject: [PATCH 27/58] =?UTF-8?q?feat=20-=20=E8=A7=A3=E5=86=B3=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=BC=95=E6=93=8E=E6=A1=86=E6=9E=B6=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/conf/FlowableConfiguration.java | 2 ++ .../cfg/CustomDefaultInternalJobManager.java | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cfg/CustomDefaultInternalJobManager.java 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 acca4c4c1..53fc11e8e 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 @@ -2,6 +2,7 @@ package cn.axzo.workflow.core.conf; import cn.axzo.workflow.core.common.utils.SpringContextUtils; import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; +import cn.axzo.workflow.core.engine.cfg.CustomDefaultInternalJobManager; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.formhandler.CustomFormFieldHandler; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; @@ -143,6 +144,7 @@ public class FlowableConfiguration { configuration.setFormFieldValidationEnabled(true); configuration.setFormFieldHandler(new CustomFormFieldHandler()); configuration.setConfigurators(Lists.newArrayList(new CustomJobServiceConfiguration())); + configuration.setInternalJobManager(new CustomDefaultInternalJobManager(configuration)); }; } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cfg/CustomDefaultInternalJobManager.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cfg/CustomDefaultInternalJobManager.java new file mode 100644 index 000000000..b573e1f83 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cfg/CustomDefaultInternalJobManager.java @@ -0,0 +1,31 @@ +package cn.axzo.workflow.core.engine.cfg; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.impl.cfg.DefaultInternalJobManager; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.job.api.Job; + +/** + * 为解决引擎底层定时任务的 NPE 问题 + * + * @author wangli + * @since 2025-10-24 17:42 + */ +@Slf4j +public class CustomDefaultInternalJobManager extends DefaultInternalJobManager { + public CustomDefaultInternalJobManager(ProcessEngineConfigurationImpl processEngineConfiguration) { + super(processEngineConfiguration); + } + + @Override + protected void handleJobDeleteInternal(Job job) { + ExecutionEntity executionEntity = getExecutionEntityManager().findById(job.getExecutionId()); + log.info("handleJobDeleteInternal job.eId:{}, job.piId:{} ", job.getExecutionId(), job.getProcessInstanceId()); + if (executionEntity == null) { + log.warn("handleJobDeleteInternal executionEntity is null for job.eId:{}, job.piId:{} ", job.getExecutionId(), job.getProcessInstanceId()); + return; + } + super.handleJobDeleteInternal(job); + } +} From 5c47507f83edbaa0c0a44e494a13547df19bda5d Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 28 Oct 2025 14:36:16 +0800 Subject: [PATCH 28/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/bpmn/BpmnJsonNodeProperty.java | 7 ++ .../form/ConditionPermissionMetaInfo.java | 97 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java index ca44ab03c..67824255f 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java @@ -10,6 +10,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.CooperateShipTypeEnum; import cn.axzo.workflow.common.enums.InitiatorSpecifiedRangeEnum; import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -201,6 +202,12 @@ public class BpmnJsonNodeProperty { @ApiModelProperty(value = "表单字段权限控制") private List fieldPermission; + /** + * 条件字段权限配置 + */ + @ApiModelProperty(value = "条件字段权限控制") + private List conditionPermission; + /** * 区域过滤开关 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java new file mode 100644 index 000000000..0e69ca011 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java @@ -0,0 +1,97 @@ +package cn.axzo.workflow.common.model.request.form; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 表单字段权限信息 + * + * @author wangli + * @since 2024-11-07 11:09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ConditionPermissionMetaInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 条件标识 + */ + private String conditionCode; + + /** + * 条件名称 + */ + private String conditionName; + + /** + * 单选框 + * 条件类型(text/number/checkbox/radio) + */ + private String conditionType; + /** + * 可编辑必填 + */ + @Builder.Default + private Boolean required = false; + + /** + * 可编辑非必填 + */ + @Builder.Default + private Boolean editable = false; + + /** + * 只读 + */ + @Builder.Default + private Boolean readonly = true; + + /** + * 隐藏 + */ + @Builder.Default + private Boolean hidden = false; + + private String value; + + + // 将对象的属性转换为对应的整数表示 + public int toBinary() { + int binaryValue = 0; + binaryValue |= (required ? 1 : 0) << 3; + binaryValue |= (editable ? 1 : 0) << 2; + binaryValue |= (readonly ? 1 : 0) << 1; + binaryValue |= (hidden ? 1 : 0); + return binaryValue; + } + + // 从整数表示还原出对象 + public static ConditionPermissionMetaInfo fromBinary(String fieldId, String fieldName, int binaryValue) { + boolean required = ((binaryValue >> 3) & 1) == 1; + boolean editable = ((binaryValue >> 2) & 1) == 1; + boolean readonly = ((binaryValue >> 1) & 1) == 1; + boolean hidden = (binaryValue & 1) == 1; + return new ConditionPermissionMetaInfo(fieldId, fieldName, required, editable, readonly, hidden, null); + } + + public ConditionPermissionMetaInfo toReadonly() { + if (required || editable || readonly) { + setRequired(false); + setEditable(false); + setReadonly(true); + setHidden(false); + } + return this; + } + + public String toBinaryString() { + return String.format("%04d", Integer.parseInt(Integer.toBinaryString(toBinary()), 10)); + } +} From 4c9d91e154f0cc9dd42586f7219d74bf553a6d12 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 Oct 2025 18:29:20 +0800 Subject: [PATCH 29/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E4=BA=8C=E6=96=B9=E4=BA=BA=E9=92=A2=E6=9E=B6?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=E4=BC=A0=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BasedIdentityV2TaskAssigneeSelector.java | 2 ++ ...InitiatorLeaderV2TaskAssigneeSelector.java | 2 ++ .../BasedPositionV2TaskAssigneeSelector.java | 2 ++ .../BasedRoleV2TaskAssigneeSelector.java | 2 ++ ...opyTemplateFileTaskEvent_105_Listener.java | 25 ++++++++++++++++--- .../bpmn/BpmnProcessInstanceController.java | 15 ++++++++++- 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java index d62a73644..f86d05307 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java @@ -39,6 +39,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyRangeOrgLimit; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable; /** @@ -76,6 +77,7 @@ public class BasedIdentityV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne .initiatorPersonId(initiator.parsePersonId()) .areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet()) .specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet()) + .projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(orgDTO.getProjectIds()) : Sets.newHashSet()) .querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent()); switch (optRange.get()) { case within_the_project: diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java index 47a2f50c3..9161ef04c 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java @@ -28,6 +28,7 @@ import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_proj import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getInitiatorLeaderRangeUnit; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable; /** @@ -69,6 +70,7 @@ public class BasedInitiatorLeaderV2TaskAssigneeSelector extends AbstractBpmnTask .initiatorPersonId(initiator.parsePersonId()) .areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet()) .specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet()) + .projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(orgDTO.getProjectIds()) : Sets.newHashSet()) .querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent()); FlowTaskAssignerV2Req request = v2ReqBuilder.build(); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java index 3ccff50b5..31eed2e82 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java @@ -42,6 +42,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCooperateShipType; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable; /** @@ -80,6 +81,7 @@ public class BasedPositionV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne .initiatorPersonId(initiator.parsePersonId()) .areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet()) .specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet()) + .projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(orgDTO.getProjectIds()) : Sets.newHashSet()) .querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent()); switch (optRange.get()) { case within_the_project: diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java index 3827b1b39..c4f3574a6 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java @@ -43,6 +43,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyValueV2; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getAreaFilterEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCooperateShipType; +import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getOnlyInProjectEnable; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSpecialtyFilterEnable; /** @@ -82,6 +83,7 @@ public class BasedRoleV2TaskAssigneeSelector extends AbstractBpmnTaskAssigneeSel .initiatorPersonId(initiator.parsePersonId()) .areaCodes(getAreaFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeAreaCodes())) : Sets.newHashSet()) .specialtyCodes(getSpecialtyFilterEnable(flowElement) ? Sets.newHashSet(ListUtils.emptyIfNull(orgDTO.getIncludeSpecialtyCodes())) : Sets.newHashSet()) + .projectIds(getOnlyInProjectEnable(flowElement) ? Sets.newHashSet(orgDTO.getProjectIds()) : Sets.newHashSet()) .querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent()); switch (optRange.get()) { case within_the_project: diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index b4dd6d9d2..ee504d38f 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -37,10 +37,15 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_BASED_FILE_TAG_ORDER; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; @@ -118,12 +123,24 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve .fileType(customDoc.getFileType()) .build()); } + List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); + if (Objects.nonNull(basedFileTagOrder)) { + // 基于 fileTag 排序 + Map fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size()) + .boxed() + .collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a)); - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); - if (Objects.equals("last", customAddType)) { - docTemplates.addAll(customDocTemplates); + docTemplates.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))); + docTemplates = docTemplates.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))) + .collect(Collectors.toList()); } else { - docTemplates.addAll(0, customDocTemplates); + // 基于前插还是后插排序 + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); + if (Objects.equals("last", customAddType)) { + docTemplates.addAll(customDocTemplates); + } else { + docTemplates.addAll(0, customDocTemplates); + } } processSign.setDocTemplate(docTemplates); 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 934b79e15..6f66a0110 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 @@ -29,6 +29,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverRead import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; @@ -390,7 +391,6 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @PostMapping("/biz/custom/variables/update") public CommonResponse updateProcessBizCustomVariables(@Validated @RequestBody BpmnProcessInstanceVariablesUpdateDTO dto) { log.info("更新流程实例中的业务自定义变量集合 updateProcessBizCustomVariables===>>>参数:{}", JSONUtil.toJsonStr(dto)); - ; bpmnProcessInstanceService.overrideProcessVariables(dto); return success(true); } @@ -613,4 +613,17 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController return logVO; }).collect(Collectors.toList())); } + + /** + * 获取流程实例的条件字段信息 + * + * @param processInstanceId + * @return + */ + @Operation(summary = "获取流程实例的条件字段信息, 仅用于同意抽屉展示") + @GetMapping("/conditions") + @Override + public CommonResponse> getConditions(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId) { + return success(bpmnProcessInstanceService.getConditions(processInstanceId)); + } } From 1f54f82c34e911296a1a578b0e2930ea04b0fa4c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 Oct 2025 18:30:43 +0800 Subject: [PATCH 30/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=B5=81=E7=A8=8B=E8=8A=82=E7=82=B9=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E6=9D=A1=E4=BB=B6=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/CustomGetConditionPermissionsCmd.java | 64 +++++++++++++++++++ .../service/BpmnProcessInstanceService.java | 3 + .../impl/BpmnProcessInstanceServiceImpl.java | 11 ++++ 3 files changed, 78 insertions(+) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java new file mode 100644 index 000000000..3f81e7318 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java @@ -0,0 +1,64 @@ +package cn.axzo.workflow.core.engine.cmd; + +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; +import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import com.alibaba.fastjson.JSON; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +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.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 获取指定流程节点配置的条件权限信息 + * + * @author wangli + * @since 2025-10-29 18:02 + */ +public class CustomGetConditionPermissionsCmd extends AbstractCommand> { + private final String processInstanceId; + + public CustomGetConditionPermissionsCmd(String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + @Override + public String paramToJsonString() { + Map params = new HashMap<>(); + params.put("processInstanceId", processInstanceId); + return JSON.toJSONString(params); + } + + @Override + public List execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + if (Objects.isNull(processInstance)) { + return Collections.emptyList(); + } + TaskService taskService = processEngineConfiguration.getTaskService(); + List tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list(); + if (CollectionUtils.isEmpty(tasks)) { + return Collections.emptyList(); + } + BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processInstance.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(tasks.get(0).getId()); + List conditions = BpmnMetaParserHelper.getConditionPermissionConf(flowElement).orElse(Collections.emptyList()); + conditions.forEach(e -> e.setValue(null)); + return conditions; + } +} 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 692f8772d..9195fce8d 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 @@ -15,6 +15,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanc import cn.axzo.workflow.common.model.request.bpmn.process.SuperBpmnProcessInstanceCancelDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; @@ -214,4 +215,6 @@ public interface BpmnProcessInstanceService { List processInstanceSelectDocs(ProcessDocQueryDTO dto); void overrideProcessVariables(BpmnProcessInstanceVariablesUpdateDTO dto); + + List getConditions(String processInstanceId); } 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 75c6149d8..f553c3581 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 @@ -40,6 +40,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO; import cn.axzo.workflow.common.model.request.category.CategorySearchDTO; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationItemResultVO; @@ -66,6 +67,7 @@ import cn.axzo.workflow.core.engine.cmd.CustomCancelProcessInstanceAsyncCmd; 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.cmd.CustomGetConditionPermissionsCmd; import cn.axzo.workflow.core.engine.cmd.CustomGetModelDocsCmd; import cn.axzo.workflow.core.engine.cmd.CustomOverrideFormVariablesByLatestInstanceCmd; import cn.axzo.workflow.core.engine.cmd.CustomOverrideProcessVariablesCmd; @@ -503,8 +505,11 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic dto.getVariables().put(SIGN_PROCESS_ENABLE_DOC_IDS, dto.getDocIds()); dto.getVariables().put(SIGN_VARIABLE, dto.getBizCustomVariables()); dto.getVariables().put(SIGNATORIES, dto.getSignatories()); + // 业务自定义文档 dto.getVariables().put(SIGN_BIZ_CUSTOM_DOCS, dto.getCustomDocs()); + // 业务自定义文档追加顺序类型 dto.getVariables().put(SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, StringUtils.hasText(dto.getDocAddOrderType()) ? dto.getDocAddOrderType() : "last"); + // 基于业务的标签排序 dto.getVariables().put(SIGN_BIZ_BASED_FILE_TAG_ORDER, dto.getBasedFileTagOrder()); } }); @@ -1961,4 +1966,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); commandExecutor.execute(new CustomOverrideProcessVariablesCmd(dto.getProcessInstanceId(), dto.getBizCustomVariables())); } + + @Override + public List getConditions(String processInstanceId) { + CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor(); + return commandExecutor.execute(new CustomGetConditionPermissionsCmd(processInstanceId)); + } } From 936833b73e6735ea14e0f0631bbbdbe0802d8410 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 Oct 2025 18:30:56 +0800 Subject: [PATCH 31/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=B5=81=E7=A8=8B=E8=8A=82=E7=82=B9=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E6=9D=A1=E4=BB=B6=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/bpmn/ProcessInstanceApi.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 a8ada187a..837b5b496 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 @@ -23,6 +23,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatus import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ProcessDocQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.instance.FormVariablesUpdateDTO; import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; @@ -370,4 +371,15 @@ public interface ProcessInstanceApi { @Manageable @InvokeMode(SYNC) CommonResponse> getProcessLogByInstanceIdAndPersonId(@Validated @RequestBody LogApproveSearchDTO dto); + + /** + * 获取流程实例的条件字段信息,仅用于同意抽屉展示 + * + * @param processInstanceId + * @return + */ + @Operation(summary = "获取流程实例的条件字段信息, 仅用于同意抽屉展示") + @GetMapping("/api/process/instance/conditions") + @InvokeMode(SYNC) + CommonResponse> getConditions(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId); } From cdbe89c05afc6ba13fcf1299e2111a7ad98f344a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 29 Oct 2025 18:31:43 +0800 Subject: [PATCH 32/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20BPMN=20=E5=8D=8F=E8=AE=AE=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/BpmnConstants.java | 2 ++ .../common/constant/VariableConstants.java | 4 ++-- .../common/model/dto/CooperationOrgDTO.java | 5 ++++ .../common/model/dto/CustomDocDTO.java | 4 ++-- .../request/bpmn/BpmnJsonNodeProperty.java | 5 ++++ .../form/ConditionPermissionMetaInfo.java | 12 ++++++++-- .../common/utils/BpmnMetaParserHelper.java | 11 +++++++++ .../json/ServiceTaskJsonConverter.java | 14 +++++++++++ .../converter/json/UserTaskJsonConverter.java | 23 +++++++++++++++++++ .../core/engine/cmd/CustomApproveTaskCmd.java | 1 + .../cmd/CustomApproveTaskWithFormCmd.java | 1 + 11 files changed, 76 insertions(+), 6 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 9b5cc0dcd..0daac19ab 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 @@ -117,6 +117,7 @@ public interface BpmnConstants { String CONFIG_ACTIVITY_SIGNATURE = "signature"; String CONFIG_FIELD_META = "field"; String CONFIG_FIELD_PERMISSION = "fieldPermission"; + String CONFIG_CONDITION_PERMISSION = "conditionPermission"; String CONFIG_FIELD_OPTION = "option"; String CONFIG_NODE_TYPE = "nodeType"; String CONFIG_BUTTON_TYPE_INITIATOR = "initiator"; @@ -126,6 +127,7 @@ public interface BpmnConstants { String CONFIG_SIGN_TYPE = "signType"; String CONFIG_AREA_FILTER_ENABLE = "areaFilterEnable"; String CONFIG_SPECIALTY_FILTER_ENABLE = "specialtyFilterEnable"; + String CONFIG_ONLY_IN_PROJECT_ENABLE = "onlyInProjectEnable"; String ELEMENT_ATTRIBUTE_NAME = "name"; String ELEMENT_ATTRIBUTE_VALUE = "value"; String ELEMENT_ATTRIBUTE_DESC = "desc"; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java index 770335072..c1d30d3b5 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java @@ -54,7 +54,7 @@ public interface VariableConstants { String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME = "activityName"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_NAME_DESC = "节点名称"; String PRINT_VAR_PROCESS_LOG_APPROVER_NAME = "approverName"; - String PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC = "审批人"; + String PRINT_VAR_PROCESS_LOG_APPROVER_NAME_DESC = "姓名"; String PRINT_VAR_PROCESS_LOG_UNIT = "unit"; String PRINT_VAR_PROCESS_LOG_UNIT_DESC = "单位"; String PRINT_VAR_PROCESS_LOG_POSITION = "position"; @@ -68,7 +68,7 @@ public interface VariableConstants { String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT = "activityResult"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_RESULT_DESC = "审批结果"; String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME = "activityOperationTime"; - String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC = "签名日期"; + String PRINT_VAR_PROCESS_LOG_ACTIVITY_OPERATION_TIME_DESC = "日期"; String PRINT_VAR_PROCESS_LOG_OPERATION = "operationDesc"; String PRINT_VAR_PROCESS_LOG_OPERATION_DESC = "操作描述"; } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java index 0106ffb23..64f53ee47 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java @@ -40,6 +40,11 @@ public class CooperationOrgDTO implements Serializable { */ private List includeSpecialtyCodes; + /** + * 控制仅支持工程内人员参与审批 + */ + private List projectIds; + /** * 企业组织架构范围 **/ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java index ffad37e9c..c61b3b7ef 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java @@ -41,13 +41,13 @@ public class CustomDocDTO implements Serializable { private String fileTag; /** - * 文件 wps code,如果有则传入 + * 如果业务是使用在线文档,则一定会有 wps code,如果有则传入 *

* wps 文件的标识,通过{@link cn.axzo.nanopart.doc.api.anonymous.DocAnonymousDatabaseApi#createFile(cn.axzo.nanopart.doc.api.anonymous.request.AnonymousCreateFileRequest)} 接口创建文件后返回的 fileCode */ private String fileCode; /** - * oss 地址的文件标识 + * 不管是在线文件还是本地上传,必须包含 oss 地址的文件标识 */ @NotBlank(message = "业务自定义文件的 oss key 不能为空") private String fileKey; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java index 67824255f..6e1183625 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java @@ -220,4 +220,9 @@ public class BpmnJsonNodeProperty { @ApiModelProperty(value = "专业过滤开关", notes = "true: 开启专业过滤, false: 关闭专业过滤") private Boolean specialtyFilterEnable; + /** + * 工程内人员开关 + */ + @ApiModelProperty(value = "仅工程内人员开关", notes = "true: 仅工程内人员, false: 非仅工程内人员") + private Boolean onlyInProjectEnable; } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java index 0e69ca011..daad1dd0b 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/form/ConditionPermissionMetaInfo.java @@ -59,8 +59,16 @@ public class ConditionPermissionMetaInfo implements Serializable { @Builder.Default private Boolean hidden = false; + /** + * 前端回显字段,后端不做任何消费逻辑 + */ private String value; + /** + * 类型是单选复选时的选项值 + */ + private String options; + // 将对象的属性转换为对应的整数表示 public int toBinary() { @@ -73,12 +81,12 @@ public class ConditionPermissionMetaInfo implements Serializable { } // 从整数表示还原出对象 - public static ConditionPermissionMetaInfo fromBinary(String fieldId, String fieldName, int binaryValue) { + public static ConditionPermissionMetaInfo fromBinary(String conditionCode, String conditionName, String conditionType, int binaryValue) { boolean required = ((binaryValue >> 3) & 1) == 1; boolean editable = ((binaryValue >> 2) & 1) == 1; boolean readonly = ((binaryValue >> 1) & 1) == 1; boolean hidden = (binaryValue & 1) == 1; - return new ConditionPermissionMetaInfo(fieldId, fieldName, required, editable, readonly, hidden, null); + return new ConditionPermissionMetaInfo(conditionCode, conditionName, conditionType, required, editable, readonly, hidden, null, null); } public ConditionPermissionMetaInfo toReadonly() { diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java index b0217a7e0..af85769b5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java @@ -31,6 +31,7 @@ import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf; import cn.axzo.workflow.common.model.request.bpmn.BpmnSignPendingProperty; import cn.axzo.workflow.common.model.request.bpmn.BpmnSmsProperty; import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf; +import cn.axzo.workflow.common.model.request.form.ConditionPermissionMetaInfo; import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; @@ -82,6 +83,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPIE import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_OBJECT; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_SPECIFY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CONDITION_PERMISSION; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_META; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_OPTION; @@ -93,6 +95,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SP import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_RANGE; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NOTICE; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_ONLY_IN_PROJECT_ENABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_LIMIT; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT; @@ -648,6 +651,10 @@ public final class BpmnMetaParserHelper { return defaultValid(flowElement, CONFIG_SPECIALTY_FILTER_ENABLE).map(element -> Boolean.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED))).orElse(false); } + public static Boolean getOnlyInProjectEnable(FlowElement flowElement) { + return defaultValid(flowElement, CONFIG_ONLY_IN_PROJECT_ENABLE).map(element -> Boolean.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED))).orElse(false); + } + private static Optional defaultValid(FlowElement flowElement, String elementName) { if (Objects.isNull(flowElement)) { return Optional.empty(); @@ -692,6 +699,10 @@ public final class BpmnMetaParserHelper { }.getType())); } + public static Optional> getConditionPermissionConf(FlowElement flowElement) { + return defaultValid(flowElement, CONFIG_CONDITION_PERMISSION).map(element -> JSON.parseObject(element.getElementText(), new TypeReference>() { + }.getType())); + } public static Optional> getFormFieldPermissionForCalc(FlowElement flowElement) { List fieldMetaInfos = getFormFieldPermissionConf(flowElement).orElse(new ArrayList<>()); return getFormFieldPermissionForModel(fieldMetaInfos); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ServiceTaskJsonConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ServiceTaskJsonConverter.java index 100756b9b..c41dda0ec 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ServiceTaskJsonConverter.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ServiceTaskJsonConverter.java @@ -25,6 +25,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPIE import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_OBJECT; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CARBON_COPY_SPECIFY; +import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_CONDITION_PERMISSION; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMISSION; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_LEADER_RANGE_UNIT; import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_INITIATOR_SPECIFIED_EXCLUDE_COOPERATE_TYPES; @@ -68,6 +69,8 @@ public class ServiceTaskJsonConverter extends AbstractBpmnJsonConverter { setApprovalExtensionElement(node, userTask); // "表单权限设置" setFormFieldExtensionElement(node, userTask); + // "条件权限设置" + setConditionExtensionElement(node, userTask); // "高级设置",包含按钮配置,自动过审配置 setAdvancedExtensionElement(node, userTask); // "待办消息模板配置" @@ -183,6 +187,14 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { specialtyFilterEnableElement.addAttribute(specialtyFilterEnableAttribute); userTask.addExtensionElement(specialtyFilterEnableElement); + ExtensionElement onlyInProjectEnableElement = new ExtensionElement(); + onlyInProjectEnableElement.setName(CONFIG_ONLY_IN_PROJECT_ENABLE); + ExtensionAttribute onlyInProjectEnableAttribute = new ExtensionAttribute(); + onlyInProjectEnableAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED); + onlyInProjectEnableAttribute.setValue(String.valueOf(Boolean.TRUE.equals(node.getProperty().getOnlyInProjectEnable()))); + onlyInProjectEnableElement.addAttribute(onlyInProjectEnableAttribute); + userTask.addExtensionElement(onlyInProjectEnableElement); + //添加自动审批配置 ExtensionElement autoApprovalExtensionElement = new ExtensionElement(); ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute(); @@ -191,6 +203,17 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { userTask.addExtensionElement(autoApprovalExtensionElement); } + private static void setConditionExtensionElement(BpmnJsonNode node, UserTask userTask) { + if (Objects.isNull(node.getProperty()) || CollectionUtils.isEmpty(node.getProperty().getConditionPermission())) { + return; + } + ExtensionElement fieldElement = new ExtensionElement(); + fieldElement.setName(CONFIG_CONDITION_PERMISSION); + fieldElement.setElementText(Objects.nonNull(node.getProperty().getConditionPermission()) ? + JSON.toJSONString(node.getProperty().getConditionPermission()) : null); + userTask.addExtensionElement(fieldElement); + } + private static void setFormFieldExtensionElement(BpmnJsonNode node, UserTask userTask) { if (Objects.isNull(node.getProperty()) || CollectionUtils.isEmpty(node.getProperty().getFieldPermission())) { return; 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 30bcbcdc9..99992115d 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 @@ -161,6 +161,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + // 更新流程内的变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 recordSignature(task, runtimeService); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java index 050ee28fc..4b3a31795 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java @@ -180,6 +180,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen nextApprover); } task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + // 更新流程实例变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 recordSignature(task, runtimeService); From 388de9eb52d8c27d28f4104a2f0b410eceda4abf Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 Oct 2025 14:57:40 +0800 Subject: [PATCH 33/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=97=A5=E5=BF=97=E6=89=93=E5=8D=B0=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/manage/PrintAdminApi.java | 16 +++- .../common/constant/VariableConstants.java | 6 ++ .../bpmn/print/Print4ProcessLogDTO.java | 32 +++++++ .../model/response/ProcessLogItemDTO.java | 60 +++++++++++++ .../common/model/response/TableItemDTO.java | 31 +++++++ .../bpmn/process/PrintData4LogVO.java | 50 +++++++++++ .../CustomGetProcessInstanceVariablesCmd.java | 8 ++ .../impl/BpmnProcessInstanceServiceImpl.java | 2 +- .../web/manage/PrintAdminController.java | 89 +++++++++++++++++++ 9 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/Print4ProcessLogDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java index 9dec9a0a9..a3b91683f 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java @@ -4,8 +4,10 @@ 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.dto.print.PrintFieldDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; +import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; @@ -66,7 +68,7 @@ public interface PrintAdminApi { * 获取指定流程下用于替换打印的相关变量 * * @param processInstanceId - * @return + * @return 仅是 kv 集合, */ @Operation(summary = "获取指定流程下用于替换打印的相关变量") @GetMapping("/api/print/admin/field/variables") @@ -74,4 +76,16 @@ public interface PrintAdminApi { @InvokeMode(SYNC) CommonResponse> getPrintFieldVariables(@NotBlank(message = "流程实例不能为空") @RequestParam String processInstanceId, @RequestParam(required = false, defaultValue = "true") Boolean throwException); + + /** + * 获取用于打印审批日志公共模板的数据 + * + * @param dto + * @return + */ + @Operation(summary = "获取用于打印审批日志公共模板的数据") + @PostMapping("/api/print/admin/process/log/data/v2") + @Manageable + @InvokeMode(SYNC) + CommonResponse getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java index c1d30d3b5..d8a6ed3ff 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/VariableConstants.java @@ -29,14 +29,20 @@ public interface VariableConstants { //=============== 打印时的变量集合中 key 的命名 ================= String VAR_PREFIX = "业务变量"; + String PRINT_VAR_PROCESS_NAME = "processName"; + String PRINT_VAR_PROCESS_NAME_DESC = "审批名称"; String PRINT_VAR_PROCESS_DEFINITION_KEY = "processDefinitionKey"; String PRINT_VAR_PROCESS_DEFINITION_KEY_DESC = "业务名称"; + String PRINT_VAR_PROCESS_BELONG_TENANT_ID = "tenantId"; + String PRINT_VAR_PROCESS_BELONG_TENANT_ID_DESC = "所属租户"; String PRINT_VAR_PROCESS_INSTANCE_ID = "processInstanceId"; String PRINT_VAR_PROCESS_INSTANCE_ID_DESC = "审批编号"; String PRINT_VAR_PROCESS_START_TIME = "startTime"; String PRINT_VAR_PROCESS_START_TIME_DESC = "发起时间"; String PRINT_VAR_PROCESS_END_TIME = "endTime"; String PRINT_VAR_PROCESS_END_TIME_DESC = "审批结束时间"; + String PRINT_VAR_PROCESS_RESULT = "processResult"; + String PRINT_VAR_PROCESS_RESULT_DESC = "审批结果"; String PRINT_VAR_PROCESS_INITIATOR = "initiator"; String PRINT_VAR_PROCESS_INITIATOR_DESC = "发起者"; String PRINT_VAR_PROCESS_INITIATOR_NAME = "initiatorName"; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/Print4ProcessLogDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/Print4ProcessLogDTO.java new file mode 100644 index 000000000..87dc3ae33 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/Print4ProcessLogDTO.java @@ -0,0 +1,32 @@ +package cn.axzo.workflow.common.model.request.bpmn.print; + +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 2025-10-30 10:43 + */ +@ApiModel("获取内置公共模板打印数据的入参模型") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Print4ProcessLogDTO { + + /** + * 流程实例 ID + */ + @ApiModelProperty(value = "流程实例 ID") + @NotBlank(message = "流程实例 ID 不能为空") + private String processInstanceId; + +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java new file mode 100644 index 000000000..cc556ce48 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java @@ -0,0 +1,60 @@ +package cn.axzo.workflow.common.model.response; + +import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +/** + * 审批日志项模型 + * + * @author wangli + * @since 2025-10-30 14:22 + */ +@Data +@Builder +public class ProcessLogItemDTO { + @Builder.Default + private String label = "审批流程"; + + /** + * 审批意见 + */ + private String advice; + + /** + * 节点名称 + */ + @ApiModelProperty(value = "节点名称") + private String activityName; + + /** + * 操作描述 + */ + @ApiModelProperty(value = "操作描述") + private String operationDesc; + + /** + * 图片列表 + */ + @ApiModelProperty(value = "图片列表") + private List imageList; + /** + * 附件列表 + */ + @ApiModelProperty(value = "附件列表") + private List fileList; + /** + * 手写签名地址 + */ + @ApiModelProperty(value = "手写签名地址") + private String signatureUrl; + + /** + * 操作时间 + */ + @ApiModelProperty(value = "操作时间") + private String operationTime; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java new file mode 100644 index 000000000..c3ba57e8d --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java @@ -0,0 +1,31 @@ +package cn.axzo.workflow.common.model.response; + +import lombok.Builder; +import lombok.Data; + +/** + * 审批日志公共打印模板的字段项模型 + * + * @author wangli + * @since 2025-10-30 10:38 + */ +@Data +@Builder +public class TableItemDTO { + /** + * 中文 + */ + private String label; + /** + * 字段 code + */ + private String code; + /** + * 字段类型 + */ + private String type; + /** + * 值 + */ + private Object value; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java new file mode 100644 index 000000000..d71def5d9 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java @@ -0,0 +1,50 @@ +package cn.axzo.workflow.common.model.response.bpmn.process; + +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; +import cn.axzo.workflow.common.model.response.ProcessLogItemDTO; +import cn.axzo.workflow.common.model.response.TableItemDTO; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 新版的审批日志公共模板的数据响应模型 + * + * @author wangli + * @since 2025-10-30 10:28 + */ +@ApiModel("新版的审批日志公共模板的数据响应模型") +@Data +@Accessors(chain = true) +public class PrintData4LogVO { + + /** + * 标题 + */ + private String processName; + /** + * 发起租户名称 + */ + private String tenantName; + /** + * 创建时间 + */ + private String createAt; + /** + * 审批状态 + */ + private BpmnProcessInstanceResultEnum result; + + /** + * 系统变量表格项 + */ + private List systemVarItems; + + /** + * 审批日志表格项 + */ + private List logItems; +} + diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java index bd84f4cf0..80ffb959a 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.engine.cmd; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.dto.SignatureDTO; import cn.axzo.workflow.core.common.utils.SpringContextUtils; import cn.axzo.workflow.core.service.CategoryService; @@ -22,10 +23,13 @@ import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_BELONG_TENANT_ID; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_DEFINITION_KEY; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_END_TIME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_NAME; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_RESULT; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; @@ -63,9 +67,13 @@ public class CustomGetProcessInstanceVariablesCmd extends AbstractCommand getAttachmentByType(Map> attachmentByTaskMap, String + public static List getAttachmentByType(Map> attachmentByTaskMap, String taskId, AttachmentTypeEnum type) { return ListUtils.emptyIfNull(attachmentByTaskMap.get(taskId)).stream() .filter(attachment -> Objects.equals(type.getType(), attachment.getType())) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index bc2d0fdf9..8b14a5521 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -4,29 +4,40 @@ import cn.axzo.maokai.api.client.OrganizationalNodeUserQueryApi; import cn.axzo.maokai.api.vo.request.OrgNodeUserBriefInfoListReq; import cn.axzo.maokai.api.vo.response.OrgNodeUserBriefInfoResp; import cn.axzo.workflow.client.feign.manage.PrintAdminApi; +import cn.axzo.workflow.common.constant.VariableConstants; +import cn.axzo.workflow.common.enums.AttachmentTypeEnum; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.VarTypeEnum; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.dto.print.FieldAttributeDTO; import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; +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.CategoryGroupVarSearchDto; +import cn.axzo.workflow.common.model.response.ProcessLogItemDTO; +import cn.axzo.workflow.common.model.response.TableItemDTO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinitionVO; import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; +import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; import cn.axzo.workflow.common.model.response.category.CategoryGroupVarItemVo; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.cmd.CustomGetFormInstanceLatestValuesCmd; import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesCmd; +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.BpmnProcessModelService; import cn.axzo.workflow.core.service.CategoryGroupService; +import cn.axzo.workflow.core.service.ExtAxProcessLogService; import cn.axzo.workflow.server.common.annotation.ErrorReporter; import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.axzo.workflow.server.controller.web.bpmn.BpmnProcessInstanceController; import cn.azxo.framework.common.model.CommonResponse; +import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -35,6 +46,8 @@ import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.flowable.engine.TaskService; +import org.flowable.engine.task.Attachment; import org.flowable.form.api.FormInfo; import org.flowable.form.api.FormRepositoryService; import org.flowable.form.model.FormContainer; @@ -80,6 +93,7 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_POSITION_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_UNIT; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_INSTANCE_ID_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOGS; @@ -104,12 +118,15 @@ import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCE import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_SIGNATURE_DESC; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_UNIT; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_LOG_UNIT_DESC; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_NAME; +import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_RESULT; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME; import static cn.axzo.workflow.common.constant.VariableConstants.PRINT_VAR_PROCESS_START_TIME_DESC; import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.form; import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.sign; import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.signature; import static cn.axzo.workflow.common.enums.PrintFieldCategoryEnum.system; +import static cn.axzo.workflow.core.service.impl.BpmnProcessInstanceServiceImpl.getAttachmentByType; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -141,6 +158,10 @@ public class PrintAdminController implements PrintAdminApi { private CategoryGroupService categoryGroupService; @Resource private BpmnProcessModelService bpmnProcessModelService; + @Resource + private ExtAxProcessLogService processLogService; + @Resource + private TaskService taskService; /** * 查询指定流程实例是否能使用打印 @@ -456,4 +477,72 @@ public class PrintAdminController implements PrintAdminApi { return users.stream().sorted(Comparator.comparing(OrgNodeUserBriefInfoResp::getExited).reversed()) .collect(Collectors.toList()).stream().findFirst(); } + + @Operation(summary = "获取用于打印审批日志公共模板的数据") + @PostMapping("/process/log/data/v2") + @Override + public CommonResponse getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto) { + CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); + Map variables = commandExecutor.execute(new CustomGetProcessInstanceVariablesCmd(dto.getProcessInstanceId())); + + PrintData4LogVO vo = new PrintData4LogVO(); + vo.setProcessName((String) variables.getOrDefault(PRINT_VAR_PROCESS_NAME, "")); + vo.setTenantName(String.valueOf(variables.get(VariableConstants.PRINT_VAR_PROCESS_BELONG_TENANT_ID))); + vo.setCreateAt(String.valueOf(variables.get(VariableConstants.PRINT_VAR_PROCESS_START_TIME))); + vo.setResult((BpmnProcessInstanceResultEnum) variables.get(PRINT_VAR_PROCESS_RESULT)); + + List systemVarItems = new ArrayList<>(); + systemVarItems.add(TableItemDTO.builder() + .label(PRINT_VAR_PROCESS_INSTANCE_ID_DESC) + .code(PRINT_VAR_PROCESS_INSTANCE_ID) + .type(FORM_FIELD_TYPE_INPUT) + .value(variables.get(PRINT_VAR_PROCESS_INSTANCE_ID)) + .build()); + + // 解析发起人 + BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(variables.getOrDefault(PRINT_VAR_PROCESS_INITIATOR, null)); + if (Objects.nonNull(initiator)) { + Optional user = getUserInfo(initiator); + systemVarItems.add(TableItemDTO.builder() + .label(PRINT_VAR_PROCESS_INITIATOR_NAME_DESC) + .code(PRINT_VAR_PROCESS_INITIATOR_NAME) + .type(FORM_FIELD_TYPE_INPUT) + .value(user.isPresent() ? user.get().getRealName() : "") + .build()); + systemVarItems.add(TableItemDTO.builder() + .label(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) + .code(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) + .type(FORM_FIELD_TYPE_INPUT) + .value(user.isPresent() ? user.get().getOrganizationalUnitName() : "") + .build()); + } + + vo.setSystemVarItems(systemVarItems); + + // 审批日志 + List logItems = new ArrayList<>(); + Map> attachmentByTaskMap = + taskService.getProcessInstanceAttachments(dto.getProcessInstanceId()).stream() + .collect(Collectors.groupingBy(Attachment::getTaskId)); + ExtAxProcessLog query = new ExtAxProcessLog(); + query.setProcessInstanceId(dto.getProcessInstanceId()); + processLogService.genericQuery(query).stream() + .sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder()))) + .collect(Collectors.toList()) + .forEach(log -> { + logItems.add(ProcessLogItemDTO.builder() + .advice(log.getAdvice()) + .activityName(log.getActivityName()) + .operationDesc(log.getOperationDesc()) + .imageList(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.image)) + .fileList(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.file)) + .signatureUrl(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) + .operationTime(DateUtil.format(log.getEndTime(), "yyyy.MM.dd HH:mm:ss")) + .build()); + }); + vo.setLogItems(logItems); + + return success(vo); + } + } From 50c423d7d2857a9b2612928a805c97f9194b09e4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 Oct 2025 15:18:36 +0800 Subject: [PATCH 34/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=A8=A1=E5=9E=8B=E7=9A=84=E6=B3=A8=E8=A7=A3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/model/response/ProcessLogItemDTO.java | 4 ++++ .../cn/axzo/workflow/common/model/response/TableItemDTO.java | 4 ++++ .../common/model/response/bpmn/process/PrintData4LogVO.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java index cc556ce48..0e8b5e9b4 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java @@ -2,8 +2,10 @@ package cn.axzo.workflow.common.model.response; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; @@ -15,6 +17,8 @@ import java.util.List; */ @Data @Builder +@AllArgsConstructor +@NoArgsConstructor public class ProcessLogItemDTO { @Builder.Default private String label = "审批流程"; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java index c3ba57e8d..5329db1de 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/TableItemDTO.java @@ -1,7 +1,9 @@ package cn.axzo.workflow.common.model.response; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 审批日志公共打印模板的字段项模型 @@ -11,6 +13,8 @@ import lombok.Data; */ @Data @Builder +@AllArgsConstructor +@NoArgsConstructor public class TableItemDTO { /** * 中文 diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java index d71def5d9..304f9c903 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/PrintData4LogVO.java @@ -4,7 +4,9 @@ import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.response.ProcessLogItemDTO; import cn.axzo.workflow.common.model.response.TableItemDTO; import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.util.List; @@ -18,6 +20,8 @@ import java.util.List; @ApiModel("新版的审批日志公共模板的数据响应模型") @Data @Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor public class PrintData4LogVO { /** From 91d263bc10233719de34cc1d103b01b7e889be5c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 Oct 2025 15:45:17 +0800 Subject: [PATCH 35/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=86=85=E9=83=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/manage/PrintAdminController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 8b14a5521..4299874bf 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -510,7 +510,7 @@ public class PrintAdminController implements PrintAdminApi { .value(user.isPresent() ? user.get().getRealName() : "") .build()); systemVarItems.add(TableItemDTO.builder() - .label(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) + .label(PRINT_VAR_PROCESS_INITIATOR_UNIT) .code(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) .type(FORM_FIELD_TYPE_INPUT) .value(user.isPresent() ? user.get().getOrganizationalUnitName() : "") From 744b8f19ac88a963a4d7d83942eb30f71003161c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 Oct 2025 15:59:25 +0800 Subject: [PATCH 36/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=86=85=E9=83=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/manage/PrintAdminController.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 4299874bf..a6bf95dab 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -3,6 +3,9 @@ package cn.axzo.workflow.server.controller.web.manage; import cn.axzo.maokai.api.client.OrganizationalNodeUserQueryApi; import cn.axzo.maokai.api.vo.request.OrgNodeUserBriefInfoListReq; import cn.axzo.maokai.api.vo.response.OrgNodeUserBriefInfoResp; +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.manage.PrintAdminApi; import cn.axzo.workflow.common.constant.VariableConstants; import cn.axzo.workflow.common.enums.AttachmentTypeEnum; @@ -44,6 +47,7 @@ import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.ListUtils; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.common.engine.impl.interceptor.CommandExecutor; import org.flowable.engine.TaskService; @@ -162,6 +166,8 @@ public class PrintAdminController implements PrintAdminApi { private ExtAxProcessLogService processLogService; @Resource private TaskService taskService; + @Resource + private ServerFileServiceApi serverFileServiceApi; /** * 查询指定流程实例是否能使用打印 @@ -540,9 +546,32 @@ public class PrintAdminController implements PrintAdminApi { .operationTime(DateUtil.format(log.getEndTime(), "yyyy.MM.dd HH:mm:ss")) .build()); }); + parseSignatureUrl(logItems); vo.setLogItems(logItems); return success(vo); } + + private void parseSignatureUrl(List logItems) { + List signUrls = logItems.stream() + .map(ProcessLogItemDTO::getSignatureUrl) + .filter(StringUtils::hasText) + .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)); + logItems.stream() + .filter(i -> StringUtils.hasText(i.getSignatureUrl())) + .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); + } + } From c26659c3646e6c779deab3069b2a79011a2da182 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 30 Oct 2025 16:04:45 +0800 Subject: [PATCH 37/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=86=85=E9=83=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/manage/PrintAdminController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index a6bf95dab..e4c0d54f6 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -532,6 +532,7 @@ public class PrintAdminController implements PrintAdminApi { .collect(Collectors.groupingBy(Attachment::getTaskId)); ExtAxProcessLog query = new ExtAxProcessLog(); query.setProcessInstanceId(dto.getProcessInstanceId()); + // TODO 这里可能需要结合节点隐藏来过滤 processLogService.genericQuery(query).stream() .sorted(Comparator.comparing(ExtAxProcessLog::getEndTime, Comparator.nullsLast(Comparator.naturalOrder()))) .collect(Collectors.toList()) From a662e6fab727dd553e20b760e3fbe266d5a164f5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 31 Oct 2025 17:41:45 +0800 Subject: [PATCH 38/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=AE=A1=E6=89=B9=E6=B5=81=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E7=9A=84=20PDF=20=E7=9A=84=E5=BC=82=E6=AD=A5=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/manage/PrintAdminApi.java | 11 ++++++ .../bpmn/print/PrintProcessLogPdfDTO.java | 36 +++++++++++++++++++ .../core/conf/SupportRefreshProperties.java | 3 ++ .../web/manage/PrintAdminController.java | 22 ++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintProcessLogPdfDTO.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java index a3b91683f..79ce4d9d5 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java @@ -6,6 +6,7 @@ import cn.axzo.workflow.common.annotation.Manageable; import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO; import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; import cn.azxo.framework.common.model.CommonResponse; @@ -88,4 +89,14 @@ public interface PrintAdminApi { @Manageable @InvokeMode(SYNC) CommonResponse getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto); + + /** + * 后端请求指定流程日志 PDF 文件生成 + * + * @return + */ + @Operation(summary = "后端请求指定流程日志 PDF 文件生成") + @PostMapping("/api/print/admin/process/log/pdf") + @InvokeMode(SYNC) + CommonResponse createProcessLogPdf(@Validated @RequestBody PrintProcessLogPdfDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintProcessLogPdfDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintProcessLogPdfDTO.java new file mode 100644 index 000000000..2c48315a0 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/PrintProcessLogPdfDTO.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.common.model.request.bpmn.print; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 请求审批日志转 pdf 的入参模型 + * + * @author wangli + * @since 2025-10-31 17:15 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class PrintProcessLogPdfDTO { + + /** + * 审批实例 ID + */ + @ApiModelProperty(value = "审批实例 ID") + @NotBlank(message = "审批实例 ID 不能为空") + private String processInstanceId; + + /** + * 实例日志访问者的personId + */ + @ApiModelProperty(value = "访问者的 PersonId") + @NotBlank(message = "访问者的 personId 不能为空") + private String personId; +} 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 29b3376d7..5e652d9df 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 @@ -108,4 +108,7 @@ public class SupportRefreshProperties { @Value("${workflow.ignoreMqAlterApplicationNames:}") private List ignoreMqAlterApplicationNames; + @Value("${workflow.processLogHtmlUrl:https://www.axzo.cn/}") + private String processLogHtmlUrl; + } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index e4c0d54f6..39d1bd8f7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -3,6 +3,9 @@ package cn.axzo.workflow.server.controller.web.manage; import cn.axzo.maokai.api.client.OrganizationalNodeUserQueryApi; import cn.axzo.maokai.api.vo.request.OrgNodeUserBriefInfoListReq; import cn.axzo.maokai.api.vo.response.OrgNodeUserBriefInfoResp; +import cn.axzo.nanopart.doc.api.conversion.DocConversionApi; +import cn.axzo.nanopart.doc.api.conversion.req.SubmitConversionTaskRequest; +import cn.axzo.nanopart.doc.api.enums.DocConversionTypeEnum; import cn.axzo.oss.http.api.ServerFileServiceApi; import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest; import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse; @@ -16,6 +19,7 @@ import cn.axzo.workflow.common.model.dto.print.FieldAttributeDTO; import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO; import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; @@ -28,6 +32,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLo import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; import cn.axzo.workflow.common.model.response.category.CategoryGroupVarItemVo; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.engine.cmd.CustomGetFormInstanceLatestValuesCmd; import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesCmd; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; @@ -168,6 +173,10 @@ public class PrintAdminController implements PrintAdminApi { private TaskService taskService; @Resource private ServerFileServiceApi serverFileServiceApi; + @Resource + private DocConversionApi docConversionApi; + @Resource + private SupportRefreshProperties refreshProperties; /** * 查询指定流程实例是否能使用打印 @@ -575,4 +584,17 @@ public class PrintAdminController implements PrintAdminApi { return RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(request), "批量获取手写签私有访问地址", request); } + @Operation(summary = "后端请求指定流程日志 PDF 文件生成") + @PostMapping("/process/log/pdf") + @Override + public CommonResponse createProcessLogPdf(@Validated @RequestBody PrintProcessLogPdfDTO dto) { + SubmitConversionTaskRequest request = new SubmitConversionTaskRequest(); + request.setBizCode("workflow-process-log"); + request.setBizKey(dto.getProcessInstanceId()); + request.setConversionType(DocConversionTypeEnum.HTML_URL_TO_PDF); + request.setFileName(refreshProperties.getProcessLogHtmlUrl()); + request.setFileKey(dto.getPersonId()); + String taskId = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.submitConvertTask(request), "创建网页转 PDF 的异步任务", request); + return CommonResponse.success(taskId); + } } From 33897ac68788a73b4302c11cd5d2a26e1c6a0210 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 3 Nov 2025 10:45:09 +0800 Subject: [PATCH 39/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E9=9A=90=E8=97=8F=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/code/BpmnTaskRespCode.java | 1 + .../common/constant/BpmnConstants.java | 1 + .../enums/BpmnProcessInstanceResultEnum.java | 1 + .../WorkflowApproverCalcException.java | 75 +++++++++++++++++++ .../core/engine/cmd/CustomApproveTaskCmd.java | 9 ++- .../AbstractBpmnTaskAssigneeSelector.java | 36 +++++++++ .../BasedIdentityV2TaskAssigneeSelector.java | 14 +++- ...InitiatorLeaderV2TaskAssigneeSelector.java | 14 +++- .../BasedPositionV2TaskAssigneeSelector.java | 14 +++- .../BasedRoleV2TaskAssigneeSelector.java | 14 +++- .../ext/listener/TaskEntityEventHandle.java | 3 + 11 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/exception/WorkflowApproverCalcException.java diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/BpmnTaskRespCode.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/BpmnTaskRespCode.java index 07d01a019..1968f7e27 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/BpmnTaskRespCode.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/code/BpmnTaskRespCode.java @@ -44,6 +44,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode { REMIND_TASK_TOO_MANY("027", "催办任务数据异常"), PROCESS_SET_ASSIGNEE_PARAM_ERROR("028", "当前审批业务审批人模型中 NodeId 必传(topNodeId/nodeId均可), 触发 ID: 【{}】"), TASK_OPERATION_PARAM_INVALID("029", "流程实例 ID 与任务 ID 必须二选一"), + COOPERATION_NOT_EXIST_WITH_NODE("030", "查询审批人时,组织不存在"), ; private final String code; 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 0daac19ab..f86508f1d 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 @@ -160,6 +160,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_LOG_NODE_HAS_BEEN_HIDDEN = "_TASK_LOG_HIDDEN"; String TASK_ATTACHMENTS_VAR_NAME = "TASK_ATTACHMENTS"; /** 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 4ae46cef7..a819d30e2 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 @@ -19,6 +19,7 @@ public enum BpmnProcessInstanceResultEnum { UPGRADED("UPGRADED", "已提级"), COMMENTED("COMMENTED", "已评论"), DELETED("DELETED", "已删除"), + HIDDEN("HIDDEN", "已隐藏"), @JsonEnumDefaultValue UNKNOWN("UNKNOWN", "未知"), ; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/exception/WorkflowApproverCalcException.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/exception/WorkflowApproverCalcException.java new file mode 100644 index 000000000..8956569cc --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/exception/WorkflowApproverCalcException.java @@ -0,0 +1,75 @@ +package cn.axzo.workflow.common.exception; + +import cn.axzo.framework.domain.ServiceException; +import cn.axzo.framework.domain.web.code.IRespCode; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; + +/** + * 流程内部计算审批人的异常 + * + * @author wangli + * @since 2025-11-03 10:11 + */ +@Slf4j +public class WorkflowApproverCalcException extends ServiceException { + + private String code; + + public WorkflowApproverCalcException(IRespCode code) { + super(code.getMessage()); + this.code = code.getRespCode(); + } + + public WorkflowApproverCalcException(IRespCode code, String... params) { + super(doFormat(code.getCode(), code.getMessage(), params)); + this.code = code.getRespCode(); + } + + public WorkflowApproverCalcException(IRespCode code, Throwable cause, String... params) { + super(doFormat(code.getCode(), code.getMessage(), params), cause); + this.code = code.getRespCode(); + } + + @Override + public String getCode() { + return this.code; + } + + /** + * 将错误编号对应的消息使用 params 进行格式化。 + * + * @param code 错误编号 + * @param messagePattern 消息模版 + * @param params 参数 + * @return 格式化后的提示 + */ + @VisibleForTesting + private static String doFormat(String code, String messagePattern, Object... params) { + StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50); + int i = 0; + int j; + int l; + for (l = 0; l < params.length; l++) { + j = messagePattern.indexOf("{}", i); + if (j == -1) { + log.warn("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params); + if (i == 0) { + return messagePattern; + } else { + sbuf.append(messagePattern.substring(i)); + return sbuf.toString(); + } + } else { + sbuf.append(messagePattern, i, j); + sbuf.append(params[l]); + i = j + 2; + } + } + if (messagePattern.indexOf("{}", i) != -1) { + log.warn("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params); + } + sbuf.append(messagePattern.substring(i)); + return sbuf.toString(); + } +} 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 99992115d..614088a31 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 @@ -42,7 +42,9 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERAT import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.HIDDEN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; @@ -159,7 +161,12 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER, nextApprover); } - task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + Boolean logNodeHidden = (Boolean) task.getTransientVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN); + if (logNodeHidden) { + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, HIDDEN.getStatus()); + } else { + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); + } // 更新流程内的变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); 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 880a0138c..682da5d49 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 @@ -7,6 +7,7 @@ import cn.axzo.karma.client.model.response.PersonProfileResp; import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp; import cn.axzo.workflow.common.enums.ApproverScopeEnum; import cn.axzo.workflow.common.enums.CarbonCopyObjectType; +import cn.axzo.workflow.common.exception.WorkflowApproverCalcException; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; @@ -45,6 +46,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.BpmnTaskRespCode.CALC_TASK_ASSIGNEE_ERROR; +import static cn.axzo.workflow.common.code.BpmnTaskRespCode.COOPERATION_NOT_EXIST_WITH_NODE; import static cn.axzo.workflow.common.code.ConvertorRespCode.CONVERTOR_META_DATA_FORMAT_ERROR; import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_CALC_ERROR; import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TASK_PARAM_ERROR; @@ -122,6 +124,40 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign return Collections.emptyList(); } + protected final T parseFoundationApiResultWithErrCode(Supplier> supplier, String operatorDesc, + String extInfo, Object... param) { + StopWatch stopWatch = new StopWatch(operatorDesc); + log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param)); + stopWatch.start(); + cn.axzo.foundation.result.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() > refreshProperties.getApiTimeout() && Boolean.TRUE.equals(refreshProperties.getSendDingTalk())) { + DingTalkUtils.sendDingTalkForSlowUrl(applicationContext.getEnvironment() + .getProperty("spring.profiles.active"), + stopWatch.getTotalTimeSeconds(), + extInfo, + param, + result); + } + } catch (Exception e) { + // ignore + } + Assert.notNull(result, "服务调用异常"); + if (Objects.equals(30022100, result.getCode())) { + // 特殊需求,组织不存在时抛得的异常码 + throw new WorkflowApproverCalcException(COOPERATION_NOT_EXIST_WITH_NODE); + } + // 200自定义处理 + if (HttpStatus.HTTP_OK != result.getCode()) { + throw new WorkflowEngineException(CALC_TASK_ASSIGNEE_ERROR, "[API:" + extInfo + "]" + result.getMsg()); + } + return result.getData(); + } + protected final T parseFoundationApiResult(Supplier> supplier, String operatorDesc, String extInfo, Object... param) { StopWatch stopWatch = new StopWatch(operatorDesc); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java index f86d05307..1a68aa9e8 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java @@ -9,9 +9,11 @@ import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum; import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import cn.axzo.workflow.common.exception.WorkflowApproverCalcException; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; @@ -21,6 +23,7 @@ import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -33,6 +36,7 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_USER_TA import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecifyRange; @@ -120,8 +124,14 @@ public class BasedIdentityV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne break; } FlowTaskAssignerV2Req request = v2ReqBuilder.build(); - List apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询身份下的人" + execution.getProcessInstanceId() + flowElement.getId(), - "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request); + List apiResultUsers = new ArrayList<>(); + try { + apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询身份下的人" + execution.getProcessInstanceId() + flowElement.getId(), + "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); + } catch (WorkflowApproverCalcException e) { + log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java index 9161ef04c..f01df895a 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java @@ -7,8 +7,10 @@ import cn.axzo.orggateway.api.nodeuser.req.FlowTaskAssignerV2Req; import cn.axzo.orggateway.api.nodeuser.resp.FlowTaskAssignerV2Resp; import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import cn.axzo.workflow.common.exception.WorkflowApproverCalcException; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.hutool.json.JSONUtil; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; @@ -17,12 +19,14 @@ import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin; import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType; @@ -74,8 +78,14 @@ public class BasedInitiatorLeaderV2TaskAssigneeSelector extends AbstractBpmnTask .querySupervisorWhileMissMatched(getApproverEmptyHandleType(flowElement).filter(type -> Objects.equals(type, transferToAdmin)).isPresent()); FlowTaskAssignerV2Req request = v2ReqBuilder.build(); - List apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询发起人主管的审批人" + execution.getProcessInstanceId() + flowElement.getId(), - "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request); + List apiResultUsers = new ArrayList<>(); + try { + apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询发起人主管的审批人" + execution.getProcessInstanceId() + flowElement.getId(), + "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); + } catch (WorkflowApproverCalcException e) { + log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java index 31eed2e82..f7adc6cfb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java @@ -10,9 +10,11 @@ import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum; import cn.axzo.workflow.common.enums.CooperateShipTypeEnum; import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import cn.axzo.workflow.common.exception.WorkflowApproverCalcException; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; @@ -22,6 +24,7 @@ import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -33,6 +36,7 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_POSITIO import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin; import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType; @@ -143,8 +147,14 @@ public class BasedPositionV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne break; } FlowTaskAssignerV2Req request = v2ReqBuilder.build(); - List apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询岗位下的人" + execution.getProcessInstanceId() + flowElement.getId(), - "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request); + List apiResultUsers = new ArrayList<>(); + try { + apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询岗位下的人" + execution.getProcessInstanceId() + flowElement.getId(), + "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); + } catch (WorkflowApproverCalcException e) { + log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java index c4f3574a6..7f297388b 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java @@ -10,9 +10,11 @@ import cn.axzo.workflow.common.enums.ApproverSpecifyRangeEnum; import cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum; import cn.axzo.workflow.common.enums.CooperateShipTypeEnum; import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import cn.axzo.workflow.common.exception.WorkflowApproverCalcException; import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; @@ -23,6 +25,7 @@ import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -34,6 +37,7 @@ import static cn.axzo.workflow.common.code.FlowableEngineRespCode.ENGINE_ROLE_V2 import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION; import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum.transferToAdmin; import static cn.axzo.workflow.common.enums.ApproverSpecifyRangeUnitEnum.in_project; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType; @@ -146,8 +150,14 @@ public class BasedRoleV2TaskAssigneeSelector extends AbstractBpmnTaskAssigneeSel break; } FlowTaskAssignerV2Req request = v2ReqBuilder.build(); - List apiResultUsers = parseFoundationApiResult(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询角色下的人" + execution.getProcessInstanceId() + flowElement.getId(), - "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request); + List apiResultUsers = new ArrayList<>(); + try { + apiResultUsers.addAll(parseFoundationApiResultWithErrCode(() -> orgNodeUserApi.listFlowTaskAssignerV2(request), "新版查询角色下的人" + execution.getProcessInstanceId() + flowElement.getId(), + "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); + } catch (WorkflowApproverCalcException e) { + log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java index 228eedc08..22ea57fbb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java @@ -59,6 +59,7 @@ 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.SUPPORT_UPGRADE_VARIABLE; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; +import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody; import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.BACK_COUNTERSIGN; import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN; @@ -291,6 +292,8 @@ public class TaskEntityEventHandle implements EntityEventHandle { needDelete = true; } } + // 重置日志隐藏的标识为 false + taskEntity.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, false); update.setEndTime(new Date()); // 判断是否抄送节点,如果是的话,需要将抄送人集合放入对应字段 From 496eef6b5cb1440aa423a86773c6a9dcacfaaa96 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Nov 2025 09:34:52 +0800 Subject: [PATCH 40/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E7=89=88=E6=97=A5=E5=BF=97=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=BD=91=E5=9D=80=E7=9A=84=E4=BC=A0=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/common/model/dto/CustomDocDTO.java | 2 +- .../axzo/workflow/core/conf/SupportRefreshProperties.java | 2 +- .../server/controller/web/manage/PrintAdminController.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java index c61b3b7ef..748b25ba2 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CustomDocDTO.java @@ -53,7 +53,7 @@ public class CustomDocDTO implements Serializable { private String fileKey; /** - * 文件的类型 + * 文件的类型,如果要替换变量,支持 docx 格式,doc 格式不支持。 */ @NotNull(message = "业务自定义文件的类型不能为空") private FileTypeEnum fileType; 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 5e652d9df..00328ecc5 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 @@ -108,7 +108,7 @@ public class SupportRefreshProperties { @Value("${workflow.ignoreMqAlterApplicationNames:}") private List ignoreMqAlterApplicationNames; - @Value("${workflow.processLogHtmlUrl:https://www.axzo.cn/}") + @Value("${workflow.processLogHtmlUrl:https://taskflow-web.axzo.cn/#/document/log?processInstanceId=%s&personId=%d}") private String processLogHtmlUrl; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 39d1bd8f7..56029b3b1 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -51,7 +51,6 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import io.swagger.v3.oas.annotations.Operation; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.common.engine.impl.interceptor.CommandExecutor; @@ -64,6 +63,7 @@ import org.flowable.form.model.FormField; import org.flowable.form.model.FormFieldTypes; import org.flowable.form.model.SimpleFormModel; import org.flowable.spring.SpringProcessEngineConfiguration; +import org.slf4j.Logger; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -144,13 +144,13 @@ import static cn.azxo.framework.common.model.CommonResponse.success; * @author wangli * @since 2025-01-16 17:48 */ -@Slf4j @RequestMapping({"/web/v1/api/print/admin", "/api/print/admin"}) @RestController @ErrorReporter @Validated public class PrintAdminController implements PrintAdminApi { + private static final Logger log = org.slf4j.LoggerFactory.getLogger(PrintAdminController.class); @Resource private FormRepositoryService formRepositoryService; @Resource @@ -592,7 +592,7 @@ public class PrintAdminController implements PrintAdminApi { request.setBizCode("workflow-process-log"); request.setBizKey(dto.getProcessInstanceId()); request.setConversionType(DocConversionTypeEnum.HTML_URL_TO_PDF); - request.setFileName(refreshProperties.getProcessLogHtmlUrl()); + request.setFileName(String.format(refreshProperties.getProcessLogHtmlUrl(), dto.getProcessInstanceId(), dto.getPersonId())); request.setFileKey(dto.getPersonId()); String taskId = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.submitConvertTask(request), "创建网页转 PDF 的异步任务", request); return CommonResponse.success(taskId); From e2802ec78ee00d4f31d4f37b91bec5118693c92e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Nov 2025 10:56:25 +0800 Subject: [PATCH 41/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=AE=A1=E6=89=B9=E7=9A=84=E5=85=A5=E5=8F=82?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java index 64f53ee47..499631039 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java @@ -41,7 +41,7 @@ public class CooperationOrgDTO implements Serializable { private List includeSpecialtyCodes; /** - * 控制仅支持工程内人员参与审批 + * 该参数仅应用于节点的高级设置中的"仅支持工程内人员参与审批” */ private List projectIds; From 48cbd0216450a0f184f02733baa06d11449b62af Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Nov 2025 13:55:07 +0800 Subject: [PATCH 42/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=AE=A1=E6=89=B9=E6=97=A5=E6=9C=9F=E8=BD=AC?= =?UTF-8?q?=20pdf=20=E7=9A=84=E4=BB=BB=E5=8A=A1=E5=86=85=E9=83=A8=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/manage/PrintAdminController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 56029b3b1..6a99eb044 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -593,7 +593,6 @@ public class PrintAdminController implements PrintAdminApi { request.setBizKey(dto.getProcessInstanceId()); request.setConversionType(DocConversionTypeEnum.HTML_URL_TO_PDF); request.setFileName(String.format(refreshProperties.getProcessLogHtmlUrl(), dto.getProcessInstanceId(), dto.getPersonId())); - request.setFileKey(dto.getPersonId()); String taskId = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.submitConvertTask(request), "创建网页转 PDF 的异步任务", request); return CommonResponse.success(taskId); } From 8af2839cefc70ea6b5d1e81c98cbc711b8845c2a Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Tue, 4 Nov 2025 15:30:05 +0800 Subject: [PATCH 43/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=86=85=E9=83=A8=E5=A4=84=E7=90=86=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/controller/web/manage/PrintAdminController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 6a99eb044..6f6753a1d 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -525,8 +525,8 @@ public class PrintAdminController implements PrintAdminApi { .value(user.isPresent() ? user.get().getRealName() : "") .build()); systemVarItems.add(TableItemDTO.builder() - .label(PRINT_VAR_PROCESS_INITIATOR_UNIT) - .code(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) + .label(PRINT_VAR_PROCESS_INITIATOR_UNIT_DESC) + .code(PRINT_VAR_PROCESS_INITIATOR_UNIT) .type(FORM_FIELD_TYPE_INPUT) .value(user.isPresent() ? user.get().getOrganizationalUnitName() : "") .build()); From 1800d9871138f59be1d30cf02a0119273c9ab083 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Nov 2025 10:30:35 +0800 Subject: [PATCH 44/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=8C=85=E5=90=AB=E4=B8=9A=E5=8A=A1=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=90=8E=E7=9A=84=E5=86=85=E9=83=A8=E5=B7=B2?= =?UTF-8?q?=E8=AF=BB=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomApproveTaskCmd.java | 2 +- .../core/service/ExtAxReadRecordService.java | 3 +- .../impl/ExtAxReadRecordServiceImpl.java | 18 ++++-- .../bpmn/BpmnProcessInstanceController.java | 56 +++++++++---------- 4 files changed, 41 insertions(+), 38 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 614088a31..45c06d1e7 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 @@ -162,7 +162,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria nextApprover); } Boolean logNodeHidden = (Boolean) task.getTransientVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN); - if (logNodeHidden) { + if (Objects.nonNull(logNodeHidden) && logNodeHidden) { task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, HIDDEN.getStatus()); } else { task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxReadRecordService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxReadRecordService.java index cbc092036..c9ec7a8e1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxReadRecordService.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxReadRecordService.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.service; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO; @@ -18,5 +19,5 @@ public interface ExtAxReadRecordService extends IService { List queryReadStatus(ApproverReadStatusDTO dto); - Boolean changeReadStatus(ChangeApproverReadStatusDTO dto); + Boolean changeReadStatus(ChangeApproverReadStatusDTO dto, List customDocs); } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxReadRecordServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxReadRecordServiceImpl.java index cdeec873f..ca1affeb0 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxReadRecordServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxReadRecordServiceImpl.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.service.impl; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ApproverReadStatusDTO; import cn.axzo.workflow.common.model.request.bpmn.process.doc.ChangeApproverReadStatusDTO; @@ -11,7 +12,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; -import org.flowable.engine.TaskService; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @@ -34,8 +34,6 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl customDocs) { ExtAxReadRecord entity = new ExtAxReadRecord(); entity.setProcessInstanceId(dto.getProcessInstanceId()); entity.setPersonId(Long.valueOf(dto.getAssigner().getPersonId())); @@ -63,7 +61,11 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl 0 ? modelDocService.get(dto.getDocId()).getTag() + : customDocs.stream() + .filter(i -> Objects.equals(i.getId(), dto.getDocId())) + .findFirst() + .orElse(new CustomDocDTO()).getFileTag()) .readStatus(dto.getReadStatus()) .build())); extAxReadRecordMapper.insert(record); @@ -76,7 +78,11 @@ public class ExtAxReadRecordServiceImpl extends ServiceImpl 0 ? modelDocService.get(dto.getDocId()).getTag() + : customDocs.stream() + .filter(i -> Objects.equals(i.getId(), dto.getDocId())) + .findFirst() + .orElse(new CustomDocDTO()).getFileTag()) .readStatus(dto.getReadStatus()) .build()); } 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 6f66a0110..6457f001f 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 @@ -7,6 +7,7 @@ import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse; import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.exception.WorkflowEngineException; +import cn.axzo.workflow.common.model.dto.CustomDocDTO; import cn.axzo.workflow.common.model.dto.SignFileDTO; import cn.axzo.workflow.common.model.dto.SimpleDocDTO; import cn.axzo.workflow.common.model.request.bpmn.log.LogApproveSearchDTO; @@ -68,6 +69,7 @@ import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; import org.flowable.common.engine.impl.interceptor.CommandExecutor; +import org.flowable.engine.RuntimeService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.beans.BeanUtils; @@ -97,6 +99,7 @@ import java.util.stream.Stream; import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_DOC_ID_NOT_IN_MODEL; import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_DOC_READ_PARAM_ERROR; import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_EXT_LOG_PARAM_ERROR; +import static cn.axzo.workflow.common.constant.BpmnConstants.SIGN_BIZ_CUSTOM_DOCS; import static cn.azxo.framework.common.model.CommonResponse.success; /** @@ -308,8 +311,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @PutMapping("/status/update") @RepeatSubmit @Override - public CommonResponse updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, - @NotNull(message = "状态不能为空") @RequestParam Integer status) { + public CommonResponse updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId, @NotNull(message = "状态不能为空") @RequestParam Integer status) { log.info("获得流程实例 updateProcessStatus===>>>参数:{},{}", processDefinitionId, status); Boolean result = bpmnProcessInstanceService.updateProcessStatus(processDefinitionId, status); return success(result); @@ -325,8 +327,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @Operation(summary = "获取审批流程实例的运行图") @GetMapping("/graphical") @Override - public CommonResponse processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable @RequestParam(required = false) String tenantId) { + public CommonResponse processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId) { return success(bpmnProcessInstanceService.getProcessInstanceGraphical(processInstanceId, tenantId)); } @@ -340,8 +341,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @Operation(summary = "获取指定实例的全节点执行顺序推算") @GetMapping("/node/forecasting") @Override - public CommonResponse> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable String tenantId) { + public CommonResponse> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) { return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId)); } @@ -358,10 +358,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序") @GetMapping("/node/filter/forecasting") @Override - public CommonResponse> 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) { + public CommonResponse> 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) { if (allNode) { return success(bpmnProcessInstanceService.getProcessInstanceNodeForecast(processInstanceId, tenantId)); } else { @@ -379,10 +376,8 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController @Operation(summary = "获取指定流程实例的流程变量") @GetMapping("/cooperation-org") @Override - public CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, - @Nullable String tenantId) { - HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId, - tenantId, true); + public CommonResponse> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable String tenantId) { + HistoricProcessInstance processInstance = bpmnProcessInstanceService.getProcessInstance(processInstanceId, tenantId, true); return success(processInstance.getProcessVariables()); } @@ -477,18 +472,10 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController } 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()); + 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))); + 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))); } } @@ -520,8 +507,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController } ApiSignUrlDownloadRequest ossRequest = new ApiSignUrlDownloadRequest(); ossRequest.setFileKeys(fileKeys); - Map ossUrlMap = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(ossRequest), "批量获取文件 OSS 地址", ossRequest) - .stream().collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, Function.identity(), (s, t) -> s)); + Map ossUrlMap = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(ossRequest), "批量获取文件 OSS 地址", ossRequest).stream().collect(Collectors.toMap(ApiSignUrlDownloadResponse::getFileKey, Function.identity(), (s, t) -> s)); docs.forEach(i -> { if (StringUtils.hasText(i.getFileKey())) { ApiSignUrlDownloadResponse ossFileInfo = ossUrlMap.getOrDefault(i.getFileKey(), null); @@ -553,10 +539,20 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController } CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor(); List relationDocs = commandExecutor.execute(new CustomGetModelDocsCmd(dto.getProcessInstanceId(), true, extAxModelDocMapper, extAxReModelService)); - relationDocs.stream().filter(i -> Objects.equals(i.getId(), dto.getDocId())) - .findAny().orElseThrow(() -> new WorkflowEngineException(PROCESS_DOC_ID_NOT_IN_MODEL)); - return success(readRecordService.changeReadStatus(dto)); + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + List customDocs = ListUtils.emptyIfNull(runtimeService.getVariable(dto.getProcessInstanceId(), SIGN_BIZ_CUSTOM_DOCS, List.class)); + + // 检查 relationDocs 中是否存在具有指定 id 的对象 + boolean existsInRelationDocs = relationDocs.stream().anyMatch(doc -> Objects.equals(doc.getId(), dto.getDocId())); + + // 检查 customDocs 中是否存在具有指定 id 的对象 + boolean existsInCustomDocs = customDocs.stream().anyMatch(doc -> Objects.equals(doc.getId(), dto.getDocId())); + if (!existsInRelationDocs && !existsInCustomDocs) { + throw new WorkflowEngineException(PROCESS_DOC_ID_NOT_IN_MODEL); + } + + return success(readRecordService.changeReadStatus(dto, customDocs)); } @Override From 98ec67641fcaf420b4e03a852c5028069c4810e9 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 5 Nov 2025 17:06:15 +0800 Subject: [PATCH 45/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomGetConditionPermissionsCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java index 3f81e7318..0b1a524c5 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetConditionPermissionsCmd.java @@ -56,7 +56,7 @@ public class CustomGetConditionPermissionsCmd extends AbstractCommand conditions = BpmnMetaParserHelper.getConditionPermissionConf(flowElement).orElse(Collections.emptyList()); conditions.forEach(e -> e.setValue(null)); return conditions; From 3988c3bb60f0dcd05ce73273b269c53691799646 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Nov 2025 11:52:11 +0800 Subject: [PATCH 46/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=9B=A0=E7=BB=84=E7=BB=87=E4=B8=8D=E5=AD=98=E5=9C=A8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=9A=84=E8=8A=82=E7=82=B9=E6=97=A5=E5=BF=97=E9=9A=90?= =?UTF-8?q?=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/engine/cmd/CustomApproveTaskCmd.java | 9 +-------- .../delegate/BasedIdentityV2TaskAssigneeSelector.java | 2 +- .../BasedInitiatorLeaderV2TaskAssigneeSelector.java | 2 +- .../delegate/BasedPositionV2TaskAssigneeSelector.java | 2 +- .../delegate/BasedRoleV2TaskAssigneeSelector.java | 2 +- .../controller/web/manage/PrintAdminController.java | 8 ++++---- .../engine/ext/listener/TaskEntityEventHandle.java | 7 ++++++- 7 files changed, 15 insertions(+), 17 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 45c06d1e7..99992115d 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 @@ -42,9 +42,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERAT import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER; import static cn.axzo.workflow.common.constant.BpmnConstants.SIGNATURE_COLLECTION; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; -import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_LOG_NODE_HAS_BEEN_HIDDEN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; -import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.HIDDEN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; @@ -161,12 +159,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER, nextApprover); } - Boolean logNodeHidden = (Boolean) task.getTransientVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN); - if (Objects.nonNull(logNodeHidden) && logNodeHidden) { - task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, HIDDEN.getStatus()); - } else { - task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); - } + task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus()); // 更新流程内的变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java index 1a68aa9e8..011428252 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedIdentityV2TaskAssigneeSelector.java @@ -130,7 +130,7 @@ public class BasedIdentityV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); } catch (WorkflowApproverCalcException e) { log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); - execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true); } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java index f01df895a..498117d16 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedInitiatorLeaderV2TaskAssigneeSelector.java @@ -84,7 +84,7 @@ public class BasedInitiatorLeaderV2TaskAssigneeSelector extends AbstractBpmnTask "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); } catch (WorkflowApproverCalcException e) { log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); - execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true); } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java index f7adc6cfb..9bc846f88 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedPositionV2TaskAssigneeSelector.java @@ -153,7 +153,7 @@ public class BasedPositionV2TaskAssigneeSelector extends AbstractBpmnTaskAssigne "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); } catch (WorkflowApproverCalcException e) { log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); - execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true); } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java index 7f297388b..527d89acb 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/delegate/BasedRoleV2TaskAssigneeSelector.java @@ -156,7 +156,7 @@ public class BasedRoleV2TaskAssigneeSelector extends AbstractBpmnTaskAssigneeSel "cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.listFlowTaskAssignerV2", request)); } catch (WorkflowApproverCalcException e) { log.warn("组织节点不存在, 入参:{}; 错误信息:{}", JSONUtil.toJsonStr(request), e.getMessage(), e); - execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, true); + execution.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + flowElement.getId(), true); } return convertApprover(apiResultUsers); } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 6f6753a1d..79fa12596 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -226,15 +226,15 @@ public class PrintAdminController implements PrintAdminApi { FormContainer formContainer = (FormContainer) formField; printFields.addAll(formContainer.getFields().get(0).stream() .filter(field -> { - if (Objects.equals(Boolean.TRUE, dto.getFilterEnablePrint())) { +// if (Objects.equals(Boolean.TRUE, dto.getFilterEnablePrint())) { if (!CollectionUtils.isEmpty(field.getParams())) { Optional optEnablePrint = Optional.ofNullable(field.getParam("enablePrint")); return optEnablePrint.map(obj -> Boolean.parseBoolean(obj.toString())).orElse(Boolean.TRUE); } return true; - } else { - return false; - } +// } else { +// return false; +// } }) .map(field -> { PrintFieldDTO printFieldDTO = new PrintFieldDTO() diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java index 22ea57fbb..7f13d2825 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java @@ -69,6 +69,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.DELETED; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.HIDDEN; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.HANDLING; import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getActivitySignature; @@ -286,6 +287,10 @@ public class TaskEntityEventHandle implements EntityEventHandle { String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class); if (StringUtils.hasText(completionType) && !Objects.equals(DELETED.getStatus(), completionType)) { update.setStatus(completionType); + Boolean hiddenLog = taskEntity.getVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + taskEntity.getTaskDefinitionKey(), Boolean.class); + if (Objects.equals(hiddenLog, Boolean.TRUE)) { + update.setStatus(HIDDEN.getStatus()); + } } else { // 多实例除操作人以外的任务,直接删除日志, 例如一个节点有两个人或签,A 人驳回了,那么 B 人不再需要操作,任务自动删除。而会签也同理 update.setStatus(DELETED.getStatus());// delete标志着是多实例删除 @@ -293,7 +298,7 @@ public class TaskEntityEventHandle implements EntityEventHandle { } } // 重置日志隐藏的标识为 false - taskEntity.setVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN, false); + taskEntity.removeVariable(TASK_LOG_NODE_HAS_BEEN_HIDDEN + taskEntity.getTaskDefinitionKey()); update.setEndTime(new Date()); // 判断是否抄送节点,如果是的话,需要将抄送人集合放入对应字段 From b72909449bb5a1ad0a4d8077f3056258aad53563 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Nov 2025 18:31:42 +0800 Subject: [PATCH 47/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E9=98=B2=E5=BE=A1?= =?UTF-8?q?=E6=80=A7=E7=BC=96=E7=A8=8B=EF=BC=8C=E5=85=BC=E5=AE=B9=20NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java index 80ffb959a..469dfe7d4 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomGetProcessInstanceVariablesCmd.java @@ -67,7 +67,9 @@ public class CustomGetProcessInstanceVariablesCmd extends AbstractCommand Date: Thu, 6 Nov 2025 18:32:17 +0800 Subject: [PATCH 48/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BB=BB=E5=8A=A1=E5=85=A5=E5=8F=82=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/request/bpmn/task/BpmnTaskAuditDTO.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java index 61b1a17bf..0cfe59964 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskAuditDTO.java @@ -106,7 +106,9 @@ public class BpmnTaskAuditDTO { private String operationDesc; /** - * 更新或新增流程变量 + * 更新或新增流程变量, + *

+ * 如果不修改,则map 的 value 设置为 null,内部会自动过滤 */ private Map variables; } From 3a755e0d9058ad1428ac32bae227947e18a98db5 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Nov 2025 18:32:43 +0800 Subject: [PATCH 49/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=20ibatis=20=E6=B3=A8=E8=A7=A3=E4=B8=8D=E8=83=BD=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E5=93=8D=E5=BA=94=20json=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/repository/mapper/ExtAxProcessLogMapper.java | 7 +++++++ 1 file changed, 7 insertions(+) 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 index 185b648ac..3eefd77b1 100644 --- 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 @@ -1,9 +1,13 @@ package cn.axzo.workflow.core.repository.mapper; +import cn.axzo.workflow.core.conf.handler.ListAssigneeTypeHandler; import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.type.JdbcType; @Mapper public interface ExtAxProcessLogMapper extends BaseMapperX { @@ -13,5 +17,8 @@ public interface ExtAxProcessLogMapper extends BaseMapperX { @Select("select * from ext_ax_process_log WHERE process_instance_id = #{processInstanceId} and task_id = #{taskId}") + @Results({ + @Result(column = "assignee_full", property = "assigneeFull", jdbcType = JdbcType.ARRAY, typeHandler = ListAssigneeTypeHandler.class) + }) ExtAxProcessLog findByProcessIdAndTaskIdWithDeleted(String processInstanceId, String taskId); } From ccf56781fc4ddaaf01d1f341b69602753b1027a4 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Thu, 6 Nov 2025 18:33:23 +0800 Subject: [PATCH 50/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=90=8C=E6=84=8F=E6=93=8D=E4=BD=9C=E6=97=B6=E7=9A=84=E7=A9=BA?= =?UTF-8?q?=E5=80=BC=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/core/conf/SupportRefreshProperties.java | 2 +- .../controller/web/bpmn/BpmnProcessTaskController.java | 9 +++++++++ 2 files changed, 10 insertions(+), 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 00328ecc5..7b3689bbe 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 @@ -108,7 +108,7 @@ public class SupportRefreshProperties { @Value("${workflow.ignoreMqAlterApplicationNames:}") private List ignoreMqAlterApplicationNames; - @Value("${workflow.processLogHtmlUrl:https://taskflow-web.axzo.cn/#/document/log?processInstanceId=%s&personId=%d}") + @Value("${workflow.processLogHtmlUrl:https://taskflow-web.axzo.cn/#/document/log?processInstanceId=%s&personId=%s}") private String processLogHtmlUrl; } 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 29b7a051b..ffdec2cac 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 @@ -54,6 +54,7 @@ import javax.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_OPERATION_PARAM_INVALID; @@ -112,6 +113,10 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp if (!StringUtils.hasText(dto.getTaskId())) { dto.setTaskId(bpmnProcessTaskService.findTaskIdByInstanceIdAndPersonId(dto.getProcessInstanceId(), dto.getApprover().getPersonId())); } + + // 移除 variable 中 value 为 null 的 key + dto.getVariables().entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + List tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>()); if (StringUtils.hasText(dto.getSignatureUrl())) { AttachmentDTO signature = new AttachmentDTO(); @@ -138,6 +143,10 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp if (!StringUtils.hasText(dto.getTaskId())) { dto.setTaskId(bpmnProcessTaskService.findTaskIdByInstanceIdAndPersonId(dto.getProcessInstanceId(), dto.getApprover().getPersonId())); } + + // 移除 variable 中 value 为 null 的 key + dto.getVariables().entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + List tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>()); if (StringUtils.hasText(dto.getSignatureUrl())) { AttachmentDTO signature = new AttachmentDTO(); From 8722e5baeacdcc7887859bedc39ee25b5771b858 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Nov 2025 15:53:27 +0800 Subject: [PATCH 51/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=90=8C=E6=84=8F=E5=8A=9F=E8=83=BD=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/SignatureDTO.java | 5 +-- .../core/engine/cmd/CustomApproveTaskCmd.java | 11 ++++-- .../cmd/CustomApproveTaskWithFormCmd.java | 35 ++----------------- .../workflow/server/common/util/WpsUtil.java | 19 ++++++++++ .../web/bpmn/BpmnProcessTaskController.java | 5 +-- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java index 6eb129612..708510905 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/SignatureDTO.java @@ -1,6 +1,5 @@ package cn.axzo.workflow.common.model.dto; -import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -41,9 +40,11 @@ public class SignatureDTO implements Serializable { @Accessors(chain = true) public static class SignDetail implements Serializable { private static final long serialVersionUID = 1L; + //审批人姓名 + private String approverName; private String signature; private String advice; - private BpmnProcessTaskResultEnum result; + private String result; private Date operationTime; } } 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 99992115d..2b71bf786 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 @@ -164,7 +164,7 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria // 更新流程内的变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 - recordSignature(task, runtimeService); + recordSignature(task, runtimeService, attachmentList, advice, approver); resetApproverNode(task.getProcessInstanceId()); @@ -192,7 +192,11 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria approver.setNodeId(logs.get(0).getAssigneeFull().get(0).getNodeId()); } - private void recordSignature(TaskEntity task, RuntimeService runtimeService) { + public static void recordSignature(TaskEntity task, + RuntimeService runtimeService, + List attachmentList, + String advice, + BpmnTaskDelegateAssigner approver) { List signatures = runtimeService.getVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, List.class); if (Objects.isNull(signatures)) { signatures = new ArrayList<>(); @@ -208,9 +212,10 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria .findFirst() .ifPresent(attachment -> dto.getSignatures().add(0, new SignatureDTO.SignDetail() + .setApproverName(approver.getAssignerName()) .setSignature(attachment.getUrl()) .setAdvice(advice) - .setResult(BpmnProcessTaskResultEnum.APPROVED) + .setResult(BpmnProcessTaskResultEnum.APPROVED.getDesc()) .setOperationTime(new Date()))); if (!any.isPresent()) { signatures.add(dto); diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java index 4b3a31795..2c8b9426f 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java @@ -1,9 +1,7 @@ package cn.axzo.workflow.core.engine.cmd; -import cn.axzo.workflow.common.enums.AttachmentTypeEnum; import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.exception.WorkflowEngineException; -import cn.axzo.workflow.common.model.dto.SignatureDTO; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditWithFormDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; @@ -14,7 +12,6 @@ import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog; import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService; import cn.axzo.workflow.core.service.ExtAxProcessLogService; import com.alibaba.fastjson.JSON; -import org.apache.commons.collections4.ListUtils; import org.flowable.common.engine.impl.identity.Authentication; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.engine.RuntimeService; @@ -34,12 +31,10 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.io.Serializable; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -48,10 +43,10 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIG 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.SIGNATURE_COLLECTION; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_SUBMIT_FORM_VARIABLE; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; +import static cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd.recordSignature; 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; @@ -183,7 +178,7 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen // 更新流程实例变量 runtimeService.setVariables(task.getProcessInstanceId(), variables); // 记录电子签名的图片 - recordSignature(task, runtimeService); + recordSignature(task, runtimeService, attachmentList, advice, approver); resetApproverNode(task.getProcessInstanceId()); @@ -262,30 +257,4 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen } } - private void recordSignature(TaskEntity task, RuntimeService runtimeService) { - List signatures = runtimeService.getVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, List.class); - if (Objects.isNull(signatures)) { - signatures = new ArrayList<>(); - } - Optional any = signatures.stream() - .filter(i -> Objects.equals(i.getActivityId(), task.getTaskDefinitionKey())).findAny(); - SignatureDTO dto = any.orElse(new SignatureDTO() - .setActivityId(task.getTaskDefinitionKey()) - .setActivityName(task.getName()) - .setSignatures(new ArrayList<>())); - ListUtils.emptyIfNull(attachmentList).stream() - .filter(i -> Objects.equals(i.getType(), AttachmentTypeEnum.signature)) - .findFirst() - .ifPresent(attachment -> dto.getSignatures().add(0, - new SignatureDTO.SignDetail() - .setSignature(attachment.getUrl()) - .setAdvice(advice))); - if (!any.isPresent()) { - signatures.add(dto); - } - - if (!CollectionUtils.isEmpty(signatures)) { - runtimeService.setVariable(task.getProcessInstanceId(), SIGNATURE_COLLECTION, signatures); - } - } } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/WpsUtil.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/WpsUtil.java index 6c892eb24..1c8e9d116 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/WpsUtil.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/common/util/WpsUtil.java @@ -18,6 +18,7 @@ import cn.axzo.workflow.common.model.dto.UploadFieldDTO; import cn.axzo.workflow.common.model.dto.VariableObjectDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesToObjectCmd; +import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.google.common.collect.Lists; @@ -113,6 +114,18 @@ public class WpsUtil { List signDetails = (List) variableObjectDTO.getValue(); if (!CollectionUtils.isEmpty(signDetails)) { SignatureDTO.SignDetail signDetail = signDetails.get(0); + signatureAndAdvices.add(VariableObjectDTO.builder() + .key(variableObjectDTO.getKey() + "_approverName") + .desc(variableObjectDTO.getDesc() + "姓名") + .value(signDetail.getApproverName()) + .type(VariableObjectDTO.Type.text) + .build()); + signatureAndAdvices.add(VariableObjectDTO.builder() + .key(variableObjectDTO.getKey() + "_activityResult") + .desc(variableObjectDTO.getDesc() + "审批结果") + .value(signDetail.getResult()) + .type(VariableObjectDTO.Type.text) + .build()); ApiSignUrlDownloadRequest request = ApiSignUrlDownloadRequest.builder() .fileKeys(Lists.newArrayList(signDetail.getSignature())).build(); List signUrl = RpcExternalUtil.rpcProcessor(() -> serverFileServiceApi.signUrlFetchDownload(request), "获取手写签图片地址", request); @@ -128,6 +141,12 @@ public class WpsUtil { .value(signDetail.getAdvice()) .type(VariableObjectDTO.Type.text) .build()); + signatureAndAdvices.add(VariableObjectDTO.builder() + .key(variableObjectDTO.getKey() + "_activityOperationTime") + .desc(variableObjectDTO.getDesc() + "日期") + .value(DateUtil.format(signDetail.getOperationTime(), "yyyy.MM.dd")) + .type(VariableObjectDTO.Type.text) + .build()); } }); wpsVariables.addAll(signatureAndAdvices); 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 ffdec2cac..0031aa928 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 @@ -36,6 +36,7 @@ import com.alibaba.fastjson.JSON; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.MapUtils; import org.flowable.form.api.FormInfo; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -115,7 +116,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp } // 移除 variable 中 value 为 null 的 key - dto.getVariables().entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + MapUtils.emptyIfNull(dto.getVariables()).entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); List tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>()); if (StringUtils.hasText(dto.getSignatureUrl())) { @@ -145,7 +146,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp } // 移除 variable 中 value 为 null 的 key - dto.getVariables().entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + MapUtils.emptyIfNull(dto.getVariables()).entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); List tempAttachments = ListUtils.defaultIfNull(dto.getAttachmentList(), new ArrayList<>()); if (StringUtils.hasText(dto.getSignatureUrl())) { From 956c7d1314a63a9c1252d190a843247770bdea4c Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Nov 2025 17:22:49 +0800 Subject: [PATCH 52/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=9C=A8=E5=BE=85=E5=8A=9E=E4=B8=AD=E6=9F=A5=E7=9C=8B=E9=99=84?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/BpmnProcessInstanceServiceImpl.java | 54 +++++++++---------- ...opyTemplateFileTaskEvent_105_Listener.java | 1 + 2 files changed, 27 insertions(+), 28 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 4a086f16e..62c62f7b9 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 @@ -157,10 +157,9 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.stream.IntStream; import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME; import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CREATE_PARAM_ERROR; @@ -1916,46 +1915,45 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } private List getAndAddBizCustomDocs(String processInstanceId, List docs) { - HistoricProcessInstance processInstance = null; + String tenantId; if (CollectionUtils.isEmpty(docs)) { - processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + tenantId = Objects.nonNull(processInstance) ? processInstance.getTenantId() : ""; + } else { + tenantId = docs.get(0).getTenantId(); } List bizCustomDocs = Optional.ofNullable( runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) .orElse(Collections.emptyList()); - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); - boolean appendLast = "last".equals(customAddType); - Comparator orderComparator = Comparator.comparing( - DocBaseVO::getOrder, Comparator.nullsFirst(Comparator.naturalOrder())); - - Optional baseOpt; - Stream filtered = docs.stream().filter(Objects::nonNull); - if (appendLast) { - baseOpt = filtered.max(orderComparator); - } else { - baseOpt = filtered.min(orderComparator); - } - - int baseOrder = baseOpt.map(DocBaseVO::getOrder).orElse(0); - String tenantId = baseOpt.map(DocBaseVO::getTenantId).orElse(Objects.nonNull(processInstance) ? processInstance.getTenantId() : null); - - AtomicInteger orderCounter = new AtomicInteger(baseOrder); - int delta = appendLast ? 1 : -1; - - List docBaseVOS = BeanMapper.copyList(bizCustomDocs, DocBaseVO.class, (s, t) -> { + // 业务自定义文档 + List customBizDocs = BeanMapper.copyList(bizCustomDocs, DocBaseVO.class, (s, t) -> { t.setStatus(true); t.setTempFile(false); t.setTemplateName(s.getFileName()); - t.setOrder(orderCounter.addAndGet(delta)); + t.setTag(s.getFileTag()); t.setTenantId(tenantId); t.setFileRelationId(s.getFileKey()); }); - if (appendLast) { - docs.addAll(docBaseVOS); + List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); + if (!CollectionUtils.isEmpty(basedFileTagOrder)) { + docs.addAll(customBizDocs); + // 基于 fileTag 排序 + Map fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size()) + .boxed() + .collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a)); + + docs.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getTag(), Integer.MAX_VALUE))); + docs = docs.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getTag(), Integer.MAX_VALUE))) + .collect(Collectors.toList()); } else { - docs.addAll(0, docBaseVOS); + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); + if ("last".equals(customAddType)) { + docs.addAll(customBizDocs); + } else { + docs.addAll(0, customBizDocs); + } } return docs; diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index ee504d38f..354352415 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -125,6 +125,7 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve } List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); if (Objects.nonNull(basedFileTagOrder)) { + docTemplates.addAll(customDocTemplates); // 基于 fileTag 排序 Map fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size()) .boxed() From 2d25ff475d587b04a30996d5d8ed6063e76a126e Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Fri, 7 Nov 2025 18:23:35 +0800 Subject: [PATCH 53/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=BC=95=E6=93=8E=E6=B5=8B=E5=A2=9E=E5=8A=A0=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=97=A5=E5=BF=97pdf=20=E7=BB=93=E6=9E=9C=E6=9F=A5=E8=AF=A2=20?= =?UTF-8?q?API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/feign/manage/PrintAdminApi.java | 18 +++++++++- .../bpmn/print/QueryProcessLogPdfDTO.java | 30 ++++++++++++++++ .../print/ProcessLogPdfResultDTO.java | 36 +++++++++++++++++++ .../web/manage/PrintAdminController.java | 30 +++++++++++++--- 4 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/QueryProcessLogPdfDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/print/ProcessLogPdfResultDTO.java diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java index 79ce4d9d5..38ff9b3ba 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/manage/PrintAdminApi.java @@ -8,7 +8,9 @@ import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.QueryProcessLogPdfDTO; import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; +import cn.axzo.workflow.common.model.response.print.ProcessLogPdfResultDTO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; @@ -91,7 +93,10 @@ public interface PrintAdminApi { CommonResponse getPrintDataForProcessLog(@Validated @RequestBody Print4ProcessLogDTO dto); /** - * 后端请求指定流程日志 PDF 文件生成 + * 后端请求指定流程日志 PDF 文件生成, 实现是异步的。 + *

+ * 请使用 {@link PrintAdminApi#queryProcessLogPdfResult(QueryProcessLogPdfDTO)} 函数查询, + * 或者使用 {@link cn.axzo.nanopart.doc.api.conversion.DocConversionApi#queryConvertResultByBiz} 函数查询,bizCode:固定为"workflow-process-log", bizKey:为实例 ID * * @return */ @@ -99,4 +104,15 @@ public interface PrintAdminApi { @PostMapping("/api/print/admin/process/log/pdf") @InvokeMode(SYNC) CommonResponse createProcessLogPdf(@Validated @RequestBody PrintProcessLogPdfDTO dto); + + /** + * 后端查询指定审批日志 PDF 文件的生成结果 + * + * @param dto + * @return + */ + @Operation(summary = "后端查询指定审批日志 PDF 文件的生成结果") + @PostMapping("/api/print/admin/process/log/pdf/result") + @InvokeMode(SYNC) + CommonResponse queryProcessLogPdfResult(@Validated @RequestBody QueryProcessLogPdfDTO dto); } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/QueryProcessLogPdfDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/QueryProcessLogPdfDTO.java new file mode 100644 index 000000000..734d5f6d2 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/print/QueryProcessLogPdfDTO.java @@ -0,0 +1,30 @@ +package cn.axzo.workflow.common.model.request.bpmn.print; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 查询审批日志转 pdf 的入参模型 + * + * @author wangli + * @since 2025-10-31 17:15 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class QueryProcessLogPdfDTO { + + /** + * 审批实例 ID + */ + @ApiModelProperty(value = "审批实例 ID") + @NotBlank(message = "审批实例 ID 不能为空") + private String processInstanceId; + +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/print/ProcessLogPdfResultDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/print/ProcessLogPdfResultDTO.java new file mode 100644 index 000000000..0a06f1e41 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/print/ProcessLogPdfResultDTO.java @@ -0,0 +1,36 @@ +package cn.axzo.workflow.common.model.response.print; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 审批日志 PDF 查询结果相应模型 + * + * @author wangli + * @since 2025-11-07 18:13 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ProcessLogPdfResultDTO { + + /** + * 转换状态 + * INIT("初始"), + *

+ * CONVERTING("转换中"), + *

+ * SUCCESS("转换完成"), + *

+ * FAILED("转换失败"); + */ + private String status; + + /** + * 转换成功后的oss fileKey + */ + private String pdfFileKey; +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 79fa12596..45fb9be8c 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -1,10 +1,13 @@ package cn.axzo.workflow.server.controller.web.manage; +import cn.axzo.basics.common.BeanMapper; import cn.axzo.maokai.api.client.OrganizationalNodeUserQueryApi; import cn.axzo.maokai.api.vo.request.OrgNodeUserBriefInfoListReq; import cn.axzo.maokai.api.vo.response.OrgNodeUserBriefInfoResp; import cn.axzo.nanopart.doc.api.conversion.DocConversionApi; +import cn.axzo.nanopart.doc.api.conversion.req.QueryConversionTaskRequestV2; import cn.axzo.nanopart.doc.api.conversion.req.SubmitConversionTaskRequest; +import cn.axzo.nanopart.doc.api.conversion.res.FileConvertResultResp; import cn.axzo.nanopart.doc.api.enums.DocConversionTypeEnum; import cn.axzo.oss.http.api.ServerFileServiceApi; import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest; @@ -21,6 +24,7 @@ import cn.axzo.workflow.common.model.request.bpmn.print.Print4ProcessLogDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintFieldQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintProcessLogPdfDTO; import cn.axzo.workflow.common.model.request.bpmn.print.PrintTemplateConfigUpsertDTO; +import cn.axzo.workflow.common.model.request.bpmn.print.QueryProcessLogPdfDTO; import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; @@ -31,6 +35,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessDefinition import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO; import cn.axzo.workflow.common.model.response.bpmn.process.PrintData4LogVO; import cn.axzo.workflow.common.model.response.category.CategoryGroupVarItemVo; +import cn.axzo.workflow.common.model.response.print.ProcessLogPdfResultDTO; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.conf.SupportRefreshProperties; import cn.axzo.workflow.core.engine.cmd.CustomGetFormInstanceLatestValuesCmd; @@ -227,11 +232,11 @@ public class PrintAdminController implements PrintAdminApi { printFields.addAll(formContainer.getFields().get(0).stream() .filter(field -> { // if (Objects.equals(Boolean.TRUE, dto.getFilterEnablePrint())) { - if (!CollectionUtils.isEmpty(field.getParams())) { - Optional optEnablePrint = Optional.ofNullable(field.getParam("enablePrint")); - return optEnablePrint.map(obj -> Boolean.parseBoolean(obj.toString())).orElse(Boolean.TRUE); - } - return true; + if (!CollectionUtils.isEmpty(field.getParams())) { + Optional optEnablePrint = Optional.ofNullable(field.getParam("enablePrint")); + return optEnablePrint.map(obj -> Boolean.parseBoolean(obj.toString())).orElse(Boolean.TRUE); + } + return true; // } else { // return false; // } @@ -596,4 +601,19 @@ public class PrintAdminController implements PrintAdminApi { String taskId = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.submitConvertTask(request), "创建网页转 PDF 的异步任务", request); return CommonResponse.success(taskId); } + + @Operation(summary = "后端查询指定审批日志 PDF 文件的生成结果") + @PostMapping("/process/log/pdf/result") + @Override + public CommonResponse queryProcessLogPdfResult(@Validated @RequestBody QueryProcessLogPdfDTO dto) { + QueryConversionTaskRequestV2 request = new QueryConversionTaskRequestV2(); + request.setBizCode("workflow-process-log"); + request.setBizKey(dto.getProcessInstanceId()); + List taskConvertResults = RpcExternalUtil.rpcApiResultProcessor(() -> docConversionApi.queryConvertResultByBiz(request), "查询流程日志转 PDF 的结果", request); + List results = BeanMapper.copyList(taskConvertResults, ProcessLogPdfResultDTO.class, (s, t) -> { + t.setPdfFileKey(s.getResultFileFileKey()); + t.setStatus(s.getStatus().name()); + }); + return CommonResponse.success(results.isEmpty() ? null : results.get(0)); + } } From 9b2d95cdde6f51c4ba6b379a01e40ea294324d88 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 10 Nov 2025 11:43:07 +0800 Subject: [PATCH 54/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=BC=95=E6=93=8E=E6=B5=8B=E5=A2=9E=E5=8A=A0=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=97=A5=E5=BF=97pdf=20=E7=BB=93=E6=9E=9C=E6=9F=A5=E8=AF=A2=20?= =?UTF-8?q?API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflow/common/model/response/ProcessLogItemDTO.java | 7 +++++++ .../server/controller/web/manage/PrintAdminController.java | 1 + 2 files changed, 8 insertions(+) diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java index 0e8b5e9b4..5e2a02ea8 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/ProcessLogItemDTO.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.common.model.response; +import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -61,4 +62,10 @@ public class ProcessLogItemDTO { */ @ApiModelProperty(value = "操作时间") private String operationTime; + + /** + * 日志项结果,对应{@link BpmnProcessInstanceResultEnum#name()} + */ + @ApiModelProperty(value = "日志项结果") + private String result; } diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java index 45fb9be8c..3d67bd9c3 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/PrintAdminController.java @@ -559,6 +559,7 @@ public class PrintAdminController implements PrintAdminApi { .fileList(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.file)) .signatureUrl(getAttachmentByType(attachmentByTaskMap, log.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl()) .operationTime(DateUtil.format(log.getEndTime(), "yyyy.MM.dd HH:mm:ss")) + .result(log.getStatus()) .build()); }); parseSignatureUrl(logItems); From 62aec2b9ee9db6190cbda5ed31ce6dacfbabd7b1 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 10 Nov 2025 15:17:30 +0800 Subject: [PATCH 55/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=B2=A1=E6=9C=89=E4=BC=A0=E5=85=A5=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=96=87=E6=A1=A3=E6=97=B6=E7=9A=84NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...opyTemplateFileTaskEvent_105_Listener.java | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index 354352415..eff5133be 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -104,50 +104,51 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); List customDocs = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class); - if (CollectionUtils.isEmpty(docs) && CollectionUtils.isEmpty(customDocs)) { + if (CollectionUtils.isEmpty(docs)) { processSign.setDocTemplate(Collections.emptyList()); - processSign.setFileArchive(Collections.emptyList()); - } else { - // 复制基础模板 - List docTemplates = copyTempTemplate(docs); - - List customDocTemplates = new ArrayList<>(); - for (CustomDocDTO customDoc : customDocs) { - customDocTemplates.add(SignFileDTO.builder() - .id(customDoc.getId()) - .fileName(customDoc.getFileName()) - .templateName(customDoc.getFileName()) - .fileTag(customDoc.getFileTag()) - .fileCode(customDoc.getFileCode()) - .fileKey(customDoc.getFileKey()) - .fileType(customDoc.getFileType()) - .build()); - } - List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); - if (Objects.nonNull(basedFileTagOrder)) { - docTemplates.addAll(customDocTemplates); - // 基于 fileTag 排序 - Map fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size()) - .boxed() - .collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a)); - - docTemplates.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))); - docTemplates = docTemplates.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))) - .collect(Collectors.toList()); - } else { - // 基于前插还是后插排序 - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); - if (Objects.equals("last", customAddType)) { - docTemplates.addAll(customDocTemplates); - } else { - docTemplates.addAll(0, customDocTemplates); - } - } - processSign.setDocTemplate(docTemplates); - - List archives = replaceTemplateVariable(docTemplates, processEngineConfiguration, processInstanceId); - processSign.setFileArchive(archives); } + if (CollectionUtils.isEmpty(customDocs)) { + processSign.setFileArchive(Collections.emptyList()); + } + // 复制基础模板 + List docTemplates = copyTempTemplate(docs); + + List customDocTemplates = new ArrayList<>(); + for (CustomDocDTO customDoc : customDocs) { + customDocTemplates.add(SignFileDTO.builder() + .id(customDoc.getId()) + .fileName(customDoc.getFileName()) + .templateName(customDoc.getFileName()) + .fileTag(customDoc.getFileTag()) + .fileCode(customDoc.getFileCode()) + .fileKey(customDoc.getFileKey()) + .fileType(customDoc.getFileType()) + .build()); + } + List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); + if (Objects.nonNull(basedFileTagOrder)) { + docTemplates.addAll(customDocTemplates); + // 基于 fileTag 排序 + Map fileTagOrderMap = IntStream.range(0, basedFileTagOrder.size()) + .boxed() + .collect(Collectors.toMap(basedFileTagOrder::get, i -> i, (a, b) -> a)); + + docTemplates.sort(Comparator.comparing(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))); + docTemplates = docTemplates.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getFileTag(), Integer.MAX_VALUE))) + .collect(Collectors.toList()); + } else { + // 基于前插还是后插排序 + String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); + if (Objects.equals("last", customAddType)) { + docTemplates.addAll(customDocTemplates); + } else { + docTemplates.addAll(0, customDocTemplates); + } + } + processSign.setDocTemplate(docTemplates); + + List archives = replaceTemplateVariable(docTemplates, processEngineConfiguration, processInstanceId); + processSign.setFileArchive(archives); // 没有可用的文档,但仍然记录库表 extAxProcessSignService.save(processSign); } From 91e81a9a785dd7b9d1c103202b130ddd8f697a93 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 10 Nov 2025 15:27:38 +0800 Subject: [PATCH 56/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=B2=A1=E6=9C=89=E4=BC=A0=E5=85=A5=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=96=87=E6=A1=A3=E6=97=B6=E7=9A=84NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/FirstCopyTemplateFileTaskEvent_105_Listener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index eff5133be..c3b92d006 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -22,6 +22,7 @@ import cn.axzo.workflow.core.service.ExtAxReModelService; import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.axzo.workflow.server.common.util.WpsUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.interceptor.CommandExecutor; import org.flowable.engine.RuntimeService; @@ -102,7 +103,7 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve // 业务自定义文档 RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - List customDocs = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class); + List customDocs = ListUtils.emptyIfNull(runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)); if (CollectionUtils.isEmpty(docs)) { processSign.setDocTemplate(Collections.emptyList()); From 127a692b7ae387b03527fbfab96e07390efe6420 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 10 Nov 2025 15:28:45 +0800 Subject: [PATCH 57/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=B2=A1=E6=9C=89=E4=BC=A0=E5=85=A5=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=96=87=E6=A1=A3=E6=97=B6=E7=9A=84NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/FirstCopyTemplateFileTaskEvent_105_Listener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java index c3b92d006..fd0034a60 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/FirstCopyTemplateFileTaskEvent_105_Listener.java @@ -22,7 +22,6 @@ import cn.axzo.workflow.core.service.ExtAxReModelService; import cn.axzo.workflow.server.common.util.RpcExternalUtil; import cn.axzo.workflow.server.common.util.WpsUtil; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.ListUtils; import org.flowable.bpmn.model.Process; import org.flowable.common.engine.impl.interceptor.CommandExecutor; import org.flowable.engine.RuntimeService; @@ -103,7 +102,9 @@ public class FirstCopyTemplateFileTaskEvent_105_Listener extends AbstractBpmnEve // 业务自定义文档 RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); - List customDocs = ListUtils.emptyIfNull(runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)); + List customDocs = Optional.ofNullable( + runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) + .orElse(Collections.emptyList()); if (CollectionUtils.isEmpty(docs)) { processSign.setDocTemplate(Collections.emptyList()); From f4f97fdbf367efa00df9d66149f119df57699016 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Mon, 10 Nov 2025 16:46:16 +0800 Subject: [PATCH 58/58] =?UTF-8?q?feat(REQ-5965)=20-=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=B5=81=E7=A8=8B=E6=96=87=E6=A1=A3=20api=20?= =?UTF-8?q?=E5=86=85=E9=83=A8=E8=BF=9B=E6=94=AF=E6=8C=81=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/BpmnProcessInstanceServiceImpl.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 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 62c62f7b9..456fdaba9 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 @@ -1922,8 +1922,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic } else { tenantId = docs.get(0).getTenantId(); } - List bizCustomDocs = Optional.ofNullable( - runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOCS, List.class)) + HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId) + .variableName(SIGN_BIZ_CUSTOM_DOCS).singleResult(); + List bizCustomDocs = Optional.ofNullable((List) historicVariableInstance.getValue()) .orElse(Collections.emptyList()); // 业务自定义文档 @@ -1936,7 +1937,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic t.setFileRelationId(s.getFileKey()); }); - List basedFileTagOrder = runtimeService.getVariable(processInstanceId, SIGN_BIZ_BASED_FILE_TAG_ORDER, List.class); + HistoricVariableInstance signBizOrder = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(SIGN_BIZ_BASED_FILE_TAG_ORDER).singleResult(); + List basedFileTagOrder = Optional.ofNullable((List) signBizOrder.getValue()).orElse(Collections.emptyList()); if (!CollectionUtils.isEmpty(basedFileTagOrder)) { docs.addAll(customBizDocs); // 基于 fileTag 排序 @@ -1948,7 +1950,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic docs = docs.stream().sorted(Comparator.comparingInt(d -> fileTagOrderMap.getOrDefault(d.getTag(), Integer.MAX_VALUE))) .collect(Collectors.toList()); } else { - String customAddType = runtimeService.getVariable(processInstanceId, SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE, String.class); + HistoricVariableInstance bizDocOrderType = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(SIGN_BIZ_CUSTOM_DOC_ADD_ORDER_TYPE).singleResult(); + String customAddType = String.valueOf(bizDocOrderType.getValue()); if ("last".equals(customAddType)) { docs.addAll(customBizDocs); } else {