Commit a23b0480f159eaad446b7b93b182b565f8c455de

Authored by jason
1 parent 362b872a

【功能新增】 新增修改流程表单数据触发器

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java
@@ -16,7 +16,9 @@ import java.util.Arrays; @@ -16,7 +16,9 @@ import java.util.Arrays;
16 @AllArgsConstructor 16 @AllArgsConstructor
17 public enum BpmTriggerTypeEnum implements ArrayValuable<Integer> { 17 public enum BpmTriggerTypeEnum implements ArrayValuable<Integer> {
18 18
19 - HTTP_REQUEST(1, "发起 HTTP 请求"); 19 + HTTP_REQUEST(1, "发起 HTTP 请求"),
  20 + UPDATE_NORMAL_FORM(2, "更新流程表单");
  21 +
20 22
21 /** 23 /**
22 * 触发器执行动作类型 24 * 触发器执行动作类型
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
@@ -345,6 +345,11 @@ public class BpmSimpleModelNodeVO { @@ -345,6 +345,11 @@ public class BpmSimpleModelNodeVO {
345 @Valid 345 @Valid
346 private HttpRequestTriggerSetting httpRequestSetting; 346 private HttpRequestTriggerSetting httpRequestSetting;
347 347
  348 + /**
  349 + * 更新流程表单触发器设置
  350 + */
  351 + private UpdateNormalFormTriggerSetting updateNormalFormSetting;
  352 +
348 @Schema(description = "http 请求触发器设置", example = "{}") 353 @Schema(description = "http 请求触发器设置", example = "{}")
349 @Data 354 @Data
350 public static class HttpRequestTriggerSetting { 355 public static class HttpRequestTriggerSetting {
@@ -365,14 +370,32 @@ public class BpmSimpleModelNodeVO { @@ -365,14 +370,32 @@ public class BpmSimpleModelNodeVO {
365 // TODO @json:可能未来看情况,搞个 HttpResponseParam;得看看有没别的业务需要,抽象统一 370 // TODO @json:可能未来看情况,搞个 HttpResponseParam;得看看有没别的业务需要,抽象统一
366 /** 371 /**
367 * 请求返回处理设置,用于修改流程表单值 372 * 请求返回处理设置,用于修改流程表单值
368 - * 373 + * <p>
369 * key:表示要修改的流程表单字段名(name) 374 * key:表示要修改的流程表单字段名(name)
370 * value:接口返回的字段名 375 * value:接口返回的字段名
371 */ 376 */
372 @Schema(description = "请求返回处理设置", example = "[]") 377 @Schema(description = "请求返回处理设置", example = "[]")
373 private List<KeyValue<String, String>> response; 378 private List<KeyValue<String, String>> response;
374 -  
375 } 379 }
376 380
  381 + @Schema(description = "更新流程表单触发器设置", example = "{}")
  382 + @Data
  383 + public static class UpdateNormalFormTriggerSetting {
  384 +
  385 + @Schema(description = "条件类型", example = "1")
  386 + @InEnum(BpmSimpleModeConditionTypeEnum.class)
  387 + @NotNull(message = "条件类型不能为空")
  388 + private Integer conditionType;
  389 +
  390 + @Schema(description = "条件表达式", example = "${day>3}")
  391 + private String conditionExpression;
  392 +
  393 + @Schema(description = "条件组", example = "{}")
  394 + private ConditionGroups conditionGroups;
  395 +
  396 + @Schema(description = "更新的表单字段", example = "userName")
  397 + @NotEmpty(message = "更新的表单字段不能为空")
  398 + private Map<String, Object> updateFormFields;
  399 + }
377 } 400 }
378 } 401 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -64,6 +64,13 @@ public class BpmnModelUtils { @@ -64,6 +64,13 @@ public class BpmnModelUtils {
64 addExtensionElement(element, name, String.valueOf(value)); 64 addExtensionElement(element, name, String.valueOf(value));
65 } 65 }
66 66
  67 + public static void addExtensionElementJson(FlowElement element, String name, Object value) {
  68 + if (value == null) {
  69 + return;
  70 + }
  71 + addExtensionElement(element, name, JsonUtils.toJsonString(value));
  72 + }
  73 +
67 public static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) { 74 public static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) {
68 if (attributes == null) { 75 if (attributes == null) {
69 return; 76 return;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert; @@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 6 import cn.hutool.core.util.*;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
11 import cn.iocoder.yudao.module.bpm.enums.definition.*; 10 import cn.iocoder.yudao.module.bpm.enums.definition.*;
@@ -626,54 +625,52 @@ public class SimpleModelUtils { @@ -626,54 +625,52 @@ public class SimpleModelUtils {
626 625
627 public static SequenceFlow buildSequenceFlow(String sourceId, String targetId, 626 public static SequenceFlow buildSequenceFlow(String sourceId, String targetId,
628 BpmSimpleModelNodeVO node) { 627 BpmSimpleModelNodeVO node) {
629 - String conditionExpression = buildConditionExpression(node); 628 + String conditionExpression = buildConditionExpression(node.getConditionSetting());
630 return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression); 629 return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression);
631 } 630 }
632 631
633 - /**  
634 - * 构造条件表达式  
635 - *  
636 - * @param node 条件节点  
637 - */  
638 - public static String buildConditionExpression(BpmSimpleModelNodeVO node) {  
639 - return buildConditionExpression(node.getConditionSetting().getConditionType(), node.getConditionSetting().getConditionExpression(),  
640 - node.getConditionSetting().getConditionGroups());  
641 - }  
642 632
643 - public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterSetting router) {  
644 - return buildConditionExpression(router.getConditionType(), router.getConditionExpression(),  
645 - router.getConditionGroups());  
646 - } 633 + }
647 634
648 - public static String buildConditionExpression(Integer conditionType, String conditionExpression,  
649 - ConditionGroups conditionGroups) {  
650 - BpmSimpleModeConditionTypeEnum conditionTypeEnum = BpmSimpleModeConditionTypeEnum.valueOf(conditionType);  
651 - if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.EXPRESSION) {  
652 - return conditionExpression; 635 + /**
  636 + * 构造条件表达式
  637 + */
  638 + public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) {
  639 + return buildConditionExpression(conditionSetting.getConditionType(), conditionSetting.getConditionExpression(),
  640 + conditionSetting.getConditionGroups());
  641 + }
  642 +
  643 + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterSetting routerSetting) {
  644 + return buildConditionExpression(routerSetting.getConditionType(), routerSetting.getConditionExpression(),
  645 + routerSetting.getConditionGroups());
  646 + }
  647 +
  648 + public static String buildConditionExpression(Integer conditionType, String conditionExpression, ConditionGroups conditionGroups) {
  649 + BpmSimpleModeConditionTypeEnum conditionTypeEnum = BpmSimpleModeConditionTypeEnum.valueOf(conditionType);
  650 + if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.EXPRESSION) {
  651 + return conditionExpression;
  652 + }
  653 + if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.RULE) {
  654 + if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) {
  655 + return null;
653 } 656 }
654 - if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.RULE) {  
655 - if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) {  
656 - return null; 657 + List<String> strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> {
  658 + if (CollUtil.isEmpty(item.getRules())) {
  659 + return "";
657 } 660 }
658 - List<String> strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> {  
659 - if (CollUtil.isEmpty(item.getRules())) {  
660 - return "";  
661 - }  
662 - // 构造规则表达式  
663 - List<String> list = CollectionUtils.convertList(item.getRules(), (rule) -> {  
664 - String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide()  
665 - : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号  
666 - return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide);  
667 - });  
668 - // 构造条件组的表达式  
669 - Boolean and = item.getAnd();  
670 - return "(" + CollUtil.join(list, and ? " && " : " || ") + ")"; 661 + // 构造规则表达式
  662 + List<String> list = CollectionUtils.convertList(item.getRules(), (rule) -> {
  663 + String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide()
  664 + : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号
  665 + return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide);
671 }); 666 });
672 - return String.format("${%s}", CollUtil.join(strConditionGroups, conditionGroups.getAnd() ? " && " : " || "));  
673 - }  
674 - return null; 667 + // 构造条件组的表达式
  668 + Boolean and = item.getAnd();
  669 + return "(" + CollUtil.join(list, and ? " && " : " || ") + ")";
  670 + });
  671 + return String.format("${%s}", CollUtil.join(strConditionGroups, conditionGroups.getAnd() ? " && " : " || "));
