From e5c8be2b053e062fdb884505ad1eac27e358a7ae Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Fri, 7 Mar 2025 22:53:35 +0800 Subject: [PATCH 1/9] =?UTF-8?q?review:=20=E4=BC=98=E5=8C=96TODO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 7a8e5a2f5a..713b28945c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -221,8 +221,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService processDefinitionInfo, processVariables, activities); // 3.3 如果是发起动作,activityId 为开始节点,不校验审批人自选节点 - // TODO @小北:ObjUtil.equals(reqVO.getActivityId(), BpmnModelConstants.START_USER_NODE_ID) 够啦,不用判空 - if (ObjUtil.isNotNull(reqVO.getActivityId()) && ObjUtil.equals(reqVO.getActivityId(), BpmnModelConstants.START_USER_NODE_ID)) { + if (ObjUtil.equals(reqVO.getActivityId(), BpmnModelConstants.START_USER_NODE_ID)) { simulateActivityNodes.removeIf(node -> BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy().equals(node.getCandidateStrategy())); } From 4054e5fdec80231d955290e16c8f73d0c4071af2 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Sun, 9 Mar 2025 22:28:13 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=20=E5=8F=91=E8=B5=B7=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E6=8A=A5=E9=94=99=EF=BC=8C=E8=BF=94=E5=9B=9E=E7=9A=84VO?= =?UTF-8?q?=E7=BC=BA=E5=B0=91=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/definition/vo/model/BpmModelMetaInfoVO.java | 6 ++++++ .../vo/process/BpmProcessDefinitionRespVO.java | 9 ++------- .../convert/definition/BpmProcessDefinitionConvert.java | 4 ++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java index e00b6d4d3b..a54a5ac716 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java @@ -44,6 +44,12 @@ public class BpmModelMetaInfoVO { private Integer formType; @Schema(description = "表单编号", example = "1024") private Long formId; // formType 为 NORMAL 使用,必须非空 + @Schema(description = "表单名字", example = "请假表单") + private String formName; + @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) + private String formConf; + @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) + private List formFields; @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create") private String formCustomCreatePath; // 表单类型为 CUSTOM 时,必须非空 @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index 8da290440e..71709f7fe8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; +import java.util.List; @Schema(description = "管理后台 - 流程定义 Response VO") @Data @@ -19,7 +20,7 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; - @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "easy-build") private String key; @Schema(description = "流程分类", example = "1") @@ -27,15 +28,9 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { @Schema(description = "流程分类名字", example = "请假") private String categoryName; - @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") - private String modelId; - @Schema(description = "流程模型的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private Integer modelType; // 参见 BpmModelTypeEnum 枚举类 - @Schema(description = "表单名字", example = "请假表单") - private String formName; - @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer suspensionState; // 参见 SuspensionState 枚举 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index 1ef8b6f058..d1a5e5a74f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -74,6 +74,10 @@ public interface BpmProcessDefinitionConvert { if (deployment != null) { respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime())); } + // 图标为null时,处理成空字符串,否则copyTo的to.setIcon( from.getIcon() );会报错 + if (respVO.getIcon() == null) { + respVO.setIcon(""); + } // BpmProcessDefinitionInfoDO if (processDefinitionInfo != null) { copyTo(processDefinitionInfo, respVO); From b6a9b5dda9f518b2cdc180759157b0562cb564a4 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Tue, 11 Mar 2025 10:22:21 +0800 Subject: [PATCH 3/9] =?UTF-8?q?fix:=20=E6=A0=A1=E9=AA=8C=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E7=94=A8=E6=88=B7=E4=BB=BB=E5=8A=A1=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E8=A7=84=E5=88=99=E7=B1=BB=E5=9E=8B=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E4=B8=BA=E2=80=9C=E5=AE=A1=E6=89=B9=E4=BA=BA=E8=87=AA=E9=80=89?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmModelServiceImpl.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 922013ddba..c7df92a27f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -40,6 +40,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -243,24 +244,19 @@ public class BpmModelServiceImpl implements BpmModelService { if (startEvent == null) { throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS); } - // 2. 校验第一个用户任务的规则类型是否为“审批人自选”,如果是则抛出异常。原因是,流程发起后,直接进入第一个用户任务,会出现无审批人的情况 - List outgoingFlows = startEvent.getOutgoingFlows(); - // TODO @小北:可能极端情况下,startEvent 后面接了个 serviceTask,接着才是 userTask。。。 - // TODO @小北:simple 因为第一个任务是发起人,可能要找第二个任务??? - if (CollUtil.isNotEmpty(outgoingFlows)) { - FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); - Integer candidateStrategy = parseCandidateStrategy(targetFlowElement); - if (Objects.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) { - throw exception(MODEL_DEPLOY_FAIL_FIRST_USER_TASK_CANDIDATE_STRATEGY_ERROR, targetFlowElement.getName()); - } - } - // 3. 校验 UserTask 的 name 都配置了 + // 2. 校验 UserTask 的 name 都配置了 List userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); userTasks.forEach(userTask -> { if (StrUtil.isEmpty(userTask.getName())) { throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); } }); + // 3. 校验第一个用户任务节点的规则类型是否为“审批人自选” + UserTask userTask = userTasks.get(0); + Integer candidateStrategy = parseCandidateStrategy(userTask); + if (Objects.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) { + throw exception(MODEL_DEPLOY_FAIL_FIRST_USER_TASK_CANDIDATE_STRATEGY_ERROR, userTask.getName()); + } } @Override From 26dd8b66702230129ba48a6d87bcda399c06a974 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Tue, 11 Mar 2025 17:11:41 +0800 Subject: [PATCH 4/9] =?UTF-8?q?fix=EF=BC=9A=E8=8E=B7=E5=8F=96=E4=B8=8B?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E8=8A=82=E7=82=B9=E5=AE=A1=E6=89=B9=E4=BA=BA?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E6=97=B6=EF=BC=8C=E8=BF=94=E5=9B=9Enew=20Has?= =?UTF-8?q?hMap<>()=EF=BC=8C=E9=81=BF=E5=85=8D=E4=B8=8B=E7=BA=A7=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=A9=BA=E6=8C=87=E9=92=88=20review:=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AE=A1=E6=89=B9=E6=97=B6=EF=BC=8C=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=9A=84=E4=B8=8B=E4=B8=80=E4=B8=AA=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=9A=84=E5=AE=A1=E6=89=B9=E4=BA=BA=EF=BC=8C=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=90=88=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/util/FlowableUtils.java | 6 +- .../bpm/service/task/BpmTaskServiceImpl.java | 65 +++++++++---------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index fe83495e35..4178638b5a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -194,7 +194,7 @@ public class FlowableUtils { @SuppressWarnings("unchecked") public static Map> getStartUserSelectAssignees(Map processVariables) { if (processVariables == null) { - return null; + return new HashMap<>(); } return (Map>) processVariables.get( BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); @@ -214,12 +214,12 @@ public class FlowableUtils { * 获得流程实例的审批用户选择的下一个节点的审批人 Map * * @param processVariables 流程变量 - * @return 审批用户选择的下一个节点的审批人Map Map + * @return 审批用户选择的下一个节点的审批人Map */ @SuppressWarnings("unchecked") public static Map> getApproveUserSelectAssignees(Map processVariables) { if (processVariables == null) { - return null; + return new HashMap<>(); } return (Map>) processVariables.get( BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index e26b58e793..09eea1e52c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -558,18 +558,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 2.3 调用 BPM complete 去完成任务 - // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 - if (CollUtil.isNotEmpty(reqVO.getVariables())) { - // 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 - Map variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), - bpmnModel, reqVO.getNextAssignees(), instance); - // 完成任务 - runtimeService.setVariables(task.getProcessInstanceId(), variables); - taskService.complete(task.getId(), variables, true); - } else { - // 完成任务 - taskService.complete(task.getId()); - } + // 校验并处理 APPROVE_USER_SELECT 当前审批人,选择下一节点审批人的逻辑 + Map variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), + bpmnModel, reqVO.getNextAssignees(), instance); + // 完成任务 + runtimeService.setVariables(task.getProcessInstanceId(), variables); + taskService.complete(task.getId(), variables, true); // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); @@ -590,51 +584,50 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private Map validateAndSetNextAssignees(String taskDefinitionKey, Map variables, BpmnModel bpmnModel, Map> nextAssignees, ProcessInstance processInstance) { - // 下一个节点参数为空,不做处理,表示流程正常流转,无需选择下一个节点的审判人 - // TODO @小北:会出现漏选,其实需要的情况哇? - if (CollUtil.isEmpty(nextAssignees)) { - return variables; - } // 1. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); - // 2. 循环下一个将要执行的节点集合 - Map> processVariables = new HashMap<>(); + Map> processVariables; for (FlowNode nextFlowNode : nextFlowNodes) { - if (!nextAssignees.containsKey(nextFlowNode.getId())) { - throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); - } - List assignees = nextAssignees.get(nextFlowNode.getId()); - // 2.1 情况一:如果节点中的审批人策略为 发起人自选 + // 获取任务节点中的审批人策略 Integer candidateStrategy = parseCandidateStrategy(nextFlowNode); + // 2.1 情况一:如果节点中的审批人策略为 发起人自选 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) { - processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); - if (processVariables == null) { - processVariables = new HashMap<>(); - } - List startUserSelectAssignee = processVariables.get(nextFlowNode.getId()); - // 特殊:如果当前节点已经存在审批人,则不允许覆盖 - if (CollUtil.isNotEmpty(startUserSelectAssignee)) { - continue; - } // 如果节点存在,但未配置审批人 + List assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } + processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); + if (CollUtil.isNotEmpty(processVariables)) { + List startUserSelectAssignee = processVariables.get(nextFlowNode.getId()); + // 特殊:如果当前节点已经存在审批人,则不允许覆盖 + if (CollUtil.isNotEmpty(startUserSelectAssignee)) { + continue; + } + } // 校验通过的全部节点和审批人 - processVariables.put(nextFlowNode.getId(), assignees); + processVariables.put(nextFlowNode.getId(), nextAssignees.get(nextFlowNode.getId())); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables); } // 2.2 情况二:如果节点中的审批人策略为 审批人,在审批时选择下一个节点的审批人,并且该节点的审批人为空 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) { // 如果节点存在,但未配置审批人 + List assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } + processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); + if (CollUtil.isNotEmpty(processVariables)) { + List approveUserSelectAssignee = processVariables.get(nextFlowNode.getId()); + // 特殊:如果当前节点已经存在审批人,则不允许覆盖 + if (CollUtil.isNotEmpty(approveUserSelectAssignee)) { + continue; + } + } // 校验通过的全部节点和审批人 - processVariables.put(nextFlowNode.getId(), assignees); - // TODO @小北:是不是要类似情况一的做法,通过 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES 拿一下?因为如果 task1 是审批人自选,task2 是审批人自选,看着会覆盖? + processVariables.put(nextFlowNode.getId(), nextAssignees.get(nextFlowNode.getId())); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables); } } From 494b80d1ebae4099d719f671a4cdfe91313f5f16 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Tue, 11 Mar 2025 17:34:13 +0800 Subject: [PATCH 5/9] =?UTF-8?q?review:=20=E4=BC=98=E5=8C=96=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E6=97=B6=EF=BC=8C=E6=A0=A1=E9=AA=8C=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E7=9A=84=E4=B8=8B=E4=B8=80=E4=B8=AA=E8=8A=82=E7=82=B9=E7=9A=84?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BA=BA=EF=BC=8C=E6=98=AF=E5=90=A6=E5=90=88?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/util/BpmnModelUtils.java | 13 ++++++++++--- .../framework/flowable/core/util/FlowableUtils.java | 6 +++--- .../module/bpm/service/task/BpmTaskServiceImpl.java | 8 ++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index af5b0852f6..c471826306 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -907,9 +907,16 @@ public class BpmnModelUtils { * @return 符合条件的路径 */ private static SequenceFlow findMatchSequenceFlowByExclusiveGateway(Gateway gateway, Map variables) { - SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), - flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) - && (evalConditionExpress(variables, flow.getConditionExpression()))); + // TODO 表单无可编辑字段时variables为空,流程走向会出现问题,比如流程审批过程中无需要修改的字段值, + SequenceFlow matchSequenceFlow; + if (CollUtil.isNotEmpty(variables)){ + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) + && (evalConditionExpress(variables, flow.getConditionExpression()))); + }else { + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())); + } if (matchSequenceFlow == null) { matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index 4178638b5a..fe83495e35 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -194,7 +194,7 @@ public class FlowableUtils { @SuppressWarnings("unchecked") public static Map> getStartUserSelectAssignees(Map processVariables) { if (processVariables == null) { - return new HashMap<>(); + return null; } return (Map>) processVariables.get( BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); @@ -214,12 +214,12 @@ public class FlowableUtils { * 获得流程实例的审批用户选择的下一个节点的审批人 Map * * @param processVariables 流程变量 - * @return 审批用户选择的下一个节点的审批人Map + * @return 审批用户选择的下一个节点的审批人Map Map */ @SuppressWarnings("unchecked") public static Map> getApproveUserSelectAssignees(Map processVariables) { if (processVariables == null) { - return new HashMap<>(); + return null; } return (Map>) processVariables.get( BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 09eea1e52c..0bfd6b0c6c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -600,7 +600,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); - if (CollUtil.isNotEmpty(processVariables)) { + if (processVariables == null){ + processVariables = new HashMap<>(); + }else { List startUserSelectAssignee = processVariables.get(nextFlowNode.getId()); // 特殊:如果当前节点已经存在审批人,则不允许覆盖 if (CollUtil.isNotEmpty(startUserSelectAssignee)) { @@ -619,7 +621,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); - if (CollUtil.isNotEmpty(processVariables)) { + if (processVariables == null){ + processVariables = new HashMap<>(); + }else { List approveUserSelectAssignee = processVariables.get(nextFlowNode.getId()); // 特殊:如果当前节点已经存在审批人,则不允许覆盖 if (CollUtil.isNotEmpty(approveUserSelectAssignee)) { From 27ae2a4761739a21feca8bad24544fadeff9d227 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Tue, 11 Mar 2025 21:23:19 +0800 Subject: [PATCH 6/9] =?UTF-8?q?review:=20=E7=88=B6=E5=AD=90=E7=B1=BB?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/definition/vo/model/BpmModelMetaInfoVO.java | 3 +-- .../admin/definition/vo/model/BpmModelSaveReqVO.java | 3 +++ .../definition/vo/process/BpmProcessDefinitionRespVO.java | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java index a54a5ac716..97a8a3ca7b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java @@ -44,8 +44,7 @@ public class BpmModelMetaInfoVO { private Integer formType; @Schema(description = "表单编号", example = "1024") private Long formId; // formType 为 NORMAL 使用,必须非空 - @Schema(description = "表单名字", example = "请假表单") - private String formName; + @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) private String formConf; @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java index 7e32596524..bcb193df1e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java @@ -21,6 +21,9 @@ public class BpmModelSaveReqVO extends BpmModelMetaInfoVO { @NotEmpty(message = "流程名称不能为空") private String name; + @Schema(description = "表单名字", example = "请假表单") + private String formName; + @Schema(description = "流程分类", example = "1") private String category; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index 71709f7fe8..81bddf7b11 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -20,7 +20,10 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; - @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "easy-build") + @Schema(description = "表单名字", example = "请假表单") + private String formName; + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "youdao") private String key; @Schema(description = "流程分类", example = "1") @@ -31,6 +34,9 @@ public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { @Schema(description = "流程模型的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private Integer modelType; // 参见 BpmModelTypeEnum 枚举类 + @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") + private String modelId; + @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer suspensionState; // 参见 SuspensionState 枚举 From 2123d7c06717113a83aaf9fccf70b71559f8ad0a Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Tue, 11 Mar 2025 21:28:29 +0800 Subject: [PATCH 7/9] =?UTF-8?q?remove:=20=E5=88=A0=E9=99=A4=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/convert/definition/BpmProcessDefinitionConvert.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index d1a5e5a74f..1ef8b6f058 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -74,10 +74,6 @@ public interface BpmProcessDefinitionConvert { if (deployment != null) { respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime())); } - // 图标为null时,处理成空字符串,否则copyTo的to.setIcon( from.getIcon() );会报错 - if (respVO.getIcon() == null) { - respVO.setIcon(""); - } // BpmProcessDefinitionInfoDO if (processDefinitionInfo != null) { copyTo(processDefinitionInfo, respVO); From cc61bb1a61e837ac62dee76045d3cd77ed4f303b Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Tue, 11 Mar 2025 22:37:23 +0800 Subject: [PATCH 8/9] =?UTF-8?q?review=EF=BC=9A=20=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E8=AE=BE=E8=AE=A1=E5=99=A8=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E7=94=A8=E6=88=B7=E4=BB=BB=E5=8A=A1=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E8=A7=84=E5=88=99=E7=B1=BB=E5=9E=8B=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E4=B8=BA=E2=80=9C=E5=AE=A1=E6=89=B9=E4=BA=BA=E8=87=AA=E9=80=89?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmModelServiceImpl.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index c7df92a27f..7a737d953a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -40,10 +40,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @@ -210,11 +207,11 @@ public class BpmModelServiceImpl implements BpmModelService { public void deployModel(Long userId, String id) { // 1.1 校验流程模型存在 Model model = validateModelManager(id, userId); + BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); // 1.2 校验流程图 byte[] bpmnBytes = getModelBpmnXML(model.getId()); - validateBpmnXml(bpmnBytes); + validateBpmnXml(bpmnBytes, metaInfo.getType()); // 1.3 校验表单已配 - BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); BpmFormDO form = validateFormConfig(metaInfo); // 1.4 校验任务分配规则已配置 taskCandidateInvoker.validateBpmnConfig(bpmnBytes); @@ -234,7 +231,7 @@ public class BpmModelServiceImpl implements BpmModelService { repositoryService.saveModel(model); } - private void validateBpmnXml(byte[] bpmnBytes) { + private void validateBpmnXml(byte[] bpmnBytes, int type) { BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); if (bpmnModel == null) { throw exception(MODEL_NOT_EXISTS); @@ -252,10 +249,14 @@ public class BpmModelServiceImpl implements BpmModelService { } }); // 3. 校验第一个用户任务节点的规则类型是否为“审批人自选” - UserTask userTask = userTasks.get(0); - Integer candidateStrategy = parseCandidateStrategy(userTask); + Map userTaskMap = new HashMap<>(); + // BPMN 设计器,校验第一个用户任务节点 + userTaskMap.put(BpmModelTypeEnum.BPMN.getType(), userTasks.get(0)); + // SIMPLE 设计器,第一个节点固定为发起人所以校验第二个用户任务节点 + userTaskMap.put(BpmModelTypeEnum.SIMPLE.getType(), userTasks.get(1)); + Integer candidateStrategy = parseCandidateStrategy(userTaskMap.get(type)); if (Objects.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) { - throw exception(MODEL_DEPLOY_FAIL_FIRST_USER_TASK_CANDIDATE_STRATEGY_ERROR, userTask.getName()); + throw exception(MODEL_DEPLOY_FAIL_FIRST_USER_TASK_CANDIDATE_STRATEGY_ERROR, userTaskMap.get(type).getName()); } } From 42eb89b2433b8197602fb5441078d50c40fbc44d Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Tue, 11 Mar 2025 22:40:53 +0800 Subject: [PATCH 9/9] =?UTF-8?q?review=EF=BC=9A=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E6=A0=A1=E9=AA=8C=E9=80=89=E6=8B=A9=E7=9A=84?= =?UTF-8?q?=E4=B8=8B=E4=B8=80=E4=B8=AA=E8=8A=82=E7=82=B9=E7=9A=84=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E4=BA=BA=EF=BC=8C=E6=98=AF=E5=90=A6=E5=90=88=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 0bfd6b0c6c..eab70f921b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -610,7 +610,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } } // 校验通过的全部节点和审批人 - processVariables.put(nextFlowNode.getId(), nextAssignees.get(nextFlowNode.getId())); + processVariables.put(nextFlowNode.getId(), assignees); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables); } // 2.2 情况二:如果节点中的审批人策略为 审批人,在审批时选择下一个节点的审批人,并且该节点的审批人为空 @@ -631,7 +631,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } } // 校验通过的全部节点和审批人 - processVariables.put(nextFlowNode.getId(), nextAssignees.get(nextFlowNode.getId())); + processVariables.put(nextFlowNode.getId(), assignees); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables); } }