Commit 1f2222cf83934529cc5cd576ce8af5b417d668c6

Authored by jason
2 parents 9a4bb60a a4e09038

Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java
... ... @@ -25,6 +25,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> {
25 25 START_USER_NODE(10, "发起人", "userTask"), // 发起人节点。前端的开始节点,Id 固定
26 26 APPROVE_NODE(11, "审批人", "userTask"),
27 27 COPY_NODE(12, "抄送人", "serviceTask"),
  28 + TRANSACTOR_NODE(13, "办理人", "userTask"),
28 29  
29 30 DELAY_TIMER_NODE(14, "延迟器", "receiveTask"),
30 31 TRIGGER_NODE(15, "触发器", "serviceTask"),
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java
1 1 package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
2 2  
3   -import cn.iocoder.yudao.framework.common.core.KeyValue;
4 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 4 import cn.iocoder.yudao.module.bpm.enums.definition.BpmAutoApproveTypeEnum;
6 5 import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
... ... @@ -27,8 +26,7 @@ import java.util.List;
27 26 @Data
28 27 public class BpmModelMetaInfoVO {
29 28  
30   - @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg")
31   - @NotEmpty(message = "流程图标不能为空")
  29 + @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg")
32 30 @URL(message = "流程图标格式不正确")
33 31 private String icon;
34 32  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java
... ... @@ -85,6 +85,9 @@ public class BpmTaskRespVO {
85 85 @Schema(description = "是否填写审批意见", example = "false")
86 86 private Boolean reasonRequire;
87 87  
  88 + @Schema(description = "节点类型", example = "10")
  89 + private Integer nodeType; // 参见 BpmSimpleModelNodeTypeEnum 枚举。
  90 +
88 91 @Data
89 92 @Schema(description = "流程实例")
90 93 public static class ProcessInstance {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums;
2 2  
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
  4 +
3 5 /**
4 6 * BPMN XML 常量信息
5 7 *
... ... @@ -129,4 +131,11 @@ public interface BpmnModelConstants {
129 131 */
130 132 String REASON_REQUIRE = "reasonRequire";
131 133  
  134 + /**
  135 + * 节点类型
  136 + *
  137 + * 目前只有 {@link BpmModelTypeEnum#SIMPLE} 的 UserTask 节点会设置该属性,用于区分是审批节点、还是办理节点
  138 + */
  139 + String NODE_TYPE = "nodeType";
  140 +
132 141 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
... ... @@ -410,6 +410,26 @@ public class BpmnModelUtils {
410 410 return parseExtensionElement(flowElement, TRIGGER_PARAM);
411 411 }
412 412  
  413 + /**
  414 + * 给节点添加节点类型
  415 + *
  416 + * @param nodeType 节点类型
  417 + * @param flowElement 节点
  418 + */
  419 + public static void addNodeType(Integer nodeType, FlowElement flowElement) {
  420 + addExtensionElement(flowElement, BpmnModelConstants.NODE_TYPE, nodeType);
  421 + }
  422 +
  423 + /**
  424 + * 解析节点类型
  425 + *
  426 + * @param flowElement 节点
  427 + * @return 节点类型
  428 + */
  429 + public static Integer parseNodeType(FlowElement flowElement) {
  430 + return NumberUtils.parseInt(parseExtensionElement(flowElement, BpmnModelConstants.NODE_TYPE));
  431 + }
  432 +
413 433 // ========== BPM 简单查找相关的方法 ==========
414 434  
415 435 /**
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
... ... @@ -40,7 +40,7 @@ public class SimpleModelUtils {
40 40  
41 41 static {
42 42 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
43   - new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
  43 + new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(),
44 44 new DelayTimerNodeConvert(), new TriggerNodeConvert(),
45 45 new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert());
46 46 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
... ... @@ -445,6 +445,8 @@ public class SimpleModelUtils {
445 445 addSignEnable(node.getSignEnable(), userTask);
446 446 // 审批意见
447 447 addReasonRequire(node.getReasonRequire(), userTask);
  448 + // 节点类型
  449 + addNodeType(node.getType(), userTask);
448 450 return userTask;
449 451 }
450 452  
... ... @@ -514,6 +516,15 @@ public class SimpleModelUtils {
514 516  
515 517 }
516 518  
  519 + private static class TransactorNodeConvert extends ApproveNodeConvert {
  520 +
  521 + @Override
  522 + public BpmSimpleModelNodeTypeEnum getType() {
  523 + return BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE;
  524 + }
  525 +
  526 + }
  527 +
517 528 private static class CopyNodeConvert implements NodeConvert {
518 529  
519 530 @Override
... ... @@ -785,10 +796,11 @@ public class SimpleModelUtils {
785 796 BpmSimpleModelNodeTypeEnum nodeType = BpmSimpleModelNodeTypeEnum.valueOf(currentNode.getType());
786 797 Assert.notNull(nodeType, "模型节点类型不支持");
787 798  
788   - // 情况:START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE
  799 + // 情况:START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE/TRANSACTOR_NODE
789 800 if (nodeType == BpmSimpleModelNodeTypeEnum.START_NODE
790 801 || nodeType == BpmSimpleModelNodeTypeEnum.START_USER_NODE
791 802 || nodeType == BpmSimpleModelNodeTypeEnum.APPROVE_NODE
  803 + || nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE
792 804 || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE
793 805 || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) {
794 806 // 添加元素
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
... ... @@ -28,8 +28,7 @@ import java.util.*;
28 28  
29 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull;
31   -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH;
32   -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH;
  31 +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
33 32 import static java.util.Collections.emptyList;
34 33  
35 34 /**
... ... @@ -156,16 +155,25 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
156 155  
157 156 @Override
158 157 public void updateProcessDefinitionState(String id, Integer state) {
  158 + ProcessDefinition processDefinition = repositoryService.getProcessDefinition(id);
  159 + if (processDefinition == null) {
  160 + throw exception(PROCESS_DEFINITION_NOT_EXISTS);
  161 + }
  162 +
159 163 // 激活
160 164 if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
161   - repositoryService.activateProcessDefinitionById(id, false, null);
  165 + if (processDefinition.isSuspended()) {
  166 + repositoryService.activateProcessDefinitionById(id, false, null);
  167 + }
162 168 return;
163 169 }
164 170 // 挂起
165 171 if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
166 172 // suspendProcessInstances = false,进行中的任务,不进行挂起。
167 173 // 原因:只要新的流程不允许发起即可,老流程继续可以执行。
168   - repositoryService.suspendProcessDefinitionById(id, false, null);
  174 + if (!processDefinition.isSuspended()) {
  175 + repositoryService.suspendProcessDefinitionById(id, false, null);
  176 + }
169 177 return;
170 178 }
171 179 log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil;
5 5 import cn.hutool.core.date.DateUtil;
6 6 import cn.hutool.core.lang.Assert;
7 7 import cn.hutool.core.util.ArrayUtil;
  8 +import cn.hutool.core.util.ObjUtil;
8 9 import cn.hutool.core.util.ObjectUtil;
9 10 import cn.hutool.core.util.StrUtil;
10 11 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -67,6 +68,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
67 68 import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode;
68 69 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
69 70 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
  71 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseNodeType;
70 72 import static java.util.Arrays.asList;
71 73 import static java.util.Collections.singletonList;
72 74 import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
... ... @@ -325,7 +327,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
325 327 ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName())
326 328 .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey())
327 329 ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()
328   - : BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
  330 + : ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别
  331 + BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()))
329 332 .setStatus(FlowableUtils.getTaskStatus(task))
330 333 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
331 334 .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime()))
... ... @@ -402,7 +405,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
402 405 HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同
403 406 ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId())
404 407 .setName(firstActivity.getActivityName())
405   - .setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
  408 + .setNodeType(ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的:解决“办理节点”的识别
  409 + BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()))
406 410 .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
407 411 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
408 412 .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime()))
... ... @@ -479,7 +483,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
479 483 // 1. 开始节点/审批节点
480 484 if (ObjectUtils.equalsAny(node.getType(),
481 485 BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType(),
482   - BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) {
  486 + BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType(),
  487 + BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE.getType())) {
483 488 List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
484 489 startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables);
485 490 activityNode.setCandidateUserIds(candidateUserIds);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -61,6 +61,7 @@ import java.util.stream.Stream;
61 61 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
62 62 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
63 63 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
  64 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
64 65 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG;
65 66 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
66 67  
... ... @@ -162,6 +163,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
162 163 bpmnModel, todoTask.getTaskDefinitionKey());
163 164 Boolean signEnable = parseSignEnable(bpmnModel, todoTask.getTaskDefinitionKey());
164 165 Boolean reasonRequire = parseReasonRequire(bpmnModel, todoTask.getTaskDefinitionKey());
  166 + Integer nodeType = parseNodeType(BpmnModelUtils.getFlowElementById(bpmnModel, todoTask.getTaskDefinitionKey()));
165 167  
166 168 // 4. 任务表单
167 169 BpmFormDO taskForm = null;
... ... @@ -170,8 +172,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
170 172 }
171 173  
172 174 return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm)
173   - .setSignEnable(signEnable)
174   - .setReasonRequire(reasonRequire);
  175 + .setNodeType(nodeType).setSignEnable(signEnable).setReasonRequire(reasonRequire);
175 176 }
176 177  
177 178 @Override
... ... @@ -194,6 +195,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
194 195 return PageResult.empty();
195 196 }
196 197 List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
  198 +
  199 + // 特殊:强制移除自动完成的“发起人”节点
  200 + // 补充说明:由于 taskQuery 无法方面的过滤,所以暂时通过内存过滤
  201 + tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID));
197 202 return new PageResult<>(tasks, count);
198 203 }
199 204  
... ...