From bfcc1987cb1e8675f7e8d540c55a5d5a5be09c64 Mon Sep 17 00:00:00 2001 From: xingyu4j Date: Sat, 19 Jul 2025 16:56:23 +0800 Subject: [PATCH 01/16] =?UTF-8?q?fix:=20=E3=80=90BPM=20=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81=E3=80=91=E9=81=BF=E5=85=8D=E5=9C=A8=20BpmHttpRequestU?= =?UTF-8?q?tils=20=E4=B8=AD=E9=87=8D=E5=A4=8D=E6=B7=BB=E5=8A=A0=20processI?= =?UTF-8?q?nstanceId=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/BpmHttpRequestUtils.java | 4 +++- .../codegen/vue3_vben5_antd/schema/views/index.vue.vm | 2 +- .../vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm | 2 +- .../codegen/vue3_vben5_ele/schema/views/index.vue.vm | 2 +- .../vue3_vben5_ele/schema/views/modules/list_sub_erp.vue.vm | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java index 2503c0fff9..014b5e3f0d 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java @@ -108,7 +108,9 @@ public class BpmHttpRequestUtils { Map processVariables = processInstance.getProcessVariables(); MultiValueMap body = new LinkedMultiValueMap<>(); addHttpRequestParam(body, bodySettings, processVariables); - body.add("processInstanceId", processInstance.getId()); + if (!body.containsKey("processInstanceId")) { // 避免重复添加 + body.add("processInstanceId", processInstance.getId()); + } return body; } diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/index.vue.vm index fdac956ff7..635e12ac24 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/index.vue.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/index.vue.vm @@ -180,7 +180,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ #end }, toolbarConfig: { - refresh: { code: 'query' }, + refresh: true, search: true, }, } as VxeTableGridOptions<${simpleClassName}Api.${simpleClassName}>, diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm index 97404b0211..4001ed3992 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm @@ -131,7 +131,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ enabled: true, }, toolbarConfig: { - refresh: { code: 'query' }, + refresh: true, search: true, }, #else diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/index.vue.vm index 3bb2b6a4a1..f9232d6b50 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/index.vue.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/index.vue.vm @@ -174,7 +174,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ #end }, toolbarConfig: { - refresh: { code: 'query' }, + refresh: true, search: true, }, } as VxeTableGridOptions<${simpleClassName}Api.${simpleClassName}>, diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/modules/list_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/modules/list_sub_erp.vue.vm index 4dd5a6f1b4..5afb9c7a0d 100644 --- a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/modules/list_sub_erp.vue.vm +++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/modules/list_sub_erp.vue.vm @@ -125,7 +125,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ enabled: true, }, toolbarConfig: { - refresh: { code: 'query' }, + refresh: true, search: true, }, #else From dc7763ef0b126dc561b2bdbf2d9f60c2b671f16f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Jul 2025 16:45:16 +0800 Subject: [PATCH 02/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91BpmTaskCandidateExpressionStrategy?= =?UTF-8?q?=20=E5=9C=A8=20PropertyNotFoundException=20=E4=B8=8D=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E6=97=B6=EF=BC=8C=E9=A2=91=E7=B9=81=E6=89=93=20warn?= =?UTF-8?q?=20=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expression/BpmTaskAssignLeaderExpression.java | 1 + .../expression/BpmTaskAssignStartUserExpression.java | 1 + .../other/BpmTaskCandidateExpressionStrategy.java | 11 +++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java index 7c1950f8ce..e9180c8695 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -24,6 +24,7 @@ import static java.util.Collections.emptySet; * @author 芋道源码 */ @Component +@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserDeptLeaderStrategy 替代 public class BpmTaskAssignLeaderExpression { @Resource diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java index ac243c0f43..f22dc508cb 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -16,6 +16,7 @@ import java.util.Set; * @author 芋道源码 */ @Component +@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserStrategy 替代 public class BpmTaskAssignStartUserExpression { @Resource diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java index 64ca9e8538..86c137a4b7 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java @@ -8,6 +8,7 @@ import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.impl.javax.el.PropertyNotFoundException; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; @@ -48,10 +49,12 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat Object result = FlowableUtils.getExpressionValue(variables, param); return CollectionUtils.toLinkedHashSet(Long.class, result); } catch (FlowableException ex) { - // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常, - log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); - // 不能预测候选人,返回空列表, 避免流程无法进行 - return Sets.newHashSet(); + // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常,此时忽略该异常!相当于说,不做流程预测!!! + if (ex.getCause() != null && ex.getCause() instanceof PropertyNotFoundException) { + return Sets.newHashSet(); + } + log.error("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); + throw ex; } } From c645813725420517bcb92c6fee82a09e90e7ebc0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Jul 2025 17:47:50 +0800 Subject: [PATCH 03/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=BE=85=E5=8A=9E=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E3=80=81=E5=B7=B2=E5=8A=9E=E4=BB=BB=E5=8A=A1=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=97=B6=E9=97=B4=E8=8C=83=E5=9B=B4=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=BC=9A=E6=8B=BC=E6=8E=A5=20OR=20=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5=EF=BC=88=E9=9D=9E=E5=AE=8C=E7=BE=8E=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=96=B9=E6=A1=88=EF=BC=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/service/task/BpmTaskServiceImpl.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 1164f4da72..1f7e699032 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -230,10 +230,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } - if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { - taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); - } +// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { +// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); +// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); +// } // 执行查询 long count = taskQuery.count(); if (count == 0) { @@ -244,6 +244,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 特殊:强制移除自动完成的“发起人”节点 // 补充说明:由于 taskQuery 无法方面的过滤,所以暂时通过内存过滤 tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID)); + // TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + tasks.removeIf(task -> task.getCreateTime() == null + || task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0])) + || task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1]))); + } return new PageResult<>(tasks, count); } @@ -259,16 +265,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotEmpty(pageVO.getCategory())) { taskQuery.taskCategory(pageVO.getCategory()); } - if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { - taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); - } +// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { +// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); +// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); +// } // 执行查询 long count = taskQuery.count(); if (count == 0) { return PageResult.empty(); } List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + // TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + tasks.removeIf(task -> task.getCreateTime() == null + || task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0])) + || task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1]))); + } return new PageResult<>(tasks, count); } From 14d8c2bb404caa337565a80b242c736822f3278a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Jul 2025 20:02:48 +0800 Subject: [PATCH 04/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91buildConditionExpression=20=E5=9C=A8?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E9=A2=84=E6=B5=8B=E6=97=B6=EF=BC=8C=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E5=8F=98=E9=87=8F=E4=B8=8D=E5=AD=98=E5=9C=A8=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=20Unknow=20property=20=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/util/SimpleModelUtils.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index bd427e32f2..c9f3ff6fcb 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.*; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; @@ -17,13 +16,14 @@ import cn.iocoder.yudao.module.bpm.service.task.listener.BpmCallActivityListener import cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener; import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.constants.BpmnXMLConstants; -import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.Process; import org.flowable.engine.delegate.ExecutionListener; import org.flowable.engine.delegate.TaskListener; import java.util.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 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; @@ -684,15 +684,18 @@ public class SimpleModelUtils { if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { return null; } - List strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> { + List strConditionGroups = convertList(conditionGroups.getConditions(), item -> { if (CollUtil.isEmpty(item.getRules())) { return ""; } // 构造规则表达式 - List list = CollectionUtils.convertList(item.getRules(), (rule) -> { + List list = convertList(item.getRules(), (rule) -> { String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide() : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号 - return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide); + return String.format(" vars:getOrDefault(%s, null) %s var:convertByType(%s,%s) ", + rule.getLeftSide(), // 左侧:读取变量 + rule.getOpCode(), // 中间:操作符,比较 + rule.getLeftSide(), rightSide); // 右侧:转换变量,VariableConvertByTypeExpressionFunction }); // 构造条件组的表达式 Boolean and = item.getAnd(); From 51859afa9ac1ffb3b7b28af37c6b904ac54b3a62 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Jul 2025 20:26:23 +0800 Subject: [PATCH 05/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91SIMPLE=20=E5=BB=B6=E8=BF=9F=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=97=B6=EF=BC=8C=E7=A7=9F=E6=88=B7=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E4=B8=A2=E5=A4=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/listener/BpmTaskEventListener.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java index e50df0bcf0..9aa3889e59 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; 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.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import com.google.common.collect.ImmutableSet; @@ -58,17 +59,20 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @Override protected void taskCreated(FlowableEngineEntityEvent event) { - taskService.processTaskCreated((Task) event.getEntity()); + Task entity = (Task) event.getEntity(); + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCreated(entity)); } @Override protected void taskAssigned(FlowableEngineEntityEvent event) { - taskService.processTaskAssigned((Task) event.getEntity()); + Task entity = (Task) event.getEntity(); + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskAssigned(entity)); } @Override protected void taskCompleted(FlowableEngineEntityEvent event) { - taskService.processTaskCompleted((Task) event.getEntity()); + Task entity = (Task) event.getEntity(); + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCompleted(entity)); } @Override From d36c0dce7cf24514dd7484f7b9e1a05afd5e2ff8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 20 Jul 2025 23:43:46 +0800 Subject: [PATCH 06/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91BPMN=20=E5=9C=BA=E6=99=AF=E4=B8=8B?= =?UTF-8?q?=EF=BC=8C=E5=A4=9A=E6=AC=A1=E6=8F=90=E9=86=92=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=20elementId=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/listener/BpmTaskEventListener.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java index 9aa3889e59..6e2e48cbec 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; @@ -98,6 +99,23 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { String processDefinitionId = event.getProcessDefinitionId(); BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processDefinitionId); Job entity = (Job) event.getEntity(); + // 特殊 from https://t.zsxq.com/h6oWr :当 elementId 为空时,尝试从 JobHandlerConfiguration 中解析 JSON 获取 + String elementId = entity.getElementId(); + if (elementId == null && entity.getJobHandlerConfiguration() != null) { + try { + String handlerConfig = entity.getJobHandlerConfiguration(); + if (handlerConfig.startsWith("{") && handlerConfig.contains("activityId")) { + elementId = new JSONObject(handlerConfig).getStr("activityId"); + } + } catch (Exception e) { + log.error("[timerFired][解析 entity({}) 失败]", entity, e); + return; + } + } + if (elementId == null) { + log.error("[timerFired][解析 entity({}) elementId 为空,跳过处理]", entity); + return; + } FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, entity.getElementId()); if (!(element instanceof BoundaryEvent)) { return; From 3aac40a51e6dcdd449e4ea5d0418ca837de5a2da Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 21 Jul 2025 16:17:17 +0800 Subject: [PATCH 07/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E6=B5=81=E7=A8=8B=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=88=A0=E9=99=A4=E6=97=B6=EF=BC=8C=E9=A2=9D?= =?UTF-8?q?=E5=A4=96=E6=A0=A1=E9=AA=8C=E6=98=AF=E5=90=A6=E8=A2=AB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=A8=A1=E5=9E=8B=E6=89=80=E4=BD=BF=E7=94=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 1 + .../definition/BpmCategoryServiceImpl.java | 16 +++++++++++++--- .../bpm/service/definition/BpmModelService.java | 8 ++++++++ .../service/definition/BpmModelServiceImpl.java | 8 ++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index d5d6fa77c4..4f7d7bf7ce 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -74,6 +74,7 @@ public interface ErrorCodeConstants { ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在"); ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); + ErrorCode CATEGORY_DELETE_FAIL_MODEL_USED = new ErrorCode(1_009_012_003, "删除失败,流程分类【{}】已被流程模型使用,请先删除对应的流程模型"); // ========== BPM 流程监听器 1-009-013-000 ========== ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在"); diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java index 8a48da15a4..42d399acd5 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java @@ -34,6 +34,9 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { @Resource private BpmCategoryMapper bpmCategoryMapper; + @Resource + private BpmModelService modelService; + @Override public Long createCategory(BpmCategorySaveReqVO createReqVO) { // 校验唯一 @@ -77,15 +80,22 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { @Override public void deleteCategory(Long id) { // 校验存在 - validateCategoryExists(id); + BpmCategoryDO category = validateCategoryExists(id); + // 校验是否被流程模型使用 + Long count = modelService.getModelCountByCategory(category.getCode()); + if (count > 0) { + throw exception(CATEGORY_DELETE_FAIL_MODEL_USED, category.getName()); + } // 删除 bpmCategoryMapper.deleteById(id); } - private void validateCategoryExists(Long id) { - if (bpmCategoryMapper.selectById(id) == null) { + private BpmCategoryDO validateCategoryExists(Long id) { + BpmCategoryDO category = bpmCategoryMapper.selectById(id); + if (category == null) { throw exception(CATEGORY_NOT_EXISTS); } + return category; } @Override diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java index 5601bcda31..3273d24cbe 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -24,6 +24,14 @@ public interface BpmModelService { */ List getModelList(String name); + /** + * 根据分类编码获得流程模型数量 + * + * @param category 分类编码 + * @return 流程模型数量 + */ + Long getModelCountByCategory(String category); + /** * 创建流程模型 * diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index e8e90006f8..c23ea9ce8f 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -88,6 +88,14 @@ public class BpmModelServiceImpl implements BpmModelService { return modelQuery.list(); } + @Override + public Long getModelCountByCategory(String category) { + return repositoryService.createModelQuery() + .modelCategory(category) + .modelTenantId(FlowableUtils.getTenantId()) + .count(); + } + @Override @Transactional(rollbackFor = Exception.class) public String createModel(@Valid BpmModelSaveReqVO createReqVO) { From fb6771aad0425df1cd23245a6001929de046e23d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 21 Jul 2025 19:45:30 +0800 Subject: [PATCH 08/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90MALL=20=E5=95=86?= =?UTF-8?q?=E5=9F=8E=E3=80=91=E7=A7=92=E6=9D=80=E6=97=B6=E9=97=B4=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/service/seckill/SeckillActivityServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java index dcc5596f25..3c84a172ab 100644 --- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -303,7 +303,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); } SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig(); - if (config == null || !CollectionUtil.contains(activity.getConfigIds(), config.getId())) { + if (config == null + || !CollectionUtil.contains(activity.getConfigIds(), config.getId()) + || !LocalDateTimeUtils.isBetween(config.getStartTime(), config.getEndTime())) { throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); } // 1.3 超过单次购买限制 From 7ba084bc4dfafeb0475ef04a4e1b9e7deef3abf6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 22 Jul 2025 12:26:08 +0800 Subject: [PATCH 09/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=AD=90=E6=B5=81=E7=A8=8B=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=9A=84=20processInstanceId=20=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/task/vo/instance/BpmApprovalDetailRespVO.java | 2 +- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java index 38c2bc1013..0a785b10f4 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java @@ -73,7 +73,7 @@ public class BpmApprovalDetailRespVO { private List candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表 @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf") - private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段) + private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 calledProcessInstanceId 字段) } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index a42a3ecd4b..d056e4dbd8 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -244,7 +244,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService if (historicProcessInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); } - // 1.3 校验BpmnModel + // 1.3 校验 BpmnModel BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(task.getProcessDefinitionId()); if (bpmnModel == null) { return null; @@ -449,7 +449,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) .setStartTime(DateUtils.of(activity.getStartTime())) .setEndTime(DateUtils.of(activity.getEndTime())) - .setProcessInstanceId(activity.getProcessInstanceId()); + .setProcessInstanceId(activity.getCalledProcessInstanceId()); approvalNodes.add(callActivity); } }); @@ -521,7 +521,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { - activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId()); + activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId()); } return activityNode; }); From b766f8d820a13ec12a25f02485570b7e50a10df2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 22 Jul 2025 20:15:52 +0800 Subject: [PATCH 10/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=AD=90=E6=B5=81=E7=A8=8B=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=B5=81=E7=A8=8B=20title=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BpmProcessInstanceEventListener.java | 17 +- .../task/BpmProcessInstanceServiceImpl.java | 161 ++++++++++-------- 2 files changed, 104 insertions(+), 74 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java index ba2aaa6bcb..3deb545fa8 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; +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.ImmutableSet; import jakarta.annotation.Resource; @@ -37,18 +38,26 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent @Override protected void processCreated(FlowableEngineEntityEvent event) { - processInstanceService.processProcessInstanceCreated((ProcessInstance)event.getEntity()); + ProcessInstance processInstance = (ProcessInstance) event.getEntity(); + FlowableUtils.execute(processInstance.getTenantId(), + () -> processInstanceService.processProcessInstanceCreated(processInstance)); } @Override protected void processCompleted(FlowableEngineEntityEvent event) { - processInstanceService.processProcessInstanceCompleted((ProcessInstance)event.getEntity()); + ProcessInstance processInstance = (ProcessInstance) event.getEntity(); + FlowableUtils.execute(processInstance.getTenantId(), + () -> processInstanceService.processProcessInstanceCompleted(processInstance)); } - @Override // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法 + @Override protected void processCancelled(FlowableCancelledEvent event) { + // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法 ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getProcessInstanceId()); - processInstanceService.processProcessInstanceCompleted(processInstance); + if (processInstance != null) { + FlowableUtils.execute(processInstance.getTenantId(), + () -> processInstanceService.processProcessInstanceCompleted(processInstance)); + } } } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index d056e4dbd8..66fbaf79a3 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -4,10 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -61,6 +58,8 @@ import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.validation.annotation.Validated; import java.util.*; @@ -244,7 +243,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService if (historicProcessInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); } - // 1.3 校验 BpmnModel + // 1.3 校验BpmnModel BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(task.getProcessDefinitionId()); if (bpmnModel == null) { return null; @@ -449,7 +448,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) .setStartTime(DateUtils.of(activity.getStartTime())) .setEndTime(DateUtils.of(activity.getEndTime())) - .setProcessInstanceId(activity.getCalledProcessInstanceId()); + .setProcessInstanceId(activity.getProcessInstanceId()); approvalNodes.add(callActivity); } }); @@ -521,7 +520,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { - activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId()); + activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId()); } return activityNode; }); @@ -771,17 +770,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule)); } // 3.2 流程名称 - BpmModelMetaInfoVO.TitleSetting titleSetting = processDefinitionInfo.getTitleSetting(); - if (titleSetting != null && Boolean.TRUE.equals(titleSetting.getEnable())) { - AdminUserRespDTO user = adminUserApi.getUser(userId); - Map cloneVariables = new HashMap<>(variables); - cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname()); - cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now()); - cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim()); - processInstanceBuilder.name(StrUtil.format(titleSetting.getTitle(), cloneVariables)); - } else { - processInstanceBuilder.name(definition.getName().trim()); - } + processInstanceBuilder.name(generateProcessInstanceName(userId, definition, processDefinitionInfo, variables)); // 3.3 发起流程实例 ProcessInstance instance = processInstanceBuilder.start(); return instance.getId(); @@ -817,6 +806,25 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService }); } + private String generateProcessInstanceName(Long userId, + ProcessDefinition definition, + BpmProcessDefinitionInfoDO definitionInfo, + Map variables) { + if (definition == null || definitionInfo == null) { + return null; + } + BpmModelMetaInfoVO.TitleSetting titleSetting = definitionInfo.getTitleSetting(); + if (titleSetting == null || !BooleanUtil.isTrue(titleSetting.getEnable())) { + return definition.getName(); + } + AdminUserRespDTO user = adminUserApi.getUser(userId); + Map cloneVariables = new HashMap<>(variables); + cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname()); + cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now()); + cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim()); + return StrUtil.format(definitionInfo.getTitleSetting().getTitle(), cloneVariables); + } + @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 @@ -833,7 +841,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService .getProcessDefinitionInfo(instance.getProcessDefinitionId()); Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo); if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消 - && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) { + && BooleanUtil.isFalse(processDefinitionInfo.getAllowCancelRunningProcess())) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW); } // 1.4 子流程不允许取消 @@ -900,64 +908,77 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @Override public void processProcessInstanceCompleted(ProcessInstance instance) { - // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 - FlowableUtils.execute(instance.getTenantId(), () -> { - // 1.1 获取当前状态 - Integer status = (Integer) instance.getProcessVariables() - .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); - String reason = (String) instance.getProcessVariables() - .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); - // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 - // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 - if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { - status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); - runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, - status); + // 1.1 获取当前状态 + Integer status = (Integer) instance.getProcessVariables() + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); + String reason = (String) instance.getProcessVariables() + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); + // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 + // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { + status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); + runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, + status); + } + + // 2. 发送对应的消息通知 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { + messageService.sendMessageWhenProcessInstanceApprove( + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); + } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { + messageService.sendMessageWhenProcessInstanceReject( + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); + } + + // 3. 发送流程实例的状态事件 + processInstanceEventPublisher.sendProcessInstanceResultEvent( + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); + + // 4. 流程后置通知 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. + getProcessDefinitionInfo(instance.getProcessDefinitionId()); + if (ObjUtil.isNotNull(processDefinitionInfo) && + ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) { + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting(); + + BpmHttpRequestUtils.executeBpmHttpRequest(instance, + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } - - // 2. 发送对应的消息通知 - if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { - messageService.sendMessageWhenProcessInstanceApprove( - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); - } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { - messageService.sendMessageWhenProcessInstanceReject( - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); - } - - // 3. 发送流程实例的状态事件 - processInstanceEventPublisher.sendProcessInstanceResultEvent( - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); - - // 4. 流程后置通知 - if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. - getProcessDefinitionInfo(instance.getProcessDefinitionId()); - if (ObjUtil.isNotNull(processDefinitionInfo) && - ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) { - BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting(); - - BpmHttpRequestUtils.executeBpmHttpRequest(instance, - setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); - } - } - }); + } } @Override public void processProcessInstanceCreated(ProcessInstance instance) { - // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 - FlowableUtils.execute(instance.getTenantId(), () -> { - // 流程前置通知 - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. - getProcessDefinitionInfo(instance.getProcessDefinitionId()); - if (ObjUtil.isNull(processDefinitionInfo) || - ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { - return; + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. + getProcessDefinitionInfo(instance.getProcessDefinitionId()); + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId()); + if (processDefinition == null || processDefinitionInfo == null) { + return; + } + + // 自定义标题。目的:主要处理子流程的标题无法处理 + // 注意:必须使用 TransactionSynchronizationManager 事务提交后,否则不生效!!! + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + String name = generateProcessInstanceName(Long.valueOf(instance.getStartUserId()), + processDefinition, processDefinitionInfo, instance.getProcessVariables()); + if (ObjUtil.notEqual(instance.getName(), name)) { + runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name); + } } - BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); - BpmHttpRequestUtils.executeBpmHttpRequest(instance, - setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); + }); + + // 流程前置通知 + if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { + return; + } + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); + BpmHttpRequestUtils.executeBpmHttpRequest(instance, + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } } From 989c4e4b88bc32e0eddab2d5c4fc969f51133b51 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 22 Jul 2025 21:57:01 +0800 Subject: [PATCH 11/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91bpmn=20subProcess=20=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=20userTask=20NPE=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowable/core/candidate/BpmTaskCandidateInvoker.java | 7 ++----- .../bpm/framework/flowable/core/util/BpmnModelUtils.java | 6 +++++- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java index 7f66b29d3b..df8b0d5fd5 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -18,10 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.CallActivity; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.UserTask; +import org.flowable.bpmn.model.*; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; @@ -132,7 +129,7 @@ public class BpmTaskCandidateInvoker { Long startUserId, String processDefinitionId, Map processVariables) { // 如果是 CallActivity 子流程,不进行计算候选人 FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); - if (flowElement instanceof CallActivity) { + if (flowElement instanceof CallActivity || flowElement instanceof SubProcess) { return new HashSet<>(); } // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过 diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 1cccf18f04..460af124f6 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -478,7 +478,11 @@ public class BpmnModelUtils { */ public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { Process process = model.getMainProcess(); - return process.getFlowElement(flowElementId); + FlowElement flowElement = process.getFlowElement(flowElementId); + if (flowElement != null) { + return flowElement; + } + return model.getFlowElement(flowElementId); } /** diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 1f7e699032..942a50669a 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -1379,7 +1379,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); if (userTaskElement.getId().equals(START_USER_NODE_ID) && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 - || Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 + || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); From 376114a8741ad134ea13396c777ee176d07fddf6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 22 Jul 2025 23:59:20 +0800 Subject: [PATCH 12/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E4=BF=AE=E5=A4=8D=E5=AD=90=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=8F=91=E8=B5=B7=E4=BA=BA=E4=B8=BA=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=97=B6=E5=AE=9E=E9=99=85=E5=8F=91=E8=B5=B7=E4=BA=BA=E4=BC=9A?= =?UTF-8?q?=E5=8F=98=E6=88=90=E4=B8=BB=E6=B5=81=E7=A8=8B=E5=8F=91=E8=B5=B7?= =?UTF-8?q?=E4=BA=BA=20https://gitee.com/zhijiantianya/yudao-cloud/issues/?= =?UTF-8?q?ICNHA8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/task/BpmProcessInstanceServiceImpl.java | 4 ++-- .../task/listener/BpmCallActivityListener.java | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 66fbaf79a3..9ce877b67c 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -448,7 +448,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) .setStartTime(DateUtils.of(activity.getStartTime())) .setEndTime(DateUtils.of(activity.getEndTime())) - .setProcessInstanceId(activity.getProcessInstanceId()); + .setProcessInstanceId(activity.getCalledProcessInstanceId()); approvalNodes.add(callActivity); } }); @@ -520,7 +520,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { - activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId()); + activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId()); } return activityNode; }); diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java index 40313a9663..da148a8562 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java @@ -85,10 +85,15 @@ public class BpmCallActivityListener implements ExecutionListener { // 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人 try { FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue)); - } catch (Exception e) { - log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", - DELEGATE_EXPRESSION, formFieldValue); - FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); + } catch (NumberFormatException ex) { + try { + List formFieldValues = JsonUtils.parseArray(formFieldValue, Long.class); + FlowableUtils.setAuthenticatedUserId(formFieldValues.get(0)); + } catch (Exception e) { + log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", + DELEGATE_EXPRESSION, formFieldValue); + FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); + } } } } From a4244ab9996f2e8f9951ed4a495dc7e027f862be Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 23 Jul 2025 12:46:00 +0800 Subject: [PATCH 13/16] =?UTF-8?q?fix=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=AD=98=E5=9C=A8=E5=8A=A0=E7=AD=BE?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E9=80=80=E5=9B=9E=E6=8A=A5=20Execution=20cou?= =?UTF-8?q?ld=20not=20be=20found=20with=20id=20null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 942a50669a..1dbd0b17c0 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -898,7 +898,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { return; } - runExecutionIds.add(task.getExecutionId()); + if (task.getExecutionId() != null) { + runExecutionIds.add(task.getExecutionId()); + } // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 From 97cec2897b85c9afddc6f52c93118c23817c379e Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Thu, 24 Jul 2025 22:23:15 +0800 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20[BPM=20=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81]=20=E5=B9=B6=E8=A1=8C=E5=88=86=E6=94=AF=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8C=85=E5=AE=B9=E7=BD=91=E5=85=B3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BpmSimpleModelNodeTypeEnum.java | 2 +- .../flowable/core/util/SimpleModelUtils.java | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java index e5ffa12025..d97c145c3f 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java @@ -35,7 +35,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable { // 50 ~ 条件分支 CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), - PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), + PARALLEL_BRANCH_NODE(52, "并行分支", "inclusiveGateway"), // 并行分支使用包容网关实现,条件表达式结果设置为 true INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway") ; diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index c9f3ff6fcb..5e9313840b 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -239,13 +239,13 @@ public class SimpleModelUtils { // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 if (isValidNode(conditionChildNode)) { // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), nodeType, item); process.addFlowElement(sequenceFlow); // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); } else { // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, nodeType, item); process.addFlowElement(sequenceFlow); } } @@ -591,17 +591,22 @@ public class SimpleModelUtils { private static class ParallelBranchNodeConvert implements NodeConvert { + /** + * 并行分支使用包容网关。需要设置所有出口条件表达式的值为 true. + * 参见: {@link ConditionNodeConvert#buildSequenceFlow} + */ @Override - public List convertList(BpmSimpleModelNodeVO node) { - ParallelGateway parallelGateway = new ParallelGateway(); - parallelGateway.setId(node.getId()); + public List convertList(BpmSimpleModelNodeVO node) { + + InclusiveGateway inclusiveGateway = new InclusiveGateway(); + inclusiveGateway.setId(node.getId()); // TODO @jason:setName - // 并行聚合网关由程序创建,前端不需要传入 - ParallelGateway joinParallelGateway = new ParallelGateway(); + // 合并网关 由程序创建,前端不需要传入 + InclusiveGateway joinParallelGateway = new InclusiveGateway(); joinParallelGateway.setId(buildGatewayJoinId(node.getId())); // TODO @jason:setName - return CollUtil.newArrayList(parallelGateway, joinParallelGateway); + return CollUtil.newArrayList(inclusiveGateway, joinParallelGateway); } @Override @@ -652,8 +657,14 @@ public class SimpleModelUtils { } public static SequenceFlow buildSequenceFlow(String sourceId, String targetId, - BpmSimpleModelNodeVO node) { - String conditionExpression = buildConditionExpression(node.getConditionSetting()); + BpmSimpleModelNodeTypeEnum nodeType, BpmSimpleModelNodeVO node) { + String conditionExpression; + // 并行分支,使用包容网关实现,强制设置条件表达式为 true + if (BpmSimpleModelNodeTypeEnum.PARALLEL_BRANCH_NODE == nodeType) { + conditionExpression ="${true}"; + } else { + conditionExpression = buildConditionExpression(node.getConditionSetting()); + } return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression); } } @@ -662,7 +673,6 @@ public class SimpleModelUtils { * 构造条件表达式 */ public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { - // 并行网关不需要设置条件 if (conditionSetting == null) { return null; } From 76d8906748839807cc50261bcb79b09a73aadca8 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Thu, 24 Jul 2025 23:07:15 +0800 Subject: [PATCH 15/16] =?UTF-8?q?fix:=20[BPM=20=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?]=20=E8=8E=B7=E5=8F=96=E4=B8=8B=E4=B8=AA=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=8A=82=E7=82=B9=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 9ce877b67c..85d15a6327 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; @@ -66,6 +67,7 @@ import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; @@ -263,7 +265,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 3. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); List nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); - List nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId()) + // 仅仅获取 UserTask 节点 TODO:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。 + List nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask); + List nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId()) .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) From 4347f1336299664693f77f1a7aa3129f59a3d53b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 25 Jul 2025 20:18:33 +0800 Subject: [PATCH 16/16] =?UTF-8?q?review=EF=BC=9A=E3=80=90BPM=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=B9=B6=E8=A1=8C=E5=88=86=E6=94=AF?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=8C=85=E5=AE=B9=E7=BD=91=E5=85=B3=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20=3D=E3=80=8B=E8=A1=A5=E5=85=85=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/framework/flowable/core/util/SimpleModelUtils.java | 5 +++-- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index 5e9313840b..f3c00258e5 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -592,8 +592,9 @@ public class SimpleModelUtils { private static class ParallelBranchNodeConvert implements NodeConvert { /** - * 并行分支使用包容网关。需要设置所有出口条件表达式的值为 true. - * 参见: {@link ConditionNodeConvert#buildSequenceFlow} + * 并行分支使用包容网关。需要设置所有出口条件表达式的值为 true 。原因是,解决 https://t.zsxq.com/m6GXh 反馈问题 + * + * @see {@link ConditionNodeConvert#buildSequenceFlow} */ @Override public List convertList(BpmSimpleModelNodeVO node) { diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 85d15a6327..47265f5c72 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -265,7 +265,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 3. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); List nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); - // 仅仅获取 UserTask 节点 TODO:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。 + // 仅仅获取 UserTask 节点 TODO add from jason:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。 List nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask); List nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId()) .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())