675 } 672 }
676 - 673 + return null;
677 } 674 }
678 675
679 public static class DelayTimerNodeConvert implements NodeConvert { 676 public static class DelayTimerNodeConvert implements NodeConvert {
@@ -727,9 +724,10 @@ public class SimpleModelUtils { @@ -727,9 +724,10 @@ public class SimpleModelUtils {
727 if (node.getTriggerSetting() != null) { 724 if (node.getTriggerSetting() != null) {
728 addExtensionElement(serviceTask, TRIGGER_TYPE, node.getTriggerSetting().getType()); 725 addExtensionElement(serviceTask, TRIGGER_TYPE, node.getTriggerSetting().getType());
729 if (node.getTriggerSetting().getHttpRequestSetting() != null) { 726 if (node.getTriggerSetting().getHttpRequestSetting() != null) {
730 - // TODO @jason:加个 addExtensionElementJson 方法,方便设置 JSON 类型的属性  
731 - addExtensionElement(serviceTask, TRIGGER_PARAM,  
732 - JsonUtils.toJsonString(node.getTriggerSetting().getHttpRequestSetting())); 727 + addExtensionElementJson(serviceTask, TRIGGER_PARAM, node.getTriggerSetting().getHttpRequestSetting());
  728 + }
  729 + if (node.getTriggerSetting().getUpdateNormalFormSetting() != null) {
  730 + addExtensionElementJson(serviceTask, TRIGGER_PARAM, node.getTriggerSetting().getUpdateNormalFormSetting());
733 } 731 }
734 } 732 }
735 return serviceTask; 733 return serviceTask;
@@ -760,7 +758,7 @@ public class SimpleModelUtils { @@ -760,7 +758,7 @@ public class SimpleModelUtils {
760 } 758 }
761 759
762 public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterSetting router) { 760 public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterSetting router) {
763 - String conditionExpression = ConditionNodeConvert.buildConditionExpression(router); 761 + String conditionExpression = SimpleModelUtils.buildConditionExpression(router);
764 return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression); 762 return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression);
765 } 763 }
766 764
@@ -804,7 +802,7 @@ public class SimpleModelUtils { @@ -804,7 +802,7 @@ public class SimpleModelUtils {
804 // 查找满足条件的 BpmSimpleModelNodeVO 节点 802 // 查找满足条件的 BpmSimpleModelNodeVO 节点
805 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), 803 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
806 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) 804 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
807 - && evalConditionExpress(variables, conditionNode)); 805 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
808 if (matchConditionNode == null) { 806 if (matchConditionNode == null) {
809 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), 807 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
810 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); 808 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
@@ -819,7 +817,7 @@ public class SimpleModelUtils { @@ -819,7 +817,7 @@ public class SimpleModelUtils {
819 // 查找满足条件的 BpmSimpleModelNodeVO 节点 817 // 查找满足条件的 BpmSimpleModelNodeVO 节点
820 Collection<BpmSimpleModelNodeVO> matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), 818 Collection<BpmSimpleModelNodeVO> matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
821 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) 819 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
822 - && evalConditionExpress(variables, conditionNode)); 820 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
823 if (CollUtil.isEmpty(matchConditionNodes)) { 821 if (CollUtil.isEmpty(matchConditionNodes)) {
824 matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), 822 matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
825 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); 823 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
@@ -841,16 +839,17 @@ public class SimpleModelUtils { @@ -841,16 +839,17 @@ public class SimpleModelUtils {
841 simulateNextNode(currentNode.getChildNode(), variables, resultNodes); 839 simulateNextNode(currentNode.getChildNode(), variables, resultNodes);
842 } 840 }
843 841
844 - public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO conditionNode) {  
845 - return BpmnModelUtils.evalConditionExpress(variables, ConditionNodeConvert.buildConditionExpression(conditionNode)); 842 + public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO.ConditionSetting conditionSetting) {
  843 + return BpmnModelUtils.evalConditionExpress(variables, buildConditionExpression(conditionSetting));
846 } 844 }
847 845
848 // TODO @芋艿:【高】要不要优化下,抽个 HttpUtils 846 // TODO @芋艿:【高】要不要优化下,抽个 HttpUtils
  847 +
