Commit 9456d461f9337c6cc590d0201c31501ca9a4074b
1 parent
1e97ca28
仿钉钉流程设计- code review 修改。扩展属性保存在 extensionElement 尝试
Showing
6 changed files
with
318 additions
and
273 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
| @@ -18,20 +18,17 @@ import java.util.Objects; | @@ -18,20 +18,17 @@ import java.util.Objects; | ||
| 18 | public enum BpmSimpleModelNodeType implements IntArrayValuable { | 18 | public enum BpmSimpleModelNodeType implements IntArrayValuable { |
| 19 | 19 | ||
| 20 | // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; | 20 | // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; |
| 21 | - // TODO @jason:_NODE 都删除掉哈; | ||
| 22 | - START_EVENT_NODE(0, "开始节点"), | ||
| 23 | - END_EVENT_NODE(-2, "结束节点"), // TODO @jaosn:挪到 START_EVENT_NODE 后; | ||
| 24 | - | ||
| 25 | - APPROVE_USER_NODE(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件;TODO @jason:改成 USER_TASK 是不是好点呀 | ||
| 26 | - // 抄送人节点、对应 BPMN 的 ScriptTask. 使用ScriptTask 原因。好像 ServiceTask 自定义属性不能写入 XML; | ||
| 27 | - // TODO @jason:ServiceTask 自定义 xml,有没啥报错信息; | ||
| 28 | - SCRIPT_TASK_NODE(2, "抄送人节点"), // TODO @jason:是不是改成 COPY_TASK 好一点哈; | ||
| 29 | - | ||
| 30 | - EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), // TODO @jason:是不是改成叫 条件分支? | ||
| 31 | - PARALLEL_GATEWAY_FORK_NODE(5, "并行网关分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? | ||
| 32 | - PARALLEL_GATEWAY_JOIN_NODE(6, "并行网关聚合节点"), | ||
| 33 | - INCLUSIVE_GATEWAY_FORK_NODE(7, "包容网关分叉节点"), | ||
| 34 | - INCLUSIVE_GATEWAY_JOIN_NODE(8, "包容网关聚合节点"), | 21 | + START_EVENT(0, "开始节点"), |
| 22 | + END_EVENT(-2, "结束节点"), // TODO @jaosn:挪到 START_EVENT_NODE 后; | ||
| 23 | + | ||
| 24 | + USER_TASK(1, "审批人节点"), // TODO @jaosn:是不是这里从 10 开始好点;相当于说,0-9 给开始和结束;10-19 给各种节点;20-29 给各种条件; TODO 后面改改 | ||
| 25 | + COPY_TASK(2, "抄送人节点"), | ||
| 26 | + | ||
| 27 | + EXCLUSIVE_GATEWAY(4, "排他网关"), // TODO @jason:是不是改成叫 条件分支? | ||
| 28 | + PARALLEL_GATEWAY_FORK(5, "并行网关分叉节点"), // TODO @jason:是不是一个 并行分支 ?就可以啦? 后面是否去掉并行网关。只用包容网关 | ||
| 29 | + PARALLEL_GATEWAY_JOIN(6, "并行网关聚合节点"), | ||
| 30 | + INCLUSIVE_GATEWAY_FORK(7, "包容网关分叉节点"), | ||
| 31 | + INCLUSIVE_GATEWAY_JOIN(8, "包容网关聚合节点"), | ||
| 35 | ; | 32 | ; |
| 36 | 33 | ||
| 37 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); | 34 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); |
| @@ -39,9 +36,13 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | @@ -39,9 +36,13 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | ||
| 39 | private final Integer type; | 36 | private final Integer type; |
| 40 | private final String name; | 37 | private final String name; |
| 41 | 38 | ||
| 42 | - public static boolean isGatewayNode(Integer type) { | ||
| 43 | - return Objects.equals(EXCLUSIVE_GATEWAY_NODE.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK_NODE.getType(), type) | ||
| 44 | - || Objects.equals(INCLUSIVE_GATEWAY_FORK_NODE.getType(), type) ; | 39 | + /** |
| 40 | + * 判断是否为分支节点 | ||
| 41 | + * @param type 节点类型 | ||
| 42 | + */ | ||
| 43 | + public static boolean isBranchNode(Integer type) { | ||
| 44 | + return Objects.equals(EXCLUSIVE_GATEWAY.getType(), type) || Objects.equals(PARALLEL_GATEWAY_FORK.getType(), type) | ||
| 45 | + || Objects.equals(INCLUSIVE_GATEWAY_FORK.getType(), type) ; | ||
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | public static BpmSimpleModelNodeType valueOf(Integer type) { | 48 | public static BpmSimpleModelNodeType valueOf(Integer type) { |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.lang.Assert; | ||
| 5 | -import cn.hutool.core.map.MapUtil; | ||
| 6 | import cn.hutool.core.util.ArrayUtil; | 4 | import cn.hutool.core.util.ArrayUtil; |
| 7 | -import cn.hutool.core.util.StrUtil; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 5 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 9 | -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; | ||
| 10 | -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; | ||
| 11 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; |
| 12 | -import org.flowable.bpmn.BpmnAutoLayout; | ||
| 13 | import org.flowable.bpmn.converter.BpmnXMLConverter; | 7 | import org.flowable.bpmn.converter.BpmnXMLConverter; |
| 14 | import org.flowable.bpmn.model.Process; | 8 | import org.flowable.bpmn.model.Process; |
| 15 | import org.flowable.bpmn.model.*; | 9 | import org.flowable.bpmn.model.*; |
| 16 | -import org.flowable.common.engine.impl.scripting.ScriptingEngines; | ||
| 17 | import org.flowable.common.engine.impl.util.io.BytesStreamSource; | 10 | import org.flowable.common.engine.impl.util.io.BytesStreamSource; |
| 18 | 11 | ||
| 19 | -import java.util.ArrayList; | ||
| 20 | -import java.util.HashSet; | ||
| 21 | -import java.util.List; | ||
| 22 | -import java.util.Set; | ||
| 23 | - | ||
| 24 | -import static org.flowable.bpmn.constants.BpmnXMLConstants.*; | 12 | +import java.util.*; |
| 25 | 13 | ||
| 26 | /** | 14 | /** |
| 27 | * 流程模型转操作工具类 | 15 | * 流程模型转操作工具类 |
| 28 | */ | 16 | */ |
| 29 | public class BpmnModelUtils { | 17 | public class BpmnModelUtils { |
| 30 | 18 | ||
| 31 | - public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; | ||
| 32 | - | ||
| 33 | public static Integer parseCandidateStrategy(FlowElement userTask) { | 19 | public static Integer parseCandidateStrategy(FlowElement userTask) { |
| 34 | - return NumberUtils.parseInt(userTask.getAttributeValue( | 20 | + Integer candidateStrategy = NumberUtils.parseInt(userTask.getAttributeValue( |
| 35 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); | 21 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); |
| 22 | + // @芋艿 尝试从 ExtensionElement 取. 后续相关扩展是否都可以 存 extensionElement。 如表单权限。 按钮权限 | ||
| 23 | + if (candidateStrategy == null) { | ||
| 24 | + ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); | ||
| 25 | + candidateStrategy = NumberUtils.parseInt(Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null)); | ||
| 26 | + | ||
| 27 | + } | ||
| 28 | + return candidateStrategy; | ||
| 36 | } | 29 | } |
| 37 | 30 | ||
| 38 | public static String parseCandidateParam(FlowElement userTask) { | 31 | public static String parseCandidateParam(FlowElement userTask) { |
| 39 | - return userTask.getAttributeValue( | 32 | + String candidateParam = userTask.getAttributeValue( |
| 40 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); | 33 | BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); |
| 34 | + if (candidateParam == null) { | ||
| 35 | + ExtensionElement element = CollUtil.getFirst(userTask.getExtensionElements().get(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); | ||
| 36 | + candidateParam = Optional.ofNullable(element).map(ExtensionElement::getElementText).orElse(null); | ||
| 37 | + } | ||
| 38 | + return candidateParam; | ||
| 41 | } | 39 | } |
| 42 | 40 | ||
| 43 | /** | 41 | /** |
| @@ -339,231 +337,4 @@ public class BpmnModelUtils { | @@ -339,231 +337,4 @@ public class BpmnModelUtils { | ||
| 339 | } | 337 | } |
| 340 | return userTaskList; | 338 | return userTaskList; |
| 341 | } | 339 | } |
| 342 | - | ||
| 343 | - // ========== TODO @jason:单独出一个 SimpleModelUtils;定位上,它是 BPMN 的精简模式 ========== | ||
| 344 | - | ||
| 345 | - /** | ||
| 346 | - * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) | ||
| 347 | - * | ||
| 348 | - * @param processId 流程标识 | ||
| 349 | - * @param processName 流程名称 | ||
| 350 | - * @param simpleModelNode 仿钉钉流程设计模型数据结构 | ||
| 351 | - * @return Bpmn Model | ||
| 352 | - */ | ||
| 353 | - public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { | ||
| 354 | - BpmnModel bpmnModel = new BpmnModel(); | ||
| 355 | - Process mainProcess = new Process(); | ||
| 356 | - mainProcess.setId(processId); | ||
| 357 | - mainProcess.setName(processName); | ||
| 358 | - mainProcess.setExecutable(Boolean.TRUE); | ||
| 359 | - bpmnModel.addProcess(mainProcess); | ||
| 360 | - // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。 | ||
| 361 | - // 添加 FlowNode | ||
| 362 | - addBpmnFlowNode(mainProcess, simpleModelNode); | ||
| 363 | - // 单独添加 end event 节点 | ||
| 364 | - addBpmnEndEventNode(mainProcess); | ||
| 365 | - // 添加节点之间的连线 Sequence Flow | ||
| 366 | - addBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID); | ||
| 367 | - // 自动布局 | ||
| 368 | - new BpmnAutoLayout(bpmnModel).execute(); | ||
| 369 | - return bpmnModel; | ||
| 370 | - } | ||
| 371 | - | ||
| 372 | - private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String endId) { | ||
| 373 | - // 节点为 null 退出 | ||
| 374 | - if (node == null || node.getId() == null) { | ||
| 375 | - return; | ||
| 376 | - } | ||
| 377 | - BpmSimpleModelNodeVO childNode = node.getChildNode(); | ||
| 378 | - // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线 | ||
| 379 | - if (!BpmSimpleModelNodeType.isGatewayNode(node.getType()) && (childNode == null || childNode.getId() == null)) { | ||
| 380 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), endId, null, null); | ||
| 381 | - return; | ||
| 382 | - } | ||
| 383 | - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | ||
| 384 | - Assert.notNull(nodeType, "模型节点类型不支持"); | ||
| 385 | - // TODO @jason:建议是,addXXX 都改成 buildXXX,构建出一个什么;然后返回之后,让这个方法添加到自己的结果里; | ||
| 386 | - switch (nodeType) { | ||
| 387 | - case START_EVENT_NODE: | ||
| 388 | - case APPROVE_USER_NODE: | ||
| 389 | - case SCRIPT_TASK_NODE: | ||
| 390 | - case PARALLEL_GATEWAY_JOIN_NODE: | ||
| 391 | - case INCLUSIVE_GATEWAY_JOIN_NODE:{ | ||
| 392 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null); | ||
| 393 | - // 递归调用后续节点 | ||
| 394 | - addBpmnSequenceFlow(mainProcess, childNode, endId); | ||
| 395 | - break; | ||
| 396 | - } | ||
| 397 | - case PARALLEL_GATEWAY_FORK_NODE: | ||
| 398 | - case EXCLUSIVE_GATEWAY_NODE: | ||
| 399 | - case INCLUSIVE_GATEWAY_FORK_NODE:{ | ||
| 400 | - String gateWayEndId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); | ||
| 401 | - List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); | ||
| 402 | - Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); | ||
| 403 | - for (int i = 0; i < conditionNodes.size(); i++) { | ||
| 404 | - BpmSimpleModelNodeVO item = conditionNodes.get(i); | ||
| 405 | - BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); | ||
| 406 | - if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { | ||
| 407 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(), | ||
| 408 | - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); | ||
| 409 | - addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId); | ||
| 410 | - } else { | ||
| 411 | - addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId, | ||
| 412 | - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); | ||
| 413 | - } | ||
| 414 | - } | ||
| 415 | - // 递归调用后续节点 | ||
| 416 | - addBpmnSequenceFlow(mainProcess, childNode, endId); | ||
| 417 | - break; | ||
| 418 | - } | ||
| 419 | - default: { | ||
| 420 | - // TODO 其它节点类型的实现 | ||
| 421 | - } | ||
| 422 | - } | ||
| 423 | - | ||
| 424 | - } | ||
| 425 | - | ||
| 426 | - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) { | ||
| 427 | - SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); | ||
| 428 | - if (StrUtil.isNotEmpty(conditionExpression)) { | ||
| 429 | - sequenceFlow.setConditionExpression(conditionExpression); | ||
| 430 | - } | ||
| 431 | - if (StrUtil.isNotEmpty(seqFlowId)) { | ||
| 432 | - sequenceFlow.setId(seqFlowId); | ||
| 433 | - } | ||
| 434 | - mainProcess.addFlowElement(sequenceFlow); | ||
| 435 | - } | ||
| 436 | - | ||
| 437 | - private static void addBpmnFlowNode(Process mainProcess, BpmSimpleModelNodeVO simpleModelNode) { | ||
| 438 | - // 节点为 null 退出 | ||
| 439 | - if (simpleModelNode == null || simpleModelNode.getId() == null) { | ||
| 440 | - return; | ||
| 441 | - } | ||
| 442 | - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); | ||
| 443 | - Assert.notNull(nodeType, "模型节点类型不支持"); | ||
| 444 | - switch (nodeType) { | ||
| 445 | - case START_EVENT_NODE: | ||
| 446 | - addBpmnStartEventNode(mainProcess, simpleModelNode); | ||
| 447 | - break; | ||
| 448 | - case APPROVE_USER_NODE: | ||
| 449 | - addBpmnUserTaskNode(mainProcess, simpleModelNode); | ||
| 450 | - break; | ||
| 451 | - case SCRIPT_TASK_NODE: | ||
| 452 | - addBpmnScriptTaSskNode(mainProcess, simpleModelNode); | ||
| 453 | - break; | ||
| 454 | - case EXCLUSIVE_GATEWAY_NODE: | ||
| 455 | - addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode); | ||
| 456 | - break; | ||
| 457 | - case PARALLEL_GATEWAY_FORK_NODE: | ||
| 458 | - case PARALLEL_GATEWAY_JOIN_NODE: | ||
| 459 | - addBpmnParallelGatewayNode(mainProcess, simpleModelNode); | ||
| 460 | - break; | ||
| 461 | - case INCLUSIVE_GATEWAY_FORK_NODE: | ||
| 462 | - addBpmnInclusiveGatewayNode(mainProcess, simpleModelNode, Boolean.TRUE); | ||
| 463 | - break; | ||
| 464 | - case INCLUSIVE_GATEWAY_JOIN_NODE: | ||
| 465 | - addBpmnInclusiveGatewayNode(mainProcess, simpleModelNode, Boolean.FALSE); | ||
| 466 | - break; | ||
| 467 | - default: { | ||
| 468 | - // TODO 其它节点类型的实现 | ||
| 469 | - } | ||
| 470 | - } | ||
| 471 | - | ||
| 472 | - // 如果不是网关类型的接口, 并且chileNode为空退出 | ||
| 473 | - if (!BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { | ||
| 474 | - return; | ||
| 475 | - } | ||
| 476 | - | ||
| 477 | - // 如果是网关类型接口. 递归添加条件节点 | ||
| 478 | - if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { | ||
| 479 | - for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { | ||
| 480 | - addBpmnFlowNode(mainProcess, node.getChildNode()); | ||
| 481 | - } | ||
| 482 | - } | ||
| 483 | - | ||
| 484 | - // chileNode不为空,递归添加子节点 | ||
| 485 | - if (simpleModelNode.getChildNode() != null) { | ||
| 486 | - addBpmnFlowNode(mainProcess, simpleModelNode.getChildNode()); | ||
| 487 | - } | ||
| 488 | - } | ||
| 489 | - | ||
| 490 | - private static void addBpmnParallelGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) { | ||
| 491 | - ParallelGateway parallelGateway = new ParallelGateway(); | ||
| 492 | - parallelGateway.setId(node.getId()); | ||
| 493 | - mainProcess.addFlowElement(parallelGateway); | ||
| 494 | - } | ||
| 495 | - | ||
| 496 | - private static void addBpmnScriptTaSskNode(Process mainProcess, BpmSimpleModelNodeVO node) { | ||
| 497 | - ScriptTask scriptTask = new ScriptTask(); | ||
| 498 | - scriptTask.setId(node.getId()); | ||
| 499 | - scriptTask.setName(node.getName()); | ||
| 500 | - // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现; | ||
| 501 | - scriptTask.setScriptFormat(ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE); | ||
| 502 | - scriptTask.setScript(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT); | ||
| 503 | - // 添加自定义属性 | ||
| 504 | - // TODO @jason:可以使用 ServiceTask 搞 ExtensionAttribute 么? | ||
| 505 | - addExtensionAttributes(node, scriptTask); | ||
| 506 | - mainProcess.addFlowElement(scriptTask); | ||
| 507 | - } | ||
| 508 | - | ||
| 509 | - private static void addExtensionAttributes(BpmSimpleModelNodeVO node, FlowElement flowElement) { | ||
| 510 | - Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); | ||
| 511 | - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, | ||
| 512 | - candidateStrategy == null ? null : String.valueOf(candidateStrategy)); | ||
| 513 | - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, | ||
| 514 | - MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); | ||
| 515 | - } | ||
| 516 | - | ||
| 517 | - private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) { | ||
| 518 | - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | ||
| 519 | - ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); | ||
| 520 | - exclusiveGateway.setId(node.getId()); | ||
| 521 | - // 网关的最后一个条件为 网关的 default sequence flow | ||
| 522 | - exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | ||
| 523 | - mainProcess.addFlowElement(exclusiveGateway); | ||
| 524 | - } | ||
| 525 | - | ||
| 526 | - private static void addBpmnInclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node, Boolean isFork) { | ||
| 527 | - InclusiveGateway inclusiveGateway = new InclusiveGateway(); | ||
| 528 | - inclusiveGateway.setId(node.getId()); | ||
| 529 | - if (isFork) { | ||
| 530 | - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | ||
| 531 | - // 网关的最后一个条件为 网关的 default sequence flow | ||
| 532 | - inclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | ||
| 533 | - } | ||
| 534 | - mainProcess.addFlowElement(inclusiveGateway); | ||
| 535 | - } | ||
| 536 | - | ||
| 537 | - private static void addBpmnEndEventNode(Process mainProcess) { | ||
| 538 | - EndEvent endEvent = new EndEvent(); | ||
| 539 | - endEvent.setId(BpmnModelConstants.END_EVENT_ID); | ||
| 540 | - endEvent.setName("结束"); | ||
| 541 | - mainProcess.addFlowElement(endEvent); | ||
| 542 | - } | ||
| 543 | - | ||
| 544 | - private static void addBpmnUserTaskNode(Process mainProcess, BpmSimpleModelNodeVO node) { | ||
| 545 | - UserTask userTask = new UserTask(); | ||
| 546 | - userTask.setId(node.getId()); | ||
| 547 | - userTask.setName(node.getName()); | ||
| 548 | - addExtensionAttributes(node, userTask); | ||
| 549 | - mainProcess.addFlowElement(userTask); | ||
| 550 | - } | ||
| 551 | - | ||
| 552 | - private static void addExtensionAttributes(FlowElement element, String namespace, String name, String value) { | ||
| 553 | - if (value == null) { | ||
| 554 | - return; | ||
| 555 | - } | ||
| 556 | - ExtensionAttribute extensionAttribute = new ExtensionAttribute(name, value); | ||
| 557 | - extensionAttribute.setNamespace(namespace); | ||
| 558 | - extensionAttribute.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); | ||
| 559 | - element.addAttribute(extensionAttribute); | ||
| 560 | - } | ||
| 561 | - | ||
| 562 | - private static void addBpmnStartEventNode(Process mainProcess, BpmSimpleModelNodeVO node) { | ||
| 563 | - StartEvent startEvent = new StartEvent(); | ||
| 564 | - startEvent.setId(node.getId()); | ||
| 565 | - startEvent.setName(node.getName()); | ||
| 566 | - mainProcess.addFlowElement(startEvent); | ||
| 567 | - } | ||
| 568 | - | ||
| 569 | } | 340 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.lang.Assert; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 5 | +import cn.hutool.core.util.ArrayUtil; | ||
| 6 | +import cn.hutool.core.util.StrUtil; | ||
| 7 | +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; | ||
| 8 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; | ||
| 9 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | ||
| 10 | +import org.flowable.bpmn.BpmnAutoLayout; | ||
| 11 | +import org.flowable.bpmn.model.*; | ||
| 12 | +import org.flowable.bpmn.model.Process; | ||
| 13 | + | ||
| 14 | +import java.util.List; | ||
| 15 | + | ||
| 16 | +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE; | ||
| 17 | +import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 仿钉钉快搭模型相关的工具方法 | ||
| 21 | + * | ||
| 22 | + * @author jason | ||
| 23 | + */ | ||
| 24 | +public class SimpleModelUtils { | ||
| 25 | + | ||
| 26 | + public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) | ||
| 30 | + * | ||
| 31 | + * @param processId 流程标识 | ||
| 32 | + * @param processName 流程名称 | ||
| 33 | + * @param simpleModelNode 仿钉钉流程设计模型数据结构 | ||
| 34 | + * @return Bpmn Model | ||
| 35 | + */ | ||
| 36 | + public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { | ||
| 37 | + BpmnModel bpmnModel = new BpmnModel(); | ||
| 38 | + Process mainProcess = new Process(); | ||
| 39 | + mainProcess.setId(processId); | ||
| 40 | + mainProcess.setName(processName); | ||
| 41 | + mainProcess.setExecutable(Boolean.TRUE); | ||
| 42 | + bpmnModel.addProcess(mainProcess); | ||
| 43 | + // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。 | ||
| 44 | + // 从 SimpleModel 构建 FlowNode 并添加到 Main Process | ||
| 45 | + buildAndAddBpmnFlowNode(simpleModelNode, mainProcess); | ||
| 46 | + // 单独构建 end event 节点 | ||
| 47 | + buildAndAddBpmnEndEvent(mainProcess); | ||
| 48 | + // 构建并添加节点之间的连线 Sequence Flow | ||
| 49 | + buildAndAddBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID); | ||
| 50 | + // 自动布局 | ||
| 51 | + new BpmnAutoLayout(bpmnModel).execute(); | ||
| 52 | + return bpmnModel; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + private static void buildAndAddBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String targetId) { | ||
| 56 | + // 节点为 null 退出 | ||
| 57 | + if (node == null || node.getId() == null) { | ||
| 58 | + return; | ||
| 59 | + } | ||
| 60 | + BpmSimpleModelNodeVO childNode = node.getChildNode(); | ||
| 61 | + // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线 | ||
| 62 | + if (!BpmSimpleModelNodeType.isBranchNode(node.getType()) && (childNode == null || childNode.getId() == null)) { | ||
| 63 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetId, null, null); | ||
| 64 | + mainProcess.addFlowElement(sequenceFlow); | ||
| 65 | + return; | ||
| 66 | + } | ||
| 67 | + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | ||
| 68 | + Assert.notNull(nodeType, "模型节点类型不支持"); | ||
| 69 | + switch (nodeType) { | ||
| 70 | + case START_EVENT: | ||
| 71 | + case USER_TASK: | ||
| 72 | + case COPY_TASK: | ||
| 73 | + case PARALLEL_GATEWAY_JOIN: | ||
| 74 | + case INCLUSIVE_GATEWAY_JOIN:{ | ||
| 75 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null); | ||
| 76 | + mainProcess.addFlowElement(sequenceFlow); | ||
| 77 | + // 递归调用后续节点 | ||
| 78 | + buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId); | ||
| 79 | + break; | ||
| 80 | + } | ||
| 81 | + case PARALLEL_GATEWAY_FORK: | ||
| 82 | + case EXCLUSIVE_GATEWAY: | ||
| 83 | + case INCLUSIVE_GATEWAY_FORK:{ | ||
| 84 | + String sequenceFlowTargetId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); | ||
| 85 | + List<BpmSimpleModelNodeVO> conditionNodes = node.getConditionNodes(); | ||
| 86 | + Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); | ||
| 87 | + for (int i = 0; i < conditionNodes.size(); i++) { | ||
| 88 | + BpmSimpleModelNodeVO item = conditionNodes.get(i); | ||
| 89 | + BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); | ||
| 90 | + if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { | ||
| 91 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), nextNodeOnCondition.getId(), | ||
| 92 | + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); | ||
| 93 | + mainProcess.addFlowElement(sequenceFlow); | ||
| 94 | + // 递归调用后续节点 | ||
| 95 | + buildAndAddBpmnSequenceFlow(mainProcess, nextNodeOnCondition, sequenceFlowTargetId); | ||
| 96 | + } else { | ||
| 97 | + SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), sequenceFlowTargetId, | ||
| 98 | + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); | ||
| 99 | + mainProcess.addFlowElement(sequenceFlow); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + // 递归调用后续节点 | ||
| 103 | + buildAndAddBpmnSequenceFlow(mainProcess, childNode, targetId); | ||
| 104 | + break; | ||
| 105 | + } | ||
| 106 | + default: { | ||
| 107 | + // TODO 其它节点类型的实现 | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + private static SequenceFlow buildBpmnSequenceFlow(String sourceId, String targetId, String seqFlowId, String conditionExpression) { | ||
| 114 | + SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); | ||
| 115 | + if (StrUtil.isNotEmpty(conditionExpression)) { | ||
| 116 | + sequenceFlow.setConditionExpression(conditionExpression); | ||
| 117 | + } | ||
| 118 | + if (StrUtil.isNotEmpty(seqFlowId)) { | ||
| 119 | + sequenceFlow.setId(seqFlowId); | ||
| 120 | + } | ||
| 121 | + return sequenceFlow; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) { | ||
| 125 | + // 节点为 null 退出 | ||
| 126 | + if (simpleModelNode == null || simpleModelNode.getId() == null) { | ||
| 127 | + return; | ||
| 128 | + } | ||
| 129 | + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); | ||
| 130 | + Assert.notNull(nodeType, "模型节点类型不支持"); | ||
| 131 | + switch (nodeType) { | ||
| 132 | + case START_EVENT: { | ||
| 133 | + StartEvent startEvent = buildBpmnStartEvent(simpleModelNode); | ||
| 134 | + mainProcess.addFlowElement(startEvent); | ||
| 135 | + break; | ||
| 136 | + } | ||
| 137 | + case USER_TASK: { | ||
| 138 | + UserTask userTask = buildBpmnUserTask(simpleModelNode); | ||
| 139 | + mainProcess.addFlowElement(userTask); | ||
| 140 | + break; | ||
| 141 | + } | ||
| 142 | + case COPY_TASK: { | ||
| 143 | + ServiceTask serviceTask = buildBpmnServiceTask(simpleModelNode); | ||
| 144 | + mainProcess.addFlowElement(serviceTask); | ||
| 145 | + break; | ||
| 146 | + } | ||
| 147 | + case EXCLUSIVE_GATEWAY: { | ||
| 148 | + ExclusiveGateway exclusiveGateway = buildBpmnExclusiveGateway(simpleModelNode); | ||
| 149 | + mainProcess.addFlowElement(exclusiveGateway); | ||
| 150 | + break; | ||
| 151 | + } | ||
| 152 | + case PARALLEL_GATEWAY_FORK: | ||
| 153 | + case PARALLEL_GATEWAY_JOIN: { | ||
| 154 | + ParallelGateway parallelGateway = buildBpmnParallelGateway(simpleModelNode); | ||
| 155 | + mainProcess.addFlowElement(parallelGateway); | ||
| 156 | + break; | ||
| 157 | + } | ||
| 158 | + case INCLUSIVE_GATEWAY_FORK: { | ||
| 159 | + InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.TRUE); | ||
| 160 | + mainProcess.addFlowElement(inclusiveGateway); | ||
| 161 | + break; | ||
| 162 | + } | ||
| 163 | + case INCLUSIVE_GATEWAY_JOIN: { | ||
| 164 | + InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.FALSE); | ||
| 165 | + mainProcess.addFlowElement(inclusiveGateway); | ||
| 166 | + break; | ||
| 167 | + } | ||
| 168 | + default: { | ||
| 169 | + // TODO 其它节点类型的实现 | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + // 如果不是网关类型的接口, 并且chileNode为空退出 | ||
| 174 | + if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { | ||
| 175 | + return; | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + // 如果是网关类型接口. 递归添加条件节点 | ||
| 179 | + if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { | ||
| 180 | + for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { | ||
| 181 | + buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess); | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + // chileNode不为空,递归添加子节点 | ||
| 186 | + if (simpleModelNode.getChildNode() != null) { | ||
| 187 | + buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess); | ||
| 188 | + } | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) { | ||
| 192 | + ParallelGateway parallelGateway = new ParallelGateway(); | ||
| 193 | + parallelGateway.setId(node.getId()); | ||
| 194 | + return parallelGateway; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) { | ||
| 198 | + ServiceTask serviceTask = new ServiceTask(); | ||
| 199 | + serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION); | ||
| 200 | + serviceTask.setImplementation(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT); | ||
| 201 | + serviceTask.setId(node.getId()); | ||
| 202 | + serviceTask.setName(node.getName()); | ||
| 203 | + // TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现; | ||
| 204 | + // @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners | ||
| 205 | + addExtensionElement(node, serviceTask); | ||
| 206 | + return serviceTask; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + private static void addExtensionElement(BpmSimpleModelNodeVO node, FlowElement flowElement) { | ||
| 210 | + Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); | ||
| 211 | + addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, | ||
| 212 | + candidateStrategy == null ? null : String.valueOf(candidateStrategy)); | ||
| 213 | + addExtensionElement(flowElement, FLOWABLE_EXTENSIONS_NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, | ||
| 214 | + MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) { | ||
| 218 | + Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | ||
| 219 | + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); | ||
| 220 | + exclusiveGateway.setId(node.getId()); | ||
| 221 | + // 网关的最后一个条件为 网关的 default sequence flow | ||
| 222 | + exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | ||
| 223 | + return exclusiveGateway; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + private static InclusiveGateway buildBpmnInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { | ||
| 227 | + InclusiveGateway inclusiveGateway = new InclusiveGateway(); | ||
| 228 | + inclusiveGateway.setId(node.getId()); | ||
| 229 | + if (isFork) { | ||
| 230 | + Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); | ||
| 231 | + // 网关的最后一个条件为 网关的 default sequence flow | ||
| 232 | + inclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); | ||
| 233 | + } | ||
| 234 | + return inclusiveGateway; | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + private static void buildAndAddBpmnEndEvent(Process mainProcess) { | ||
| 238 | + EndEvent endEvent = new EndEvent(); | ||
| 239 | + endEvent.setId(BpmnModelConstants.END_EVENT_ID); | ||
| 240 | + endEvent.setName("结束"); | ||
| 241 | + mainProcess.addFlowElement(endEvent); | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node) { | ||
| 245 | + UserTask userTask = new UserTask(); | ||
| 246 | + userTask.setId(node.getId()); | ||
| 247 | + userTask.setName(node.getName()); | ||
| 248 | + addExtensionElement(node, userTask); | ||
| 249 | + return userTask; | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + private static void addExtensionElement(FlowElement element, String namespace, String name, String value) { | ||
| 253 | + if (value == null) { | ||
| 254 | + return; | ||
| 255 | + } | ||
| 256 | + ExtensionElement extensionElement = new ExtensionElement(); | ||
| 257 | + extensionElement.setNamespace(namespace); | ||
| 258 | + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); | ||
| 259 | + extensionElement.setElementText(value); | ||
| 260 | + extensionElement.setName(name); | ||
| 261 | + element.addExtensionElement(extensionElement); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + private static StartEvent buildBpmnStartEvent(BpmSimpleModelNodeVO node) { | ||
| 265 | + StartEvent startEvent = new StartEvent(); | ||
| 266 | + startEvent.setId(node.getId()); | ||
| 267 | + startEvent.setName(node.getName()); | ||
| 268 | + return startEvent; | ||
| 269 | + } | ||
| 270 | +} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java
| @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp | @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimp | ||
| 10 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; | 10 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; |
| 11 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | 11 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; |
| 12 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | 12 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| 13 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; | ||
| 13 | import jakarta.annotation.Resource; | 14 | import jakarta.annotation.Resource; |
| 14 | import org.flowable.bpmn.model.*; | 15 | import org.flowable.bpmn.model.*; |
| 15 | import org.flowable.engine.repository.Model; | 16 | import org.flowable.engine.repository.Model; |
| @@ -22,7 +23,7 @@ import java.util.Map; | @@ -22,7 +23,7 @@ import java.util.Map; | ||
| 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 23 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; | 24 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; |
| 24 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; | 25 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; |
| 25 | -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT_NODE; | 26 | +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT; |
| 26 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; | 27 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; |
| 27 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; | 28 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; |
| 28 | 29 | ||
| @@ -56,7 +57,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | @@ -56,7 +57,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | ||
| 56 | // return Boolean.FALSE; | 57 | // return Boolean.FALSE; |
| 57 | // } | 58 | // } |
| 58 | // 1. JSON 转换成 bpmnModel | 59 | // 1. JSON 转换成 bpmnModel |
| 59 | - BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); | 60 | + BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); |
| 60 | // 2.1 保存 Bpmn XML | 61 | // 2.1 保存 Bpmn XML |
| 61 | bpmModelService.saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); | 62 | bpmModelService.saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); |
| 62 | // 2.2 保存 JSON 数据 | 63 | // 2.2 保存 JSON 数据 |
| @@ -93,7 +94,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | @@ -93,7 +94,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | ||
| 93 | return null; | 94 | return null; |
| 94 | } | 95 | } |
| 95 | BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); | 96 | BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); |
| 96 | - rootNode.setType(START_EVENT_NODE.getType()); | 97 | + rootNode.setType(START_EVENT.getType()); |
| 97 | rootNode.setId(startEvent.getId()); | 98 | rootNode.setId(startEvent.getId()); |
| 98 | rootNode.setName(startEvent.getName()); | 99 | rootNode.setName(startEvent.getName()); |
| 99 | recursiveBuildSimpleModelNode(startEvent, rootNode); | 100 | recursiveBuildSimpleModelNode(startEvent, rootNode); |
| @@ -105,10 +106,10 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | @@ -105,10 +106,10 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | ||
| 105 | Assert.notNull(nodeType, "节点类型不支持"); | 106 | Assert.notNull(nodeType, "节点类型不支持"); |
| 106 | // 校验节点是否支持转仿钉钉的流程模型 | 107 | // 校验节点是否支持转仿钉钉的流程模型 |
| 107 | List<SequenceFlow> outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); | 108 | List<SequenceFlow> outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); |
| 108 | - if (CollUtil.isEmpty(outgoingFlows) || outgoingFlows.get(0).getTargetFlowElement() == null) { | 109 | + if (CollUtil.isEmpty(outgoingFlows) || CollUtil.getFirst(outgoingFlows).getTargetFlowElement() == null) { |
| 109 | return; | 110 | return; |
| 110 | } | 111 | } |
| 111 | - FlowElement targetElement = outgoingFlows.get(0).getTargetFlowElement(); | 112 | + FlowElement targetElement = CollUtil.getFirst(outgoingFlows).getTargetFlowElement(); |
| 112 | // 如果是 EndEvent 直接退出 | 113 | // 如果是 EndEvent 直接退出 |
| 113 | if (targetElement instanceof EndEvent) { | 114 | if (targetElement instanceof EndEvent) { |
| 114 | return; | 115 | return; |
| @@ -123,7 +124,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | @@ -123,7 +124,7 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | ||
| 123 | 124 | ||
| 124 | private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { | 125 | private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { |
| 125 | BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); | 126 | BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); |
| 126 | - simpleModelNodeVO.setType(BpmSimpleModelNodeType.APPROVE_USER_NODE.getType()); | 127 | + simpleModelNodeVO.setType(BpmSimpleModelNodeType.USER_TASK.getType()); |
| 127 | simpleModelNodeVO.setName(userTask.getName()); | 128 | simpleModelNodeVO.setName(userTask.getName()); |
| 128 | simpleModelNodeVO.setId(userTask.getId()); | 129 | simpleModelNodeVO.setId(userTask.getId()); |
| 129 | Map<String, Object> attributes = MapUtil.newHashMap(); | 130 | Map<String, Object> attributes = MapUtil.newHashMap(); |
| @@ -137,13 +138,13 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | @@ -137,13 +138,13 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | ||
| 137 | 138 | ||
| 138 | private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { | 139 | private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { |
| 139 | switch (nodeType) { | 140 | switch (nodeType) { |
| 140 | - case START_EVENT_NODE: | ||
| 141 | - case APPROVE_USER_NODE: { | 141 | + case START_EVENT: |
| 142 | + case USER_TASK: { | ||
| 142 | List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows(); | 143 | List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows(); |
| 143 | if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { | 144 | if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { |
| 144 | throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); | 145 | throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); |
| 145 | } | 146 | } |
| 146 | - validIsSupportFlowNode(outgoingFlows.get(0).getTargetFlowElement()); | 147 | + validIsSupportFlowNode(CollUtil.getFirst(outgoingFlows).getTargetFlowElement()); |
| 147 | return outgoingFlows; | 148 | return outgoingFlows; |
| 148 | } | 149 | } |
| 149 | default: { | 150 | default: { |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java
| @@ -47,7 +47,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy | @@ -47,7 +47,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy | ||
| 47 | // TODO @芋艿:这里多加了一个 name; | 47 | // TODO @芋艿:这里多加了一个 name; |
| 48 | @Override | 48 | @Override |
| 49 | public void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String taskId, String taskName) { | 49 | public void createProcessInstanceCopy(Collection<Long> userIds, String processInstanceId, String taskId, String taskName) { |
| 50 | - // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) TODO jason:抄送节点,会没有来源的 taskId 么? | 50 | + // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) TODO jason:抄送节点,会没有来源的 taskId 么? @芋艿 是否校验一下 传递进来的 id 不为空就行 |
| 51 | // Task task = taskService.getTask(taskId); | 51 | // Task task = taskService.getTask(taskId); |
| 52 | // if (ObjectUtil.isNull(task)) { | 52 | // if (ObjectUtil.isNull(task)) { |
| 53 | // throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); | 53 | // throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java
| @@ -9,7 +9,8 @@ import org.springframework.stereotype.Service; | @@ -9,7 +9,8 @@ import org.springframework.stereotype.Service; | ||
| 9 | import java.util.Set; | 9 | import java.util.Set; |
| 10 | 10 | ||
| 11 | /** | 11 | /** |
| 12 | - * 仿钉钉快搭各个节点 Service TODO @jason:注释要有空行哈; | 12 | + * 仿钉钉快搭各个节点 Service |
| 13 | + * | ||
| 13 | * @author jason | 14 | * @author jason |
| 14 | */ | 15 | */ |
| 15 | @Service | 16 | @Service |
| @@ -21,7 +22,8 @@ public class BpmSimpleNodeService { | @@ -21,7 +22,8 @@ public class BpmSimpleNodeService { | ||
| 21 | private BpmProcessInstanceCopyService processInstanceCopyService; | 22 | private BpmProcessInstanceCopyService processInstanceCopyService; |
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 24 | - * 仿钉钉快搭抄送 TODO @jason:注释要有空行哈; | 25 | + * 仿钉钉快搭抄送 |
| 26 | + * | ||
| 25 | * @param execution 执行的任务(ScriptTask) | 27 | * @param execution 执行的任务(ScriptTask) |
| 26 | */ | 28 | */ |
| 27 | public Boolean copy(DelegateExecution execution) { | 29 | public Boolean copy(DelegateExecution execution) { |