From f45758b8fdac813c0e7b26ab798ab610be2d9374 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Sun, 23 Feb 2025 20:12:05 +0800 Subject: [PATCH 01/21] =?UTF-8?q?feat:=20=E5=AE=A1=E6=89=B9=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E8=87=AA=E9=80=89=E5=AE=A1=E6=89=B9=E4=BA=BA=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 e284e42706..1976e13a8b 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 @@ -173,7 +173,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); - processVariables = historicProcessInstance.getProcessVariables(); + // 如果流程变量为空,则使用历史流程变量 + if (null == processVariables) { + processVariables = historicProcessInstance.getProcessVariables(); + } } // 1.3 读取其它相关数据 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( From 5d163550424d40d0025293a9d8bc78f11b675a7c Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Mon, 24 Feb 2025 16:31:03 +0800 Subject: [PATCH 02/21] =?UTF-8?q?fix=EF=BC=9A=201=E3=80=81=E9=A2=84?= =?UTF-8?q?=E6=B5=8B=E8=8A=82=E7=82=B9=E5=AE=A1=E6=89=B9=E4=BA=BA=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=EF=BC=8C=E5=A6=82=E6=9E=9C=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=EF=BC=8C=E5=88=99=E7=9B=B4=E6=8E=A5=E8=BF=94=E5=9B=9E=E7=A9=BA?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=202=E3=80=81=E5=A6=82=E6=9E=9CprocessVariabl?= =?UTF-8?q?es=E4=B8=8D=E4=B8=BA=E7=A9=BA=EF=BC=8C=E5=88=99=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=89=8D=E7=AB=AF=E4=BC=A0=E9=80=92=E7=9A=84=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BpmTaskCandidateStartUserSelectStrategy.java | 10 ++++++++-- .../task/BpmProcessInstanceServiceImpl.java | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java index 9fd14d6ded..d547643609 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java @@ -53,8 +53,11 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", execution.getProcessInstanceId()); - // 获得审批人 + // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); + if (CollUtil.isEmpty(assignees)){ + return null; + } return new LinkedHashSet<>(assignees); } @@ -68,8 +71,11 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand if (startUserSelectAssignees == null) { return Sets.newLinkedHashSet(); } - // 获得审批人 + // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 List assignees = startUserSelectAssignees.get(activityId); + if (CollUtil.isEmpty(assignees)){ + return null; + } return new LinkedHashSet<>(assignees); } 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 1976e13a8b..27884ae51e 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 @@ -173,10 +173,19 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); - // 如果流程变量为空,则使用历史流程变量 - if (null == processVariables) { - processVariables = historicProcessInstance.getProcessVariables(); + // 如果流程变量不为空,则用前端传递的新变量值覆盖历史的流程变量 + Map historicVariables = historicProcessInstance.getProcessVariables(); + if (null != processVariables) { + // 遍历新变量值,仅更新历史变量中存在的键 + for (Map.Entry entry : processVariables.entrySet()) { + String key = entry.getKey(); + if (historicVariables.containsKey(key)) { + // 如果历史变量中存在该键,则用新值覆盖 + historicVariables.put(key, entry.getValue()); + } + } } + processVariables = historicVariables; } // 1.3 读取其它相关数据 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( From 45a72f4cd857397c05da7a3136bb291e564a46b8 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Mon, 24 Feb 2025 17:15:17 +0800 Subject: [PATCH 03/21] =?UTF-8?q?fix=EF=BC=9A=E5=AE=A1=E6=89=B9=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=B7=BB=E5=8A=A0=E5=AE=A1=E6=89=B9=E4=BA=BA=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/task/vo/task/BpmTaskApproveReqVO.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index 40df86efc8..07078b8db3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import lombok.Data; +import java.util.List; import java.util.Map; @Schema(description = "管理后台 - 通过流程任务的 Request VO") @@ -23,4 +24,7 @@ public class BpmTaskApproveReqVO { @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) private Map variables; + @Schema(description = "节点审批人", example = "[1,2]") + private List assignees; + } From e11529375ef1e52c548597d12271c7ddb9fb9437 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Mon, 24 Feb 2025 22:56:18 +0800 Subject: [PATCH 04/21] =?UTF-8?q?feat:=20=E5=AE=A1=E6=89=B9=E6=97=B6?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E4=B8=8B=E4=B8=80=E4=B8=AA=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E7=B1=BB=E5=9E=8B=E6=98=AF=E5=90=A6=E4=B8=BA=E8=87=AA?= =?UTF-8?q?=E9=80=89=E5=AE=A1=E6=89=B9=E4=BA=BA=E6=98=AF=E5=90=A6=E5=B7=B2?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E4=BA=86=E5=AE=A1=E6=89=B9=E4=BA=BA=EF=BC=8C?= =?UTF-8?q?=E5=90=A6=E5=88=99=E7=94=B1=E5=89=8D=E7=AB=AF=E4=BC=A0=E9=80=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/task/vo/task/BpmTaskApproveReqVO.java | 4 ++-- .../dept/BpmTaskCandidateStartUserSelectStrategy.java | 4 ++-- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index 07078b8db3..b84cb44ca6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -24,7 +24,7 @@ public class BpmTaskApproveReqVO { @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) private Map variables; - @Schema(description = "节点审批人", example = "[1,2]") - private List assignees; + @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") + private Map> startUserSelectAssignees; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java index d547643609..07b051cadd 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java @@ -56,7 +56,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); if (CollUtil.isEmpty(assignees)){ - return null; + return Sets.newLinkedHashSet(); } return new LinkedHashSet<>(assignees); } @@ -74,7 +74,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 List assignees = startUserSelectAssignees.get(activityId); if (CollUtil.isEmpty(assignees)){ - return null; + return Sets.newLinkedHashSet(); } return new LinkedHashSet<>(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 76c7771035..f4d08b59d9 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 @@ -520,6 +520,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 修改表单的值需要存储到 ProcessInstance 变量 + if (CollUtil.isNotEmpty(reqVO.getStartUserSelectAssignees())) { + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, + reqVO.getStartUserSelectAssignees()); + } runtimeService.setVariables(task.getProcessInstanceId(), variables); taskService.complete(task.getId(), variables, true); } else { From f2909d6bb6bb1928bcc3d20f6e75a14844b61ef2 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Tue, 25 Feb 2025 16:27:05 +0800 Subject: [PATCH 05/21] =?UTF-8?q?feat=EF=BC=9A=E6=96=B0=E5=A2=9E=E8=87=AA?= =?UTF-8?q?=E9=80=89=E8=8A=82=E7=82=B9=E5=AE=A1=E6=89=B9=E4=BA=BA=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E7=94=B1=E5=89=8D=E7=AB=AF=E4=BC=A0=E9=80=92?= =?UTF-8?q?=E4=B8=8B=E4=B8=AA=E8=8A=82=E7=82=B9=E9=80=89=E6=8B=A9=E7=9A=84?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 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 f4d08b59d9..f2bd3ff993 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 @@ -519,10 +519,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); - // 修改表单的值需要存储到 ProcessInstance 变量 + // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getStartUserSelectAssignees())) { - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, - reqVO.getStartUserSelectAssignees()); + // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 + Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); + startUserSelectAssignees.putAll(reqVO.getStartUserSelectAssignees()); + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } runtimeService.setVariables(task.getProcessInstanceId(), variables); taskService.complete(task.getId(), variables, true); From b2ca263067661919b0eeec181058b228bfd45593 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Tue, 25 Feb 2025 16:29:35 +0800 Subject: [PATCH 06/21] =?UTF-8?q?feat=EF=BC=9A=E6=B7=BB=E5=8A=A0=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dept/BpmTaskCandidateStartUserSelectStrategy.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/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java index 07b051cadd..f4efa549e5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java @@ -53,7 +53,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", execution.getProcessInstanceId()); - // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 + // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); if (CollUtil.isEmpty(assignees)){ return Sets.newLinkedHashSet(); @@ -71,7 +71,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand if (startUserSelectAssignees == null) { return Sets.newLinkedHashSet(); } - // 获得审批人,如果不存在,则直接返回空,避免类型转换异常 + // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 List assignees = startUserSelectAssignees.get(activityId); if (CollUtil.isEmpty(assignees)){ return Sets.newLinkedHashSet(); From 37b2fd4789e50c646a3839fd31231d39d131eec4 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Wed, 26 Feb 2025 15:59:42 +0800 Subject: [PATCH 07/21] =?UTF-8?q?feat=EF=BC=9A=E8=B0=83=E6=95=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/task/vo/task/BpmTaskApproveReqVO.java | 4 ++-- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index b84cb44ca6..a0751c12e6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -24,7 +24,7 @@ public class BpmTaskApproveReqVO { @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) private Map variables; - @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") - private Map> startUserSelectAssignees; + @Schema(description = "下一个节点审批人", example = "{nodeId:[1, 2]}") + private Map> nextAssignees; } 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 f2bd3ff993..1866ed006f 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 @@ -520,11 +520,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 下个节点审批人如果不存在,则由前端传递 - if (CollUtil.isNotEmpty(reqVO.getStartUserSelectAssignees())) { + if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 - Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); - startUserSelectAssignees.putAll(reqVO.getStartUserSelectAssignees()); - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); + Map> hisProcessVariables = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); + hisProcessVariables.putAll(reqVO.getNextAssignees()); + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, hisProcessVariables); } runtimeService.setVariables(task.getProcessInstanceId(), variables); taskService.complete(task.getId(), variables, true); From 13c2d36eeea6455d65c4b1262fccfdf816e0558c Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Wed, 26 Feb 2025 17:45:35 +0800 Subject: [PATCH 08/21] =?UTF-8?q?feat=EF=BC=9A=E6=B7=BB=E5=8A=A0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=A1=E6=89=B9=E6=97=B6=E6=A0=A1=E9=AA=8C=EF=BC=8C?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E4=B8=8B=E4=B8=80=E4=B8=AA=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=A1=E6=89=B9=E7=9A=84=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 1 + .../task/BpmProcessInstanceServiceImpl.java | 9 +---- .../bpm/service/task/BpmTaskServiceImpl.java | 36 +++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index 7fbc7ba223..e089f33751 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -57,6 +57,7 @@ public interface ErrorCodeConstants { ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!"); ErrorCode TASK_REASON_REQUIRE = new ErrorCode(1_009_005_016, "审批意见不能为空!"); + ErrorCode TASK_START_USER_SELECT_NODE_NOT_EXISTS = new ErrorCode(1_009_004_007, "({})不是下一个执行的流程节点!"); // ========== 动态表单模块 1-009-010-000 ========== ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); 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 27884ae51e..3bd5c1098f 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 @@ -176,14 +176,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 如果流程变量不为空,则用前端传递的新变量值覆盖历史的流程变量 Map historicVariables = historicProcessInstance.getProcessVariables(); if (null != processVariables) { - // 遍历新变量值,仅更新历史变量中存在的键 - for (Map.Entry entry : processVariables.entrySet()) { - String key = entry.getKey(); - if (historicVariables.containsKey(key)) { - // 如果历史变量中存在该键,则用新值覆盖 - historicVariables.put(key, entry.getValue()); - } - } + historicVariables.putAll(processVariables); } processVariables = historicVariables; } 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 1866ed006f..44c04fb030 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 @@ -10,15 +10,19 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.*; import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; @@ -56,6 +60,7 @@ import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.*; +import java.util.stream.Collectors; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -519,6 +524,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); + // 校验传递的参数中是否存在不是下一个执行的节点 + checkNextActivityNodes(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 @@ -536,6 +543,35 @@ public class BpmTaskServiceImpl implements BpmTaskService { handleParentTaskIfSign(task.getParentTaskId()); } + /** + * 校验传递的参数中是否存在不是下一个执行的节点 + * + * @param loginUserId 流程发起人 + * @param processInstanceId 流程实例id + * @param nextActivityNodes 下一个执行节点信息 {节点id : [审批人id,审批人id]} + */ + private void checkNextActivityNodes(Long loginUserId, Map variables,String processInstanceId, + Map> nextActivityNodes){ + // 1、查询流程【预测】的全部信息 + BpmApprovalDetailRespVO approvalDetail = processInstanceService.getApprovalDetail(loginUserId, + new BpmApprovalDetailReqVO().setProcessVariables(variables).setProcessInstanceId(processInstanceId)); + // 2、获取预测节点的信息 + List activityNodes = approvalDetail.getActivityNodes(); + if (CollUtil.isNotEmpty(activityNodes)) { + // 2.1、获取节点中的审批人策略为【发起人自选】且状态为【未执行】的节点 + List notStartActivityNodes = activityNodes.stream().filter(node -> + BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy().equals(node.getCandidateStrategy()) + && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus())).toList(); + // 3、校验传递的参数中是否存在不是下一节点的信息 + for (Map.Entry> nextActivityNode : nextActivityNodes.entrySet()) { + if (notStartActivityNodes.stream().noneMatch(taskNode -> taskNode.getId().equals(nextActivityNode.getKey()))) { + log.error("[checkNextActivityNodes][ ({}) 不是下一个执行的流程节点!]", nextActivityNode.getKey()); + throw exception(TASK_START_USER_SELECT_NODE_NOT_EXISTS, nextActivityNode.getKey()); + } + } + } + } + /** * 审批通过存在“后加签”的任务。 *