849 /** 848 /**
850 * 添加 HTTP 请求参数。请求头或者请求体 849 * 添加 HTTP 请求参数。请求头或者请求体
851 * 850 *
852 - * @param params HTTP 请求参数  
853 - * @param paramSettings HTTP 请求参数设置 851 + * @param params HTTP 请求参数
  852 + * @param paramSettings HTTP 请求参数设置
854 * @param processVariables 流程变量 853 * @param processVariables 流程变量
855 */ 854 */
856 public static void addHttpRequestParam(MultiValueMap<String, String> params, 855 public static void addHttpRequestParam(MultiValueMap<String, String> params,
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmUpdateNormalFormTrigger.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.task.trigger;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TriggerSetting.UpdateNormalFormTriggerSetting;
  5 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum;
  6 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  7 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
  8 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
  9 +import jakarta.annotation.Resource;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.flowable.engine.runtime.ProcessInstance;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import java.util.Map;
  15 +
  16 +
  17 +/**
  18 + * BPM 更新流程表单触发器
  19 + *
  20 + * @author jason
  21 + */
  22 +@Component
  23 +@Slf4j
  24 +public class BpmUpdateNormalFormTrigger implements BpmTrigger {
  25 +
  26 + @Resource
  27 + private BpmProcessInstanceService processInstanceService;
  28 +
  29 + @Override
  30 + public BpmTriggerTypeEnum getType() {
  31 + return BpmTriggerTypeEnum.UPDATE_NORMAL_FORM;
  32 + }
  33 +
  34 + @Override
  35 + public void execute(String processInstanceId, String param) {
  36 + // 1. 解析更新流程表单配置
  37 + UpdateNormalFormTriggerSetting setting = JsonUtils.parseObject(param, UpdateNormalFormTriggerSetting.class);
  38 + if (setting == null) {
  39 + log.error("[execute][流程({}) 更新流程表单触发器配置为空]", processInstanceId);
  40 + return;
  41 + }
  42 + // 2.获取流程变量
  43 + ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
  44 + Map<String, Object> processVariables = processInstance.getProcessVariables();
  45 + String expression = SimpleModelUtils.buildConditionExpression(setting.getConditionType(), setting.getConditionExpression(),
  46 + setting.getConditionGroups());
  47 +
  48 + // 3.满足条件,更新流程表单
  49 + if(BpmnModelUtils.evalConditionExpress(processVariables, expression)) {
  50 + processInstanceService.updateProcessInstanceVariables(processInstanceId, setting.getUpdateFormFields());
  51 + }
  52 + }
  53 +}