From 357f4966d30418128ad6aa501bc96bdf45555e42 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Wed, 26 Feb 2025 22:38:31 +0800 Subject: [PATCH 09/21] =?UTF-8?q?review:=20=E4=BB=A3=E7=A0=81=E5=AE=A1?= =?UTF-8?q?=E6=9F=A5=20=E4=BF=AE=E6=94=B9=E6=96=B9=E6=B3=95=E5=90=8D?= =?UTF-8?q?=E7=A7=B0validateNextAssignees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 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 44c04fb030..df682c09f9 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 @@ -525,7 +525,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 校验传递的参数中是否存在不是下一个执行的节点 - checkNextActivityNodes(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); + validateNextAssignees(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 @@ -550,7 +550,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param processInstanceId 流程实例id * @param nextActivityNodes 下一个执行节点信息 {节点id : [审批人id,审批人id]} */ - private void checkNextActivityNodes(Long loginUserId, Map variables,String processInstanceId, + private void validateNextAssignees(Long loginUserId, Map variables,String processInstanceId, Map> nextActivityNodes){ // 1、查询流程【预测】的全部信息 BpmApprovalDetailRespVO approvalDetail = processInstanceService.getApprovalDetail(loginUserId, @@ -562,7 +562,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { List notStartActivityNodes = activityNodes.stream().filter(node -> BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy().equals(node.getCandidateStrategy()) && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus())).toList(); - // 3、校验传递的参数中是否存在不是下一节点的信息 + // 3、校验传递的参数中是否存在不是下一个节点的信息 for (Map.Entry> nextActivityNode : nextActivityNodes.entrySet()) { if (notStartActivityNodes.stream().noneMatch(taskNode -> taskNode.getId().equals(nextActivityNode.getKey()))) { log.error("[checkNextActivityNodes][ ({}) 不是下一个执行的流程节点!]", nextActivityNode.getKey()); From b03025746661e637454ed2a70c94e79e4641b9ae Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Wed, 26 Feb 2025 23:24:21 +0800 Subject: [PATCH 10/21] =?UTF-8?q?review:=20=E4=BB=A3=E7=A0=81=E5=AE=A1?= =?UTF-8?q?=E6=9F=A5=20=E4=BF=AE=E6=94=B9=E6=96=B9=E6=B3=95=E5=90=8D?= =?UTF-8?q?=E7=A7=B0validateNextAssignees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 df682c09f9..236efb4f48 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 @@ -561,7 +561,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.1、获取节点中的审批人策略为【发起人自选】且状态为【未执行】的节点 List notStartActivityNodes = activityNodes.stream().filter(node -> BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy().equals(node.getCandidateStrategy()) - && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus())).toList(); + && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus()) + && CollUtil.isEmpty(node.getCandidateUsers())).toList(); // 3、校验传递的参数中是否存在不是下一个节点的信息 for (Map.Entry> nextActivityNode : nextActivityNodes.entrySet()) { if (notStartActivityNodes.stream().noneMatch(taskNode -> taskNode.getId().equals(nextActivityNode.getKey()))) { From 074146c99133bcbdb5c72a7c8f39767db0d7a2fa Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 27 Feb 2025 09:56:34 +0800 Subject: [PATCH 11/21] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91BPM=EF=BC=9A=E8=A7=A6=E5=8F=91=E5=99=A8=20HTT?= =?UTF-8?q?P=20=E5=BC=82=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/definition/BpmTriggerTypeEnum.java | 5 +++-- .../bpm/framework/flowable/core/util/SimpleModelUtils.java | 4 +--- .../service/task/trigger/http/BpmHttpCallbackTrigger.java | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java index c1aaae3437..13f997c7b4 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java @@ -16,8 +16,9 @@ import java.util.Arrays; @AllArgsConstructor public enum BpmTriggerTypeEnum implements ArrayValuable { - HTTP_REQUEST(1, "发起 HTTP 请求"), - HTTP_CALLBACK(2, "发起 HTTP 回调"), + HTTP_REQUEST(1, "发起 HTTP 请求"), // BPM => 业务,流程继续执行,无需等待业务 + HTTP_CALLBACK(2, "接收 HTTP 回调"), // BPM => 业务 => BPM,流程卡主,等待业务回调 + FORM_UPDATE(10, "更新流程表单数据"), FORM_DELETE(11, "删除流程表单数据"), ; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index 6cff39f4f6..e0911240fc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -25,7 +25,6 @@ import org.springframework.util.MultiValueMap; import java.util.*; -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum.HTTP_CALLBACK; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; import static java.util.Arrays.asList; @@ -737,13 +736,12 @@ public class SimpleModelUtils { public static class TriggerNodeConvert implements NodeConvert { - // TODO @芋艿:【回调】在看看 @Override public List convertList(BpmSimpleModelNodeVO node) { Assert.notNull(node.getTriggerSetting(), "触发器节点设置不能为空"); List flowElements = new ArrayList<>(2); // HTTP 回调请求。需要附加一个 ReceiveTask、发起请求后、等待回调执行 - if (HTTP_CALLBACK.getType().equals(node.getTriggerSetting().getType())) { + if (BpmTriggerTypeEnum.HTTP_CALLBACK.getType().equals(node.getTriggerSetting().getType())) { Assert.notNull(node.getTriggerSetting().getHttpRequestSetting(), "触发器 HTTP 回调请求设置不能为空"); ReceiveTask receiveTask = new ReceiveTask(); receiveTask.setId("Activity_" + IdUtil.fastUUID()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java index f081ff82d3..867af70b9d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java @@ -42,8 +42,8 @@ public class BpmHttpCallbackTrigger extends BpmAbstractHttpRequestTrigger { MultiValueMap headers = buildHttpHeaders(processInstance, setting.getHeader()); // 2.2 设置请求体 MultiValueMap body = buildHttpBody(processInstance, setting.getBody()); - // TODO @芋艿:【回调】在看看 - body.add("callbackId", setting.getCallbackTaskDefineKey()); // 回调请求 callbackId 需要传给被调用方,用于回调执行 + // 重要:回调请求 taskDefineKey 需要传给被调用方,用于回调执行 + body.add("taskDefineKey", setting.getCallbackTaskDefineKey()); // 3. 发起请求 sendHttpRequest(setting.getUrl(), headers, body); From db6d7a74300da30b721b1e2cdaa7de78f2e810af Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Thu, 27 Feb 2025 15:17:30 +0800 Subject: [PATCH 12/21] =?UTF-8?q?feat=EF=BC=9A=E6=B7=BB=E5=8A=A0TODO?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/framework/flowable/core/util/BpmnModelUtils.java | 2 ++ 1 file changed, 2 insertions(+) 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 49ab5bb35b..b73e0cc98d 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 @@ -778,6 +778,8 @@ public class BpmnModelUtils { if (currentElement instanceof ExclusiveGateway) { // 查找满足条件的 SequenceFlow 路径 Gateway gateway = (Gateway) currentElement; + // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题,需要优化, + // TODO 具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) && (evalConditionExpress(variables, flow.getConditionExpression()))); From 6c6992c86a9f64b78e23c622a6f6204cd424e6ef Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Thu, 27 Feb 2025 17:28:22 +0800 Subject: [PATCH 13/21] =?UTF-8?q?feat=EF=BC=9ATODO=20List?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/service/task/BpmTaskServiceImpl.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) 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 236efb4f48..d64a822545 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 @@ -525,6 +525,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 校验传递的参数中是否存在不是下一个执行的节点 + // 当前执行的流程节点,需根据该节点寻找下一个节点 + String taskDefinitionKey = task.getTaskDefinitionKey(); + List nextFlowNodes = getNextFlowNodes(taskDefinitionKey, bpmnModel, variables); + System.out.println(nextFlowNodes); validateNextAssignees(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { @@ -543,6 +547,41 @@ public class BpmTaskServiceImpl implements BpmTaskService { handleParentTaskIfSign(task.getParentTaskId()); } + /** + * + * @param taskDefinitionKey 当前节点id + * @param bpmnModel bpmnModel + */ + private List getNextFlowNodes(String taskDefinitionKey, BpmnModel bpmnModel, Map variables){ + FlowNode flowElement = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); + // 存储下一个执行的节点 + List nextFlowNodes = new ArrayList<>(); + resolveNextNodes(flowElement, bpmnModel, variables, nextFlowNodes); + return nextFlowNodes; + } + + private void resolveNextNodes(FlowNode currentNode, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + List outgoingFlows = currentNode.getOutgoingFlows(); + for (SequenceFlow sequenceFlow : outgoingFlows) { + // 如果是排他网关,需要根据条件表达式判断 + if (currentNode instanceof ExclusiveGateway) { + String conditionExpression = sequenceFlow.getConditionExpression(); + if (conditionExpression != null && !BpmnModelUtils.evalConditionExpress(variables,conditionExpression)) { + continue; + } + } + FlowElement targetElement = bpmnModel.getFlowElement(sequenceFlow.getTargetRef()); + if (targetElement instanceof FlowNode targetNode) { + if (targetNode instanceof Gateway) { + // 如果目标节点还是网关,递归处理 + resolveNextNodes(targetNode, bpmnModel, variables, nextFlowNodes); + } else { + nextFlowNodes.add(targetNode); + } + } + } + } + /** * 校验传递的参数中是否存在不是下一个执行的节点 * @@ -559,6 +598,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { List activityNodes = approvalDetail.getActivityNodes(); if (CollUtil.isNotEmpty(activityNodes)) { // 2.1、获取节点中的审批人策略为【发起人自选】且状态为【未执行】的节点 + // TODO 获取下一个执行节点 List notStartActivityNodes = activityNodes.stream().filter(node -> BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy().equals(node.getCandidateStrategy()) && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus()) From 093e563b80ef8c34ccc6fb88e1d3e54502bd8a70 Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Thu, 27 Feb 2025 23:33:16 +0800 Subject: [PATCH 14/21] feat: add TODO --- .../bpm/service/task/BpmTaskServiceImpl.java | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 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 d64a822545..04842ea51d 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 @@ -529,7 +529,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { String taskDefinitionKey = task.getTaskDefinitionKey(); List nextFlowNodes = getNextFlowNodes(taskDefinitionKey, bpmnModel, variables); System.out.println(nextFlowNodes); - validateNextAssignees(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); +// validateNextAssignees(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 @@ -548,40 +548,66 @@ public class BpmTaskServiceImpl implements BpmTaskService { } /** - * - * @param taskDefinitionKey 当前节点id - * @param bpmnModel bpmnModel + * 根据当前节点 ID 获取下一个执行的 FlowNode 列表 + * @param taskDefinitionKey 当前节点 ID + * @param bpmnModel BPMN 模型 + * @param variables 流程变量,用于条件判断 + * @return 下一个执行的 FlowNode 列表 */ - private List getNextFlowNodes(String taskDefinitionKey, BpmnModel bpmnModel, Map variables){ - FlowNode flowElement = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); - // 存储下一个执行的节点 + public List getNextFlowNodes(String taskDefinitionKey, BpmnModel bpmnModel, Map variables) { + if (taskDefinitionKey == null || bpmnModel == null) { + throw new IllegalArgumentException("taskDefinitionKey and bpmnModel cannot be null"); + } + FlowNode currentNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); + if (currentNode == null) { + throw new IllegalArgumentException("FlowElement with given taskDefinitionKey not found in BpmnModel"); + } List nextFlowNodes = new ArrayList<>(); - resolveNextNodes(flowElement, bpmnModel, variables, nextFlowNodes); + resolveNextNodes(currentNode, bpmnModel, variables, nextFlowNodes); return nextFlowNodes; } + /** + * 递归解析下一个执行节点 + * @param currentNode 当前节点 + * @param bpmnModel BPMN 模型 + * @param variables 流程变量,用于条件判断 + * @param nextFlowNodes 存储下一个执行节点的列表 + */ private void resolveNextNodes(FlowNode currentNode, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { List outgoingFlows = currentNode.getOutgoingFlows(); for (SequenceFlow sequenceFlow : outgoingFlows) { - // 如果是排他网关,需要根据条件表达式判断 - if (currentNode instanceof ExclusiveGateway) { - String conditionExpression = sequenceFlow.getConditionExpression(); - if (conditionExpression != null && !BpmnModelUtils.evalConditionExpress(variables,conditionExpression)) { - continue; - } + if (!shouldFollowSequenceFlow(currentNode, sequenceFlow, variables)) { + continue; } FlowElement targetElement = bpmnModel.getFlowElement(sequenceFlow.getTargetRef()); if (targetElement instanceof FlowNode targetNode) { if (targetNode instanceof Gateway) { - // 如果目标节点还是网关,递归处理 + // 如果目标节点是网关,递归处理 resolveNextNodes(targetNode, bpmnModel, variables, nextFlowNodes); - } else { + }else { nextFlowNodes.add(targetNode); } } } } + /** + * 判断是否应该遵循当前序列流 + * @param currentNode 当前节点 + * @param sequenceFlow 序列流 + * @param variables 流程变量,用于条件判断 + * @return 是否应该遵循该序列流 + */ + private boolean shouldFollowSequenceFlow(FlowNode currentNode, SequenceFlow sequenceFlow, Map variables) { + if (currentNode instanceof ExclusiveGateway) { + String conditionExpression = sequenceFlow.getConditionExpression(); + return conditionExpression == null || BpmnModelUtils.evalConditionExpress(variables, conditionExpression); + } + return true; + } + + /** * 校验传递的参数中是否存在不是下一个执行的节点 * From 8df3a2d9502a9097d0629fa64b1bc26192357066 Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Fri, 28 Feb 2025 09:29:56 +0800 Subject: [PATCH 15/21] =?UTF-8?q?fix:=20=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BpmChildProcessMultiInstanceSourceTypeEnum.java | 4 ++-- .../definition/vo/model/simple/BpmSimpleModelNodeVO.java | 2 +- .../core/behavior/BpmParallelMultiInstanceBehavior.java | 4 ++-- .../core/behavior/BpmSequentialMultiInstanceBehavior.java | 4 ++-- .../bpm/framework/flowable/core/util/SimpleModelUtils.java | 7 +++---- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java index 8ab275f572..fab0ddfd71 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java @@ -17,8 +17,8 @@ import java.util.Arrays; public enum BpmChildProcessMultiInstanceSourceTypeEnum implements ArrayValuable { FIXED_QUANTITY(1, "固定数量"), - DIGITAL_FORM(2, "数字表单"), - MULTI_FORM(3, "多项表单"); + NUMBER_FORM(2, "数字表单"), + MULTIPLE_FORM(3, "多选表单"); private final Integer type; private final String name; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java index b18ad23561..f002e6894a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java @@ -509,7 +509,7 @@ public class BpmSimpleModelNodeVO { @Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @NotNull(message = "完成比例不能为空") - private Integer completeRatio; // TODO @lesan:approveRatio 要不这个,和上面保持一致? + private Integer approveRatio; @Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "多实例来源类型不能为空") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index e63c68e4e8..57f4d393f3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -77,10 +77,10 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav if (execution.getCurrentFlowElement() instanceof CallActivity) { FlowElement flowElement = execution.getCurrentFlowElement(); Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType())) { return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); } - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java index 35bba43106..cb748182ed 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java @@ -71,10 +71,10 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB if (execution.getCurrentFlowElement() instanceof CallActivity) { FlowElement flowElement = execution.getCurrentFlowElement(); Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType())) { return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); } - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index e0911240fc..da17b6d901 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -873,13 +873,12 @@ public class SimpleModelUtils { if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY.getType())) { multiInstanceCharacteristics.setLoopCardinality(childProcessSetting.getMultiInstanceSetting().getSource()); } - if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType()) || - childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { + if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType()) || + childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource()); } -// TODO @lesan:String.format(approveMethodEnum.getCompletionCondition(), String.format("%.2f", approveRatio / 100D))); multiInstanceCharacteristics.setCompletionCondition(String.format("${ nrOfCompletedInstances/nrOfInstances >= %s}", - String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getCompleteRatio() / 100D))); + String.format(BpmUserTaskApproveMethodEnum.RATIO.getCompletionCondition(), String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getApproveRatio() / 100D)))); callActivity.setLoopCharacteristics(multiInstanceCharacteristics); addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType()); } From 5b88d88177abeb846dc5b7210a15626be038c2ba Mon Sep 17 00:00:00 2001 From: Lesan <1960681385@qq.com> Date: Fri, 28 Feb 2025 09:35:43 +0800 Subject: [PATCH 16/21] =?UTF-8?q?fix:=20=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/SimpleModelUtils.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/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index da17b6d901..0060d0e9c5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -877,8 +877,8 @@ public class SimpleModelUtils { childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource()); } - multiInstanceCharacteristics.setCompletionCondition(String.format("${ nrOfCompletedInstances/nrOfInstances >= %s}", - String.format(BpmUserTaskApproveMethodEnum.RATIO.getCompletionCondition(), String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getApproveRatio() / 100D)))); + multiInstanceCharacteristics.setCompletionCondition(String.format(BpmUserTaskApproveMethodEnum.RATIO.getCompletionCondition(), + String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getApproveRatio() / 100D))); callActivity.setLoopCharacteristics(multiInstanceCharacteristics); addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType()); } From deef88f56fc4dd1235f24a10c11e1991be73a034 Mon Sep 17 00:00:00 2001 From: lizhixian <18210040298@163.com> Date: Fri, 28 Feb 2025 17:10:59 +0800 Subject: [PATCH 17/21] =?UTF-8?q?feat=EF=BC=9A=E5=AE=A1=E6=89=B9=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E6=97=B6=EF=BC=8C=E6=A0=A1=E9=AA=8C=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E4=B8=8B=E4=B8=80=E4=B8=AA=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/util/BpmnModelUtils.java | 119 ++++++++++++++++ .../bpm/service/task/BpmTaskServiceImpl.java | 133 ++++++------------ 2 files changed, 161 insertions(+), 91 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 b73e0cc98d..7873681318 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 @@ -828,6 +828,125 @@ public class BpmnModelUtils { } } + /** + * 根据当前节点,获取下一个节点 + * + * @param currentElement 当前节点 + * @param bpmnModel BPMN模型 + * @param variables 流程变量 + */ + public static List getNextFlowNodes(FlowElement currentElement, BpmnModel bpmnModel, + Map variables){ + // 下一个执行的流程节点集合 + List nextFlowNodes = new ArrayList<>(); + // 当前执行节点的基本属性 + FlowNode currentNode = (FlowNode) currentElement; + // 获取当前节点的关联节点 + List outgoingFlows = currentNode.getOutgoingFlows(); + if (CollUtil.isEmpty(outgoingFlows)){ + log.warn("[getNextFlowNodes][当前节点({}) 的 outgoingFlows 为空]", currentNode.getId()); + return nextFlowNodes; + } + // 遍历每个出口流 + for (SequenceFlow outgoingFlow : outgoingFlows) { + // 获取目标节点的基本属性 + FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef()); + if (targetElement == null){ + continue; + } + if (targetElement instanceof Gateway gateway) { + // 处理不同类型的网关 + if (gateway instanceof ExclusiveGateway) { + handleExclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); + } else if (gateway instanceof InclusiveGateway) { + handleInclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); + } else if (gateway instanceof ParallelGateway) { + handleParallelGateway(gateway, bpmnModel, variables, nextFlowNodes); + } + } else { + // 如果不是网关,直接添加到下一个节点列表 + nextFlowNodes.add((FlowNode) targetElement); + } + } + return nextFlowNodes; + } + + /** + * 处理排他网关 + * + * @param gateway 排他网关 + * @param bpmnModel BPMN模型 + * @param variables 流程变量 + * @param nextFlowNodes 下一个执行的流程节点集合 + */ + private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + // TODO @小北: 这里findOne和simulateNextFlowElements中有重复代码,需要优化,@芋道:是否重构?? + SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) + && (evalConditionExpress(variables, flow.getConditionExpression()))); + if (matchSequenceFlow == null) { + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); + // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 + if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) { + matchSequenceFlow = gateway.getOutgoingFlows().get(0); + } + } + // 遍历满足条件的 SequenceFlow 路径 + if (matchSequenceFlow != null) { + FlowElement targetElement = bpmnModel.getFlowElement(matchSequenceFlow.getTargetRef()); + if (targetElement instanceof FlowNode) { + nextFlowNodes.add((FlowNode) targetElement); + } + } + } + + /** + * 处理包容网关 + * + * @param gateway 排他网关 + * @param bpmnModel BPMN模型 + * @param variables 流程变量 + * @param nextFlowNodes 下一个执行的流程节点集合 + */ + private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + Collection matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) + && evalConditionExpress(variables, flow.getConditionExpression())); + if (CollUtil.isEmpty(matchSequenceFlows)) { + matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); + // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 + if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) { + matchSequenceFlows = gateway.getOutgoingFlows(); + } + } + // 遍历满足条件的 SequenceFlow 路径,获取目标节点 + matchSequenceFlows.forEach(flow -> { + FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); + if (targetElement instanceof FlowNode) { + nextFlowNodes.add((FlowNode) targetElement); + } + }); + } + /** + * 处理并行网关 + * + * @param gateway 排他网关 + * @param bpmnModel BPMN模型 + * @param variables 流程变量 + * @param nextFlowNodes 下一个执行的流程节点集合 + */ + private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + // 并行网关,遍历所有出口路径,获取目标节点 + gateway.getOutgoingFlows().forEach(flow -> { + FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); + if (targetElement instanceof FlowNode) { + nextFlowNodes.add((FlowNode) targetElement); + } + }); + } + /** * 计算条件表达式是否为 true 满足条件 * 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 04842ea51d..1a00f38617 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 @@ -23,6 +23,7 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; @@ -522,14 +523,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 2.3 调用 BPM complete 去完成任务 // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 - if (CollUtil.isNotEmpty(reqVO.getVariables())) { +// if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 校验传递的参数中是否存在不是下一个执行的节点 - // 当前执行的流程节点,需根据该节点寻找下一个节点 - String taskDefinitionKey = task.getTaskDefinitionKey(); - List nextFlowNodes = getNextFlowNodes(taskDefinitionKey, bpmnModel, variables); - System.out.println(nextFlowNodes); -// validateNextAssignees(userId, reqVO.getVariables(), task.getProcessInstanceId(), reqVO.getNextAssignees()); + validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 @@ -539,104 +536,58 @@ public class BpmTaskServiceImpl implements BpmTaskService { } runtimeService.setVariables(task.getProcessInstanceId(), variables); taskService.complete(task.getId(), variables, true); - } else { - taskService.complete(task.getId()); - } +// } else { +// taskService.complete(task.getId()); +// } // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); } - /** - * 根据当前节点 ID 获取下一个执行的 FlowNode 列表 - * @param taskDefinitionKey 当前节点 ID - * @param bpmnModel BPMN 模型 - * @param variables 流程变量,用于条件判断 - * @return 下一个执行的 FlowNode 列表 - */ - public List getNextFlowNodes(String taskDefinitionKey, BpmnModel bpmnModel, Map variables) { - if (taskDefinitionKey == null || bpmnModel == null) { - throw new IllegalArgumentException("taskDefinitionKey and bpmnModel cannot be null"); - } - FlowNode currentNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); - if (currentNode == null) { - throw new IllegalArgumentException("FlowElement with given taskDefinitionKey not found in BpmnModel"); - } - List nextFlowNodes = new ArrayList<>(); - resolveNextNodes(currentNode, bpmnModel, variables, nextFlowNodes); - return nextFlowNodes; - } - - /** - * 递归解析下一个执行节点 - * @param currentNode 当前节点 - * @param bpmnModel BPMN 模型 - * @param variables 流程变量,用于条件判断 - * @param nextFlowNodes 存储下一个执行节点的列表 - */ - private void resolveNextNodes(FlowNode currentNode, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { - List outgoingFlows = currentNode.getOutgoingFlows(); - for (SequenceFlow sequenceFlow : outgoingFlows) { - if (!shouldFollowSequenceFlow(currentNode, sequenceFlow, variables)) { - continue; - } - FlowElement targetElement = bpmnModel.getFlowElement(sequenceFlow.getTargetRef()); - if (targetElement instanceof FlowNode targetNode) { - if (targetNode instanceof Gateway) { - // 如果目标节点是网关,递归处理 - resolveNextNodes(targetNode, bpmnModel, variables, nextFlowNodes); - }else { - nextFlowNodes.add(targetNode); - } - } - } - } - - /** - * 判断是否应该遵循当前序列流 - * @param currentNode 当前节点 - * @param sequenceFlow 序列流 - * @param variables 流程变量,用于条件判断 - * @return 是否应该遵循该序列流 - */ - private boolean shouldFollowSequenceFlow(FlowNode currentNode, SequenceFlow sequenceFlow, Map variables) { - if (currentNode instanceof ExclusiveGateway) { - String conditionExpression = sequenceFlow.getConditionExpression(); - return conditionExpression == null || BpmnModelUtils.evalConditionExpress(variables, conditionExpression); - } - return true; - } - /** * 校验传递的参数中是否存在不是下一个执行的节点 * - * @param loginUserId 流程发起人 - * @param processInstanceId 流程实例id - * @param nextActivityNodes 下一个执行节点信息 {节点id : [审批人id,审批人id]} + * @param taskDefinitionKey 当前任务节点id + * @param variables 流程变量 + * @param bpmnModel 流程模型 + * @param nextActivityNodes 下一个节点审批人集合(参数) */ - private void validateNextAssignees(Long loginUserId, Map variables,String processInstanceId, - Map> nextActivityNodes){ - // 1、查询流程【预测】的全部信息 - BpmApprovalDetailRespVO approvalDetail = processInstanceService.getApprovalDetail(loginUserId, - new BpmApprovalDetailReqVO().setProcessVariables(variables).setProcessInstanceId(processInstanceId)); - // 2、获取预测节点的信息 - List activityNodes = approvalDetail.getActivityNodes(); - if (CollUtil.isNotEmpty(activityNodes)) { - // 2.1、获取节点中的审批人策略为【发起人自选】且状态为【未执行】的节点 - // TODO 获取下一个执行节点 - List notStartActivityNodes = activityNodes.stream().filter(node -> - BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy().equals(node.getCandidateStrategy()) - && BpmTaskStatusEnum.NOT_START.getStatus().equals(node.getStatus()) - && CollUtil.isEmpty(node.getCandidateUsers())).toList(); - // 3、校验传递的参数中是否存在不是下一个节点的信息 - for (Map.Entry> nextActivityNode : nextActivityNodes.entrySet()) { - if (notStartActivityNodes.stream().noneMatch(taskNode -> taskNode.getId().equals(nextActivityNode.getKey()))) { - log.error("[checkNextActivityNodes][ ({}) 不是下一个执行的流程节点!]", nextActivityNode.getKey()); - throw exception(TASK_START_USER_SELECT_NODE_NOT_EXISTS, nextActivityNode.getKey()); + private void validateNextAssignees(String taskDefinitionKey, Map variables, BpmnModel bpmnModel, + Map> nextActivityNodes,ProcessInstance processInstance){ + + // 1、获取当前任务节点的信息 + FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); + // 2、获取下一个应该执行的节点集合 + List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); + // 3、比较前端传递的节点和预测的下一个节点是否匹配,匹配则将该节点设置上审批人 + for (FlowNode nextFlowNode : nextFlowNodes) { + // 获取下一个执行节点的属性 是否为 发起人自选 + Map> extensionElements = nextFlowNode.getExtensionElements(); + List elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); + if (CollUtil.isEmpty(elements)){ + continue; + } + // 获取节点中的审批人策略 + Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText()); + // 获取流程实例中的发起人自选审批人 + Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); + List startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId()); + if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) { + // 先判断节点是否存在 + if (!nextActivityNodes.containsKey(nextFlowNode.getId())){ + throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); + } + // 如果节点存在,则判断节点中的审批人策略是否为 发起人自选 + List nextAssignees = nextActivityNodes.get(nextFlowNode.getId()); + // 3.1、如果前端传递的节点为空,则抛出异常 + if (CollUtil.isEmpty(nextAssignees)) { + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } } + } + } /** From ff555b51366c1e0df4a571f59a3cef4f812546fb Mon Sep 17 00:00:00 2001 From: smallNorthLee <18210040298@163.com> Date: Fri, 28 Feb 2025 22:37:57 +0800 Subject: [PATCH 18/21] =?UTF-8?q?feat:=20=E5=AE=A1=E6=89=B9=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E6=97=B6=EF=BC=8C=E6=A0=A1=E9=AA=8C=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E4=B8=8B=E4=B8=80=E4=B8=AA=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/util/BpmnModelUtils.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 32 +++++++++---------- 2 files changed, 16 insertions(+), 18 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 7873681318..fff0ac5317 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 @@ -880,7 +880,7 @@ public class BpmnModelUtils { * @param nextFlowNodes 下一个执行的流程节点集合 */ private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { - // TODO @小北: 这里findOne和simulateNextFlowElements中有重复代码,需要优化,@芋道:是否重构?? + // TODO @小北: 这里和simulateNextFlowElements中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋道 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) && (evalConditionExpress(variables, flow.getConditionExpression()))); 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 1a00f38617..bcc70da867 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 @@ -523,9 +523,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 2.3 调用 BPM complete 去完成任务 // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 -// if (CollUtil.isNotEmpty(reqVO.getVariables())) { + if (CollUtil.isNotEmpty(reqVO.getVariables())) { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); - // 校验传递的参数中是否存在不是下一个执行的节点 + // 校验传递的参数中是否为下一个将要执行的任务节点 validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance); // 下个节点审批人如果不存在,则由前端传递 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { @@ -536,9 +536,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { } runtimeService.setVariables(task.getProcessInstanceId(), variables); taskService.complete(task.getId(), variables, true); -// } else { -// taskService.complete(task.getId()); -// } + } else { + taskService.complete(task.getId()); + } // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); @@ -546,7 +546,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { /** - * 校验传递的参数中是否存在不是下一个执行的节点 + * 校验传递的参数中是否为下一个将要执行的任务节点 * * @param taskDefinitionKey 当前任务节点id * @param variables 流程变量 @@ -555,39 +555,37 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private void validateNextAssignees(String taskDefinitionKey, Map variables, BpmnModel bpmnModel, Map> nextActivityNodes,ProcessInstance processInstance){ - // 1、获取当前任务节点的信息 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); - // 2、获取下一个应该执行的节点集合 + // 2、获取下一个将要执行的节点集合 List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); - // 3、比较前端传递的节点和预测的下一个节点是否匹配,匹配则将该节点设置上审批人 + // 3、循环下一个将要执行的节点集合 for (FlowNode nextFlowNode : nextFlowNodes) { - // 获取下一个执行节点的属性 是否为 发起人自选 + // 3.1、获取下一个将要执行节点的属性(是否为自选审批人等) Map> extensionElements = nextFlowNode.getExtensionElements(); List elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); if (CollUtil.isEmpty(elements)){ continue; } - // 获取节点中的审批人策略 + // 3.2、获取节点中的审批人策略 Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText()); - // 获取流程实例中的发起人自选审批人 + // 3.3、获取流程实例中的发起人自选审批人 Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); List startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId()); + // 3.4、如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) { - // 先判断节点是否存在 + // 先判断前端传递的参数节点节点是否为将要执行的节点 if (!nextActivityNodes.containsKey(nextFlowNode.getId())){ throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); } - // 如果节点存在,则判断节点中的审批人策略是否为 发起人自选 + // 如果节点存在,则获取节点中的审批人 List nextAssignees = nextActivityNodes.get(nextFlowNode.getId()); - // 3.1、如果前端传递的节点为空,则抛出异常 + // 如果前端传递的节点为空,则抛出异常 if (CollUtil.isEmpty(nextAssignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } } - } - } /** From fedb9242b59b9846951d49e475b718c5a87a406e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Mar 2025 16:34:30 +0800 Subject: [PATCH 19/21] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91BPM=EF=BC=9A=E4=B8=8B=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 1 - .../task/vo/task/BpmTaskApproveReqVO.java | 2 +- ...mTaskCandidateStartUserSelectStrategy.java | 44 +++------------- .../flowable/core/util/BpmnModelUtils.java | 40 ++++++++------- .../task/BpmProcessInstanceServiceImpl.java | 4 +- .../bpm/service/task/BpmTaskServiceImpl.java | 51 +++++++++++-------- 6 files changed, 62 insertions(+), 80 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index a1e2d45aa9..3a50bba523 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -58,7 +58,6 @@ public interface ErrorCodeConstants { ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!"); ErrorCode TASK_REASON_REQUIRE = new ErrorCode(1_009_005_016, "审批意见不能为空!"); - ErrorCode TASK_START_USER_SELECT_NODE_NOT_EXISTS = new ErrorCode(1_009_004_007, "({})不是下一个执行的流程节点!"); // ========== 动态表单模块 1-009-010-000 ========== ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index a0751c12e6..0969fda135 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -25,6 +25,6 @@ public class BpmTaskApproveReqVO { private Map variables; @Schema(description = "下一个节点审批人", example = "{nodeId:[1, 2]}") - private Map> nextAssignees; + private Map> nextAssignees; // 为什么是 Map,而不是 List 呢?因为下一个节点可能是多个,例如说并行网关的情况 } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java index f4efa549e5..9304d288ac 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java @@ -2,24 +2,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import com.google.common.collect.Sets; import jakarta.annotation.Resource; import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.ServiceTask; -import org.flowable.bpmn.model.Task; -import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; /** * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 @@ -53,12 +50,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", execution.getProcessInstanceId()); - // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 + // 获得审批人 List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); - if (CollUtil.isEmpty(assignees)){ - return Sets.newLinkedHashSet(); - } - return new LinkedHashSet<>(assignees); + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet(); } @Override @@ -71,33 +65,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand if (startUserSelectAssignees == null) { return Sets.newLinkedHashSet(); } - // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 + // 获得审批人 List assignees = startUserSelectAssignees.get(activityId); - if (CollUtil.isEmpty(assignees)){ - return Sets.newLinkedHashSet(); - } - return new LinkedHashSet<>(assignees); - } - - /** - * 获得发起人自选审批人或抄送人的 Task 列表 - * - * @param bpmnModel BPMN 模型 - * @return Task 列表 - */ - public static List getStartUserSelectTaskList(BpmnModel bpmnModel) { - if (bpmnModel == null) { - return Collections.emptyList(); - } - List tasks = new ArrayList<>(); - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class)); - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, ServiceTask.class)); - if (CollUtil.isEmpty(tasks)) { - return Collections.emptyList(); - } - tasks.removeIf(task -> ObjectUtil.notEqual(BpmnModelUtils.parseCandidateStrategy(task), - BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())); - return tasks; + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet(); } } 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 31c27c2b2a..1eea893f76 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 @@ -809,8 +809,7 @@ public class BpmnModelUtils { if (currentElement instanceof ExclusiveGateway) { // 查找满足条件的 SequenceFlow 路径 Gateway gateway = (Gateway) currentElement; - // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题,需要优化, - // TODO 具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761 + // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题。需要优化,具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) && (evalConditionExpress(variables, flow.getConditionExpression()))); @@ -866,27 +865,27 @@ public class BpmnModelUtils { * @param bpmnModel BPMN模型 * @param variables 流程变量 */ + @SuppressWarnings("PatternVariableCanBeUsed") public static List getNextFlowNodes(FlowElement currentElement, BpmnModel bpmnModel, Map variables){ - // 下一个执行的流程节点集合 - List nextFlowNodes = new ArrayList<>(); - // 当前执行节点的基本属性 - FlowNode currentNode = (FlowNode) currentElement; - // 获取当前节点的关联节点 - List outgoingFlows = currentNode.getOutgoingFlows(); - if (CollUtil.isEmpty(outgoingFlows)){ + List nextFlowNodes = new ArrayList<>(); // 下一个执行的流程节点集合 + FlowNode currentNode = (FlowNode) currentElement; // 当前执行节点的基本属性 + List outgoingFlows = currentNode.getOutgoingFlows(); // 当前节点的关联节点 + if (CollUtil.isEmpty(outgoingFlows)) { log.warn("[getNextFlowNodes][当前节点({}) 的 outgoingFlows 为空]", currentNode.getId()); return nextFlowNodes; } + // 遍历每个出口流 for (SequenceFlow outgoingFlow : outgoingFlows) { // 获取目标节点的基本属性 FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef()); - if (targetElement == null){ + if (targetElement == null) { continue; } - if (targetElement instanceof Gateway gateway) { - // 处理不同类型的网关 + // 情况一:处理不同类型的网关 + if (targetElement instanceof Gateway) { + Gateway gateway = (Gateway) targetElement; if (gateway instanceof ExclusiveGateway) { handleExclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); } else if (gateway instanceof InclusiveGateway) { @@ -895,7 +894,7 @@ public class BpmnModelUtils { handleParallelGateway(gateway, bpmnModel, variables, nextFlowNodes); } } else { - // 如果不是网关,直接添加到下一个节点列表 + // 情况二:如果不是网关,直接添加到下一个节点列表 nextFlowNodes.add((FlowNode) targetElement); } } @@ -903,15 +902,17 @@ public class BpmnModelUtils { } /** - * 处理排他网关 + * 处理排它网关 * * @param gateway 排他网关 * @param bpmnModel BPMN模型 * @param variables 流程变量 * @param nextFlowNodes 下一个执行的流程节点集合 */ - private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { - // TODO @小北: 这里和simulateNextFlowElements中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋道 + private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, + Map variables, List nextFlowNodes) { + // TODO @小北: 这里和 simulateNextFlowElements 中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋艿 + // TODO @小北:ok,把 simulateNextFlowElements 里面处理网关的,复用这个方法,可以么? SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) && (evalConditionExpress(variables, flow.getConditionExpression()))); @@ -940,7 +941,8 @@ public class BpmnModelUtils { * @param variables 流程变量 * @param nextFlowNodes 下一个执行的流程节点集合 */ - private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel, + Map variables, List nextFlowNodes) { Collection matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) && evalConditionExpress(variables, flow.getConditionExpression())); @@ -960,6 +962,7 @@ public class BpmnModelUtils { } }); } + /** * 处理并行网关 * @@ -968,7 +971,8 @@ public class BpmnModelUtils { * @param variables 流程变量 * @param nextFlowNodes 下一个执行的流程节点集合 */ - private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel, Map variables, List nextFlowNodes) { + private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel, + Map variables, List nextFlowNodes) { // 并行网关,遍历所有出口路径,获取目标节点 gateway.getOutgoingFlows().forEach(flow -> { FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); 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 2b8e67c147..9da2610cb6 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 @@ -175,9 +175,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); - // 如果流程变量不为空,则用前端传递的新变量值覆盖历史的流程变量 + // 合并 DB 和前端传递的流量变量,以前端的为主 Map historicVariables = historicProcessInstance.getProcessVariables(); - if (null != processVariables) { + if (CollUtil.isNotEmpty(processVariables)) { historicVariables.putAll(processVariables); } processVariables = historicVariables; 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 ab9238dc10..0b5a70ab08 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 @@ -11,13 +11,10 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; -import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.*; import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; @@ -63,7 +60,6 @@ import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.*; -import java.util.stream.Collectors; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -535,9 +531,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); // 校验传递的参数中是否为下一个将要执行的任务节点 validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance); - // 下个节点审批人如果不存在,则由前端传递 + // 如果有下一个审批人,则设置到流程变量中 + // TODO @小北:validateNextAssignees 升级成 validateAndSetNextAssignees,然后里面吧下面这一小段逻辑,抽进去如何? if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 + // TODO @小北:这里有个需要讨论的点,微信哈; + // TODO 因为 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES 定位是发起人,那么审批人选择的,放在 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES。目前想到两个方案: + // TODO 方案一:增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,然后设置到这里面。然后,BpmTaskCandidateStartUserSelectStrategy 也从这里读 + // TODO 方案二:也是增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,根据节点审批人类型,放到 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES、PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES + // TODO 方案三:融合成 PROCESS_INSTANCE_VARIABLE_USER_SELECT_ASSIGNEES,不再区分是发起人选择、还是审批人选择。 Map> hisProcessVariables = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); hisProcessVariables.putAll(reqVO.getNextAssignees()); variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, hisProcessVariables); @@ -554,45 +556,52 @@ public class BpmTaskServiceImpl implements BpmTaskService { /** - * 校验传递的参数中是否为下一个将要执行的任务节点 + * 校验选择的下一个节点的审批人,是否合法 * - * @param taskDefinitionKey 当前任务节点id + * 1. 是否有漏选:没有选择审批人 + * 2. 是否有多选:非下一个节点 + * + * @param taskDefinitionKey 当前任务节点标识 * @param variables 流程变量 * @param bpmnModel 流程模型 - * @param nextActivityNodes 下一个节点审批人集合(参数) + * @param nextAssignees 下一个节点审批人集合(参数) + * @param processInstance 流程实例 */ private void validateNextAssignees(String taskDefinitionKey, Map variables, BpmnModel bpmnModel, - Map> nextActivityNodes,ProcessInstance processInstance){ - // 1、获取当前任务节点的信息 + Map> nextAssignees, ProcessInstance processInstance) { + // 1. 获取当前任务节点的信息 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); - // 2、获取下一个将要执行的节点集合 + // 2. 获取下一个将要执行的节点集合 List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); - // 3、循环下一个将要执行的节点集合 + + // 3. 循环下一个将要执行的节点集合 for (FlowNode nextFlowNode : nextFlowNodes) { - // 3.1、获取下一个将要执行节点的属性(是否为自选审批人等) + // 3.1 获取下一个将要执行节点的属性(是否为自选审批人等) + // TODO @小北:public static Integer parseCandidateStrategy(FlowElement userTask) 使用这个工具方法哈。 Map> extensionElements = nextFlowNode.getExtensionElements(); List elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); - if (CollUtil.isEmpty(elements)){ + if (CollUtil.isEmpty(elements)) { continue; } - // 3.2、获取节点中的审批人策略 + // 3.2 获取节点中的审批人策略 Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText()); - // 3.3、获取流程实例中的发起人自选审批人 + // 3.3 获取流程实例中的发起人自选审批人 Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); List startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId()); - // 3.4、如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空 + // 3.4 如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) { // 先判断前端传递的参数节点节点是否为将要执行的节点 - if (!nextActivityNodes.containsKey(nextFlowNode.getId())){ + // TODO @小北:!nextAssignees.containsKey(nextFlowNode.getId())、和 CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) 是不是等价的? + if (!nextAssignees.containsKey(nextFlowNode.getId())) { throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); } - // 如果节点存在,则获取节点中的审批人 - List nextAssignees = nextActivityNodes.get(nextFlowNode.getId()); // 如果前端传递的节点为空,则抛出异常 - if (CollUtil.isEmpty(nextAssignees)) { + // TODO @小北:换一个错误码哈。 + if (CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } } + // TODO @小北:加一个“审批人选择”的校验; } } From 9927dd443944d787423726cdfa3f4e00ca7e0bf9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Mar 2025 20:39:23 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=9A=E4=B9=89=E7=9A=84=20simple=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/definition/BpmModelController.java | 2 +- .../definition/BpmProcessDefinitionController.java | 13 +++++++++++++ .../admin/task/BpmProcessInstanceController.java | 12 +++++++++--- .../task/vo/instance/BpmProcessInstanceRespVO.java | 8 ++++++++ .../admin/task/vo/task/BpmTaskPageReqVO.java | 3 +++ .../bpm/convert/task/BpmProcessInstanceConvert.java | 9 +++++++++ .../bpm/service/task/BpmProcessInstanceService.java | 1 - .../module/bpm/service/task/BpmTaskServiceImpl.java | 3 +++ 8 files changed, 46 insertions(+), 5 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java index 6483ee0e39..5578114f9d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java @@ -57,7 +57,7 @@ public class BpmModelController { @GetMapping("/list") @Operation(summary = "获得模型分页") @Parameter(name = "name", description = "模型名称", example = "芋艿") - public CommonResult> getModelPage(@RequestParam(value = "name", required = false) String name) { + public CommonResult> getModelList(@RequestParam(value = "name", required = false) String name) { List list = modelService.getModelList(name); if (CollUtil.isEmpty(list)) { return success(Collections.emptyList()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java index 28cbd0ab98..90c38886a7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.springframework.security.access.prepost.PreAuthorize; @@ -31,6 +32,7 @@ import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -99,6 +101,17 @@ public class BpmProcessDefinitionController { list, null, processDefinitionMap, null, null)); } + @GetMapping("/simple-list") + @Operation(summary = "获得流程定义精简列表", description = "只包含未挂起的流程,主要用于前端的下拉选项") + public CommonResult> getSimpleProcessDefinitionList() { + // 只查询未挂起的流程 + List list = processDefinitionService.getProcessDefinitionListBySuspensionState( + SuspensionState.ACTIVE.getStateCode()); + // 拼接 VO 返回,只返回 id、name、key + return success(convertList(list, definition -> new BpmProcessDefinitionRespVO() + .setId(definition.getId()).setName(definition.getName()).setKey(definition.getKey()))); + } + @GetMapping ("/get") @Operation(summary = "获得流程定义") @Parameter(name = "id", description = "流程编号", required = true, example = "1024") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java index def95cca63..7ce43a32c2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java @@ -32,10 +32,10 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” @@ -78,8 +78,14 @@ public class BpmProcessInstanceController { convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); Map processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); + Set userIds = convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId())); + userIds.addAll(convertSetByFlatMap(taskMap.values(), + tasks -> tasks.stream().map(Task::getAssignee).filter(StrUtil::isNotBlank).map(Long::parseLong))); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, - processDefinitionMap, categoryMap, taskMap, null, null, processDefinitionInfoMap)); + processDefinitionMap, categoryMap, taskMap, userMap, deptMap, processDefinitionInfoMap)); } @GetMapping("/manager-page") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java index 76dca606a2..f73c490a54 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -73,6 +74,13 @@ public class BpmProcessInstanceRespVO { @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; + @Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") + @JsonIgnore // 不返回,只是方便后续读取,赋值给 assigneeUser + private Long assignee; + + @Schema(description = "任务分配人", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") + private UserSimpleBaseVO assigneeUser; + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java index 11c59ce3ed..f129e5a315 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java @@ -18,6 +18,9 @@ public class BpmTaskPageReqVO extends PageParam { @Schema(description = "流程分类", example = "1") private String category; + @Schema(description = "流程定义的标识", example = "2048") + private String processDefinitionKey; // 精准匹配 + @Schema(description = "创建时间") @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 6e798e77f2..ccd7f06e74 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -76,6 +76,15 @@ public interface BpmProcessInstanceConvert { respVO.setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class)); MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); } + if (CollUtil.isNotEmpty(respVO.getTasks())) { + respVO.getTasks().forEach(task -> { + AdminUserRespDTO assigneeUser = userMap.get(task.getAssignee()); + if (assigneeUser!= null) { + task.setAssigneeUser(BeanUtils.toBean(assigneeUser, UserSimpleBaseVO.class)); + MapUtils.findAndThen(deptMap, assigneeUser.getDeptId(), dept -> task.getAssigneeUser().setDeptName(dept.getName())); + } + }); + } } // 摘要 respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()), diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index c4684d3402..6b9c6fa3e7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -85,7 +85,6 @@ public interface BpmProcessInstanceService { PageResult getProcessInstancePage(Long userId, @Valid BpmProcessInstancePageReqVO pageReqVO); - // TODO @芋艿:重点在 review 下 /** * 获取审批详情。 *

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 0b5a70ab08..5d9f1552b4 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 @@ -122,6 +122,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotEmpty(pageVO.getCategory())) { taskQuery.taskCategory(pageVO.getCategory()); } + if (StrUtil.isNotEmpty(pageVO.getProcessDefinitionKey())) { + taskQuery.processDefinitionKey(pageVO.getProcessDefinitionKey()); + } if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); From d8a7d668a4658b9ece574e4eb497795889bd6a04 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 2 Mar 2025 09:56:54 +0800 Subject: [PATCH 21/21] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91BPM=EF=BC=9A=E6=94=AF=E6=8C=81=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E2=80=9C=E5=8E=86=E5=8F=B2=E2=80=9D=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/vo/model/BpmModelRespVO.java | 2 +- .../process/BpmProcessDefinitionRespVO.java | 29 ++++--------------- .../BpmProcessDefinitionInfoDO.java | 11 +++++-- .../BpmProcessDefinitionServiceImpl.java | 3 +- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java index 278291483d..275368c7c6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java @@ -25,7 +25,7 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO { @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") private String icon; - @Schema(description = "流程分类编码", example = "1") + @Schema(description = "流程分类编号", example = "1") private String category; @Schema(description = "流程分类名字", example = "请假") private String categoryName; 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 1e9dfc8207..8da290440e 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 @@ -1,14 +1,14 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -import java.util.List; @Schema(description = "管理后台 - 流程定义 Response VO") @Data -public class BpmProcessDefinitionRespVO { +public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String id; @@ -22,36 +22,19 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") private String key; - @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") - private String icon; - - @Schema(description = "流程描述", example = "我是描述") - private String description; - @Schema(description = "流程分类", example = "1") private String category; @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 = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") - private Integer formType; - @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") - private Long formId; @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 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/create") - private String formCustomCreatePath; - @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/view") - private String formCustomViewPath; @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer suspensionState; // 参见 SuspensionState 枚举 @@ -67,7 +50,7 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "流程定义排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long sort; - + @Schema(description = "BPMN UserTask 用户任务") @Data public static class UserTask { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java index ccab7b0435..34dfbece3a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; -import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; import cn.iocoder.yudao.module.bpm.enums.definition.BpmAutoApproveTypeEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; @@ -60,6 +59,14 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { */ private Integer modelType; + /** + * 流程分类的编码 + * + * 关联 {@link BpmCategoryDO#getCode()} + * + * 为什么要存储?原因是,{@link ProcessDefinition#getCategory()} 无法设置 + */ + private String category; /** * 图标 */ @@ -149,7 +156,7 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { * * 关联 {@link AdminUserRespDTO#getId()} 字段的数组 */ - @TableField(typeHandler = StringListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤 + @TableField(typeHandler = LongListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤 private List managerUserIds; /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java index 96280fa088..14ee084063 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java @@ -143,9 +143,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ // 插入拓展表 BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) - .setModelId(model.getId()).setProcessDefinitionId(definition.getId()) + .setModelId(model.getId()).setCategory(model.getCategory()).setProcessDefinitionId(definition.getId()) .setModelType(modelMetaInfo.getType()).setSimpleModel(simpleJson); - if (form != null) { definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); }