Commit a53c7dafd3db965d8a1d6241b6e3274903b634cb

Authored by YunaiV
2 parents 743d88a4 d7a785d1

Merge branch 'feature/bpm' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

Showing 20 changed files with 238 additions and 89 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
... ... @@ -42,6 +42,7 @@ public interface ErrorCodeConstants {
42 42 ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_005, "流程取消失败,该流程不允许取消");
43 43 ErrorCode PROCESS_INSTANCE_HTTP_TRIGGER_CALL_ERROR = new ErrorCode(1_009_004_006, "流程 Http 触发器请求调用失败");
44 44 ErrorCode PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_007, "下一个任务({})的审批人未配置");
  45 + ErrorCode PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_008, "子流程取消失败,子流程不允许取消");
45 46  
46 47 // ========== 流程任务 1-009-005-000 ==========
47 48 ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你");
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
... ... @@ -18,6 +18,7 @@ public enum BpmReasonEnum {
18 18 REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法
19 19 CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程
20 20 CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程
  21 + CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS("子流程自动取消,原因:主流程已取消"),
21 22  
22 23 // ========== 流程任务的独有原因 ==========
23 24  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/dept/DeptSimpleBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.controller.admin.base.dept;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "部门精简信息 VO")
  7 +@Data
  8 +public class DeptSimpleBaseVO {
  9 +
  10 + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  11 + private Long id;
  12 + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术部")
  13 + private String name;
  14 +
  15 +}
0 16 \ No newline at end of file
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
... ... @@ -12,6 +12,8 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
12 12 import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
13 13 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
14 14 import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
  15 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  16 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
15 17 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
16 18 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
17 19 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -53,6 +55,8 @@ public class BpmModelController {
53 55  
54 56 @Resource
55 57 private AdminUserApi adminUserApi;
  58 + @Resource
  59 + private DeptApi deptApi;
56 60  
57 61 @GetMapping("/list")
58 62 @Operation(summary = "获得模型分页")
... ... @@ -79,14 +83,19 @@ public class BpmModelController {
79 83 List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(
80 84 deploymentMap.keySet());
81 85 Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
82   - // 获得 User Map
  86 + // 获得 User Map、Dept Map
83 87 Set<Long> userIds = convertSetByFlatMap(list, model -> {
84 88 BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
85 89 return metaInfo != null ? metaInfo.getStartUserIds().stream() : Stream.empty();
86 90 });
87 91 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
  92 + Set<Long> deptIds = convertSetByFlatMap(list, model -> {
  93 + BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
  94 + return metaInfo != null && metaInfo.getStartDeptIds() != null ? metaInfo.getStartDeptIds().stream() : Stream.empty();
  95 + });
  96 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(deptIds);
88 97 return success(BpmModelConvert.INSTANCE.buildModelList(list,
89   - formMap, categoryMap, deploymentMap, processDefinitionMap, userMap));
  98 + formMap, categoryMap, deploymentMap, processDefinitionMap, userMap, deptMap));
90 99 }
91 100  
92 101 @GetMapping("/get")
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java
... ... @@ -59,6 +59,9 @@ public class BpmModelMetaInfoVO {
59 59 @Schema(description = "可发起用户编号数组", example = "[1,2,3]")
60 60 private List<Long> startUserIds;
61 61  
  62 + @Schema(description = "可发起部门编号数组", example = "[2,4,6]")
  63 + private List<Long> startDeptIds;
  64 +
62 65 @Schema(description = "可管理用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2,4,6]")
63 66 @NotEmpty(message = "可管理用户编号数组不能为空")
64 67 private List<Long> managerUserIds;
... ... @@ -88,6 +91,12 @@ public class BpmModelMetaInfoVO {
88 91 @Schema(description = "流程后置通知设置", example = "{}")
89 92 private HttpRequestSetting processAfterTriggerSetting;
90 93  
  94 + @Schema(description = "任务前置通知设置", example = "{}")
  95 + private HttpRequestSetting taskBeforeTriggerSetting;
  96 +
  97 + @Schema(description = "任务后置通知设置", example = "{}")
  98 + private HttpRequestSetting taskAfterTriggerSetting;
  99 +
91 100 @Schema(description = "流程 ID 规则")
92 101 @Data
93 102 @Valid
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
1 1 package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
2 2  
  3 +import cn.iocoder.yudao.module.bpm.controller.admin.base.dept.DeptSimpleBaseVO;
3 4 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
4 5 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
5 6 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
... ... @@ -39,6 +40,9 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO {
39 40 @Schema(description = "可发起的用户数组")
40 41 private List<UserSimpleBaseVO> startUsers;
41 42  
  43 + @Schema(description = "可发起的部门数组")
  44 + private List<DeptSimpleBaseVO> startDepts;
  45 +
42 46 @Schema(description = "BPMN XML")
43 47 private String bpmnXml;
44 48  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
... ... @@ -112,7 +112,7 @@ public class BpmSimpleModelNodeVO {
112 112 /**
113 113 * 条件节点设置
114 114 */
115   - private ConditionSetting conditionSetting; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
  115 + private ConditionSetting conditionSetting; // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE
116 116  
117 117 @Schema(description = "路由分支组", example = "[]")
118 118 private List<RouterSetting> routerGroups;
... ... @@ -241,7 +241,7 @@ public class BpmSimpleModelNodeVO {
241 241 @Schema(description = "条件设置")
242 242 @Data
243 243 @Valid
244   - // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
  244 + // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE
245 245 public static class ConditionSetting {
246 246  
247 247 @Schema(description = "条件类型", example = "1")
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
... ... @@ -148,7 +148,6 @@ public class BpmProcessInstanceController {
148 148 processDefinition, processDefinitionInfo, startUser, dept));
149 149 }
150 150  
151   - // TODO @lesan:【子流程】子流程如果取消,主流程应该是通过、还是不通过哈?还是禁用掉子流程的取消?
152 151 @DeleteMapping("/cancel-by-start-user")
153 152 @Operation(summary = "用户取消流程实例", description = "取消发起的流程")
154 153 @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')")
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
... ... @@ -72,6 +72,9 @@ public class BpmApprovalDetailRespVO {
72 72 @Schema(description = "候选人用户列表")
73 73 private List<UserSimpleBaseVO> candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表
74 74  
  75 + @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf")
  76 + private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段)
  77 +
75 78 }
76 79  
77 80 @Schema(description = "活动节点的任务信息")
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.util.ArrayUtil;
4 4 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
5 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.bpm.controller.admin.base.dept.DeptSimpleBaseVO;
7 8 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
8 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
9 10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO;
... ... @@ -13,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro
13 14 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
14 15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
15 16 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  17 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
16 18 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
17 19 import org.flowable.common.engine.impl.db.SuspensionState;
18 20 import org.flowable.engine.repository.Deployment;
... ... @@ -43,7 +45,8 @@ public interface BpmModelConvert {
43 45 Map<String, BpmCategoryDO> categoryMap,
44 46 Map<String, Deployment> deploymentMap,
45 47 Map<String, ProcessDefinition> processDefinitionMap,
46   - Map<Long, AdminUserRespDTO> userMap) {
  48 + Map<Long, AdminUserRespDTO> userMap,
  49 + Map<Long, DeptRespDTO> deptMap) {
47 50 List<BpmModelRespVO> result = convertList(list, model -> {
48 51 BpmModelMetaInfoVO metaInfo = parseMetaInfo(model);
49 52 BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null;
... ... @@ -52,7 +55,8 @@ public interface BpmModelConvert {
52 55 ProcessDefinition processDefinition = model.getDeploymentId() != null ?
53 56 processDefinitionMap.get(model.getDeploymentId()) : null;
54 57 List<AdminUserRespDTO> startUsers = metaInfo != null ? convertList(metaInfo.getStartUserIds(), userMap::get) : null;
55   - return buildModel0(model, metaInfo, form, category, deployment, processDefinition, startUsers);
  58 + List<DeptRespDTO> startDepts = metaInfo != null ? convertList(metaInfo.getStartDeptIds(), deptMap::get) : null;
  59 + return buildModel0(model, metaInfo, form, category, deployment, processDefinition, startUsers, startDepts);
56 60 });
57 61 // 排序
58 62 result.sort(Comparator.comparing(BpmModelMetaInfoVO::getSort));
... ... @@ -61,7 +65,7 @@ public interface BpmModelConvert {
61 65  
62 66 default BpmModelRespVO buildModel(Model model, byte[] bpmnBytes, BpmSimpleModelNodeVO simpleModel) {
63 67 BpmModelMetaInfoVO metaInfo = parseMetaInfo(model);
64   - BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null);
  68 + BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null, null);
65 69 if (ArrayUtil.isNotEmpty(bpmnBytes)) {
66 70 modelVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnBytes));
67 71 }
... ... @@ -72,7 +76,7 @@ public interface BpmModelConvert {
72 76 default BpmModelRespVO buildModel0(Model model,
73 77 BpmModelMetaInfoVO metaInfo, BpmFormDO form, BpmCategoryDO category,
74 78 Deployment deployment, ProcessDefinition processDefinition,
75   - List<AdminUserRespDTO> startUsers) {
  79 + List<AdminUserRespDTO> startUsers, List<DeptRespDTO> startDepts) {
76 80 BpmModelRespVO modelRespVO = new BpmModelRespVO().setId(model.getId()).setName(model.getName())
77 81 .setKey(model.getKey()).setCategory(model.getCategory())
78 82 .setCreateTime(DateUtils.of(model.getCreateTime()));
... ... @@ -94,8 +98,9 @@ public interface BpmModelConvert {
94 98 modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime()));
95 99 }
96 100 }
97   - // User
98   - modelRespVO.setStartUsers(BeanUtils.toBean(startUsers, UserSimpleBaseVO.class));
  101 + // User、Dept
  102 + modelRespVO.setStartUsers(BeanUtils.toBean(startUsers, UserSimpleBaseVO.class))
  103 + .setStartDepts(BeanUtils.toBean(startDepts, DeptSimpleBaseVO.class));
99 104 return modelRespVO;
100 105 }
101 106  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java
... ... @@ -152,6 +152,14 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
152 152 private List<Long> startUserIds;
153 153  
154 154 /**
  155 + * 可发起部门编号数组
  156 + *
  157 + * 关联 {@link AdminUserRespDTO#getDeptId()} 字段的数组
  158 + */
  159 + @TableField(typeHandler = LongListTypeHandler.class)
  160 + private List<Long> startDeptIds;
  161 +
  162 + /**
155 163 * 可管理用户编号数组
156 164 *
157 165 * 关联 {@link AdminUserRespDTO#getId()} 字段的数组
... ... @@ -199,4 +207,16 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
199 207 @TableField(typeHandler = JacksonTypeHandler.class)
200 208 private BpmModelMetaInfoVO.HttpRequestSetting processAfterTriggerSetting;
201 209  
  210 + /**
  211 + * 任务前置通知设置
  212 + */
  213 + @TableField(typeHandler = JacksonTypeHandler.class)
  214 + private BpmModelMetaInfoVO.HttpRequestSetting taskBeforeTriggerSetting;
  215 +
  216 + /**
  217 + * 任务后置通知设置
  218 + */
  219 + @TableField(typeHandler = JacksonTypeHandler.class)
  220 + private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting;
  221 +
202 222 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
... ... @@ -47,7 +47,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
47 47 public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
48 48 .add(FlowableEngineEventType.TASK_CREATED)
49 49 .add(FlowableEngineEventType.TASK_ASSIGNED)
50   -// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。
  50 + .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,这里仅处理任务后置通知。
51 51 .add(FlowableEngineEventType.ACTIVITY_CANCELLED)
52 52 .add(FlowableEngineEventType.TIMER_FIRED) // 监听审批超时
53 53 .build();
... ... @@ -67,6 +67,11 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
67 67 }
68 68  
69 69 @Override
  70 + protected void taskCompleted(FlowableEngineEntityEvent event) {
  71 + taskService.processTaskCompleted((Task) event.getEntity());
  72 + }
  73 +
  74 + @Override
70 75 protected void activityCancelled(FlowableActivityCancelledEvent event) {
71 76 List<HistoricActivityInstance> activityList = taskService.getHistoricActivityListByExecutionId(event.getExecutionId());
72 77 if (CollUtil.isEmpty(activityList)) {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
... ... @@ -187,7 +187,7 @@ public class SimpleModelUtils {
187 187 /**
188 188 * 构建有附加节点的连线
189 189 *
190   - * @param nodeId 当前节点 ID
  190 + * @param nodeId 当前节点 ID
191 191 * @param attachNodeId 附属节点 ID
192 192 * @param targetNodeId 目标节点 ID
193 193 */
... ... @@ -662,6 +662,10 @@ public class SimpleModelUtils {
662 662 * 构造条件表达式
663 663 */
664 664 public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) {
  665 + // 并行网关不需要设置条件
  666 + if (conditionSetting == null) {
  667 + return null;
  668 + }
665 669 return buildConditionExpression(conditionSetting.getConditionType(), conditionSetting.getConditionExpression(),
666 670 conditionSetting.getConditionGroups());
667 671 }
... ... @@ -813,7 +817,6 @@ public class SimpleModelUtils {
813 817 callActivity.setCalledElementType("key");
814 818 // 1. 是否异步
815 819 if (node.getChildProcessSetting().getAsync()) {
816   - // TODO @lesan: 这里目前测试没有跳过执行call activity 后面的节点
817 820 callActivity.setAsynchronous(true);
818 821 }
819 822  
... ... @@ -959,8 +962,8 @@ public class SimpleModelUtils {
959 962 if (nodeType == BpmSimpleModelNodeTypeEnum.CONDITION_BRANCH_NODE) {
960 963 // 查找满足条件的 BpmSimpleModelNodeVO 节点
961 964 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
962   - conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
963   - && evalConditionExpress(variables, conditionNode.getConditionSetting()));
  965 + conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
  966 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
964 967 if (matchConditionNode == null) {
965 968 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
966 969 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
... ... @@ -974,8 +977,8 @@ public class SimpleModelUtils {
974 977 if (nodeType == BpmSimpleModelNodeTypeEnum.INCLUSIVE_BRANCH_NODE) {
975 978 // 查找满足条件的 BpmSimpleModelNodeVO 节点
976 979 Collection<BpmSimpleModelNodeVO> matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
977   - conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
978   - && evalConditionExpress(variables, conditionNode.getConditionSetting()));
  980 + conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
  981 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
979 982 if (CollUtil.isEmpty(matchConditionNodes)) {
980 983 matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
981 984 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
... ... @@ -12,6 +12,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitio
12 12 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionInfoMapper;
13 13 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
14 14 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  15 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  16 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
15 17 import jakarta.annotation.Resource;
16 18 import lombok.extern.slf4j.Slf4j;
17 19 import org.flowable.bpmn.model.BpmnModel;
... ... @@ -50,6 +52,9 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
50 52 @Resource
51 53 private BpmProcessDefinitionInfoMapper processDefinitionMapper;
52 54  
  55 + @Resource
  56 + private AdminUserApi adminUserApi;
  57 +
53 58 @Override
54 59 public ProcessDefinition getProcessDefinition(String id) {
55 60 return repositoryService.getProcessDefinition(id);
... ... @@ -88,12 +93,22 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
88 93 if (processDefinition == null) {
89 94 return false;
90 95 }
91   - // 为空,则所有人都可以发起
92   - if (CollUtil.isEmpty(processDefinition.getStartUserIds())) {
93   - return true;
  96 +
  97 + // 校验用户是否在允许发起的用户列表中
  98 + if (CollUtil.isNotEmpty(processDefinition.getStartUserIds())) {
  99 + return processDefinition.getStartUserIds().contains(userId);
  100 + }
  101 +
  102 + // 校验用户是否在允许发起的部门列表中
  103 + if (CollUtil.isNotEmpty(processDefinition.getStartDeptIds())) {
  104 + AdminUserRespDTO user = adminUserApi.getUser(userId);
  105 + return user != null
  106 + && user.getDeptId() != null
  107 + && processDefinition.getStartDeptIds().contains(user.getDeptId());
94 108 }
95   - // 不为空,则需要存在里面
96   - return processDefinition.getStartUserIds().contains(userId);
  109 +
  110 + // 都为空,则所有人都可以发起
  111 + return true;
97 112 }
98 113  
99 114 @Override
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
... ... @@ -14,7 +14,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
14 14 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
15 15 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
16 16 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
17   -import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
18 17 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
19 18 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
20 19 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
... ... @@ -63,7 +62,6 @@ import org.springframework.context.annotation.Lazy;
63 62 import org.springframework.stereotype.Service;
64 63 import org.springframework.transaction.annotation.Transactional;
65 64 import org.springframework.validation.annotation.Validated;
66   -import org.springframework.web.client.RestTemplate;
67 65  
68 66 import java.util.*;
69 67  
... ... @@ -263,30 +261,31 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
263 261 processVariables.putAll(reqVO.getProcessVariables());
264 262 }
265 263  
266   - // 3 获取当前任务节点的信息
267   - // 3.1 获取下一个将要执行的节点集合
  264 + // 3. 获取下一个将要执行的节点集合
268 265 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
269 266 List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables);
270   - return convertList(nextFlowNodes, node -> {
271   - List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
272   - loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables);
273   - // 3.2 获取节点的审批人信息
274   - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(candidateUserIds);
275   - // 3.3 获取节点的审批人部门信息
276   - Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
277   - // 3.4 存在一个节点多人审批的情况,组装审批人信息
278   - List<UserSimpleBaseVO> candidateUsers = new ArrayList<>();
279   - userMap.forEach((key, value) -> candidateUsers.add(BpmProcessInstanceConvert.INSTANCE.buildUser(key, userMap, deptMap)));
280   - return new ActivityNode().setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
281   - .setId(node.getId())
282   - .setName(node.getName())
283   - .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
284   - .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
285   - // TODO @小北:先把 candidateUserIds 设置完,然后最后拼接 candidateUsers 信息。这样,如果有多个节点,就不用重复查询啦;类似 buildApprovalDetail 思路;
286   - // TODO 先拼接处 List ActivityNode
287   - // TODO 接着,再起一段,处理 adminUserApi.getUserMap(candidateUserIds)、deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId))
288   - .setCandidateUsers(candidateUsers);
289   - });
  267 + List<ActivityNode> nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId())
  268 + .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
  269 + .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
  270 + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
  271 + .setCandidateUserIds(getTaskCandidateUserList(bpmnModel, node.getId(),
  272 + loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables)));
  273 + if (CollUtil.isNotEmpty(nextActivityNodes)) {
  274 + return nextActivityNodes;
  275 + }
  276 +
  277 + // 4. 拼接基础信息
  278 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
  279 + convertSetByFlatMap(nextActivityNodes, ActivityNode::getCandidateUserIds, Collection::stream));
  280 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  281 + nextActivityNodes.forEach(node -> node.setCandidateUsers(convertList(node.getCandidateUserIds(), userId -> {
  282 + AdminUserRespDTO user = userMap.get(userId);
  283 + if (user != null) {
  284 + return BpmProcessInstanceConvert.INSTANCE.buildUser(userId, userMap, deptMap);
  285 + }
  286 + return null;
  287 + })));
  288 + return nextActivityNodes;
290 289 }
291 290  
292 291 @Override
... ... @@ -388,8 +387,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
388 387 List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) {
389 388 // 遍历 tasks 列表,只处理已结束的 UserTask
390 389 // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点
391   - // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程;
392   - // TODO @lesan:【子流程】基于 activities 查询出 usertask、callactivity,然后拼接?如果是子流程,就是可以点击过去?
393 390 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
394 391 List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
395 392 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
... ... @@ -411,7 +408,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
411 408  
412 409 // 遍历 activities,只处理已结束的 StartEvent、EndEvent
413 410 List<HistoricActivityInstance> endActivities = filterList(activities, activity -> activity.getEndTime() != null
414   - && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END)));
  411 + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_CALL_ACTIVITY, ELEMENT_EVENT_END)));
415 412 endActivities.forEach(activity -> {
416 413 // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点
417 414 if (ELEMENT_EVENT_START.equals(activity.getActivityType())
... ... @@ -445,7 +442,20 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
445 442 }
446 443 approvalNodes.add(endNode);
447 444 }
  445 + // CallActivity
  446 + if (ELEMENT_CALL_ACTIVITY.equals(activity.getActivityType())) {
  447 + ActivityNode callActivity = new ActivityNode().setId(activity.getId())
  448 + .setName(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getName())
  449 + .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus)
  450 + .setStartTime(DateUtils.of(activity.getStartTime()))
  451 + .setEndTime(DateUtils.of(activity.getEndTime()))
  452 + .setProcessInstanceId(activity.getProcessInstanceId());
  453 + approvalNodes.add(callActivity);
  454 + }
448 455 });
  456 +
  457 + // 按照时间排序
  458 + approvalNodes.sort(Comparator.comparing(ActivityNode::getStartTime));
449 459 return approvalNodes;
450 460 }
451 461  
... ... @@ -465,7 +475,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
465 475 HistoricActivityInstance::getActivityId);
466 476  
467 477 // 按照 activityId 分组,构建 ApprovalNodeInfo 节点
468   - // TODO @lesan:【子流程】在子流程进行审批的时候,HistoricActivityInstance 里面可以拿到 runActivities.get(0).getCalledProcessInstanceId()。要不要支持跳转???
469 478 Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId);
470 479 return convertList(runningTaskMap.entrySet(), entry -> {
471 480 String activityId = entry.getKey();
... ... @@ -511,6 +520,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
511 520 approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner
512 521 activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
513 522 }
  523 + if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) {
  524 + activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId());
  525 + }
514 526 return activityNode;
515 527 });
516 528 }
... ... @@ -824,6 +836,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
824 836 && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) {
825 837 throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW);
826 838 }
  839 + // 1.4 子流程不允许取消
  840 + if (StrUtil.isNotBlank(instance.getSuperExecutionId())) {
  841 + throw exception(PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW);
  842 + }
827 843  
828 844 // 2. 取消流程
829 845 updateProcessInstanceCancel(cancelReqVO.getId(),
... ... @@ -850,7 +866,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
850 866 BpmProcessInstanceStatusEnum.CANCEL.getStatus());
851 867 runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason);
852 868  
853   - // 2. 结束流程
  869 + // 2. 取消所有子流程
  870 + List<ProcessInstance> childProcessInstances = runtimeService.createProcessInstanceQuery()
  871 + .superProcessInstanceId(id).list();
  872 + childProcessInstances.forEach(processInstance -> updateProcessInstanceCancel(
  873 + processInstance.getProcessInstanceId(), BpmReasonEnum.CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS.getReason()));
  874 +
  875 + // 3. 结束流程
854 876 taskService.moveTaskToEnd(id, reason);
855 877 }
856 878  
... ... @@ -915,10 +937,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
915 937 BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
916 938  
917 939 BpmHttpRequestUtils.executeBpmHttpRequest(instance,
918   - setting.getUrl(),
919   - setting.getHeader(),
920   - setting.getBody(),
921   - true, setting.getResponse());
  940 + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
922 941 }
923 942 }
924 943 });
... ... @@ -937,10 +956,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
937 956 }
938 957 BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
939 958 BpmHttpRequestUtils.executeBpmHttpRequest(instance,
940   - setting.getUrl(),
941   - setting.getHeader(),
942   - setting.getBody(),
943   - true, setting.getResponse());
  959 + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
944 960 });
945 961 }
946 962  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -279,6 +279,13 @@ public interface BpmTaskService {
279 279 void processTaskAssigned(Task task);
280 280  
281 281 /**
  282 + * 处理 Task 完成事件,目前是发送任务后置通知
  283 + *
  284 + * @param task 任务实体
  285 + */
  286 + void processTaskCompleted(Task task);
  287 +
  288 + /**
282 289 * 处理 Task 审批超时事件,可能会处理多个当前审批中的任务
283 290 *
284 291 * @param processInstanceId 流程示例编号
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -6,12 +6,14 @@ import cn.hutool.core.lang.Assert;
6 6 import cn.hutool.core.util.*;
7 7 import cn.hutool.extra.spring.SpringUtil;
8 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
9 10 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
10 11 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
11 12 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
12 13 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
13 14 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
14 15 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
  16 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
15 17 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
16 18 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
17 19 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
... ... @@ -23,6 +25,7 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum;
23 25 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
24 26 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
25 27 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
  28 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils;
26 29 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
27 30 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
28 31 import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
... ... @@ -597,47 +600,54 @@ public class BpmTaskServiceImpl implements BpmTaskService {
597 600 */
598 601 private Map<String, Object> validateAndSetNextAssignees(String taskDefinitionKey, Map<String, Object> variables, BpmnModel bpmnModel,
599 602 Map<String, List<Long>> nextAssignees, ProcessInstance processInstance) {
  603 + // simple 设计器第一个节点默认为发起人节点,不校验是否存在审批人
  604 + if (Objects.equals(taskDefinitionKey, START_USER_NODE_ID)) {
  605 + return variables;
  606 + }
600 607 // 1. 获取下一个将要执行的节点集合
601 608 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
602 609 List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables);
603 610  
604 611 // 2. 校验选择的下一个节点的审批人,是否合法
605   - Map<String, List<Long>> processVariables;
606 612 for (FlowNode nextFlowNode : nextFlowNodes) {
607 613 Integer candidateStrategy = parseCandidateStrategy(nextFlowNode);
608 614 // 2.1 情况一:如果节点中的审批人策略为 发起人自选
609 615 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) {
  616 + // 特殊:如果当前节点已经存在审批人,则不允许覆盖
  617 + Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables());
  618 + if (startUserSelectAssignees != null && CollUtil.isNotEmpty(startUserSelectAssignees.get(nextFlowNode.getId()))) {
  619 + continue;
  620 + }
610 621 // 如果节点存在,但未配置审批人
611 622 List<Long> assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null;
612 623 if (CollUtil.isEmpty(assignees)) {
613 624 throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName());
614 625 }
615   - processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables());
616   - // 特殊:如果当前节点已经存在审批人,则不允许覆盖
617   - if (processVariables != null && CollUtil.isNotEmpty(processVariables.get(nextFlowNode.getId()))) {
618   - continue;
619   - }
  626 +
620 627 // 设置 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES
621   - if (processVariables == null) {
622   - processVariables = new HashMap<>();
  628 + if (startUserSelectAssignees == null) {
  629 + startUserSelectAssignees = new HashMap<>();
623 630 }
624   - processVariables.put(nextFlowNode.getId(), assignees);
625   - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables);
  631 + startUserSelectAssignees.put(nextFlowNode.getId(), assignees);
  632 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees);
  633 + continue;
626 634 }
  635 +
627 636 // 2.2 情况二:如果节点中的审批人策略为 审批人,在审批时选择下一个节点的审批人,并且该节点的审批人为空
628 637 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) {
629 638 // 如果节点存在,但未配置审批人
  639 + Map<String, List<Long>> approveUserSelectAssignees = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables());
630 640 List<Long> assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null;
631 641 if (CollUtil.isEmpty(assignees)) {
632 642 throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName());
633 643 }
634   - processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables());
635   - if (processVariables == null) {
636   - processVariables = new HashMap<>();
637   - }
  644 +
638 645 // 设置 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES
639   - processVariables.put(nextFlowNode.getId(), assignees);
640   - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables);
  646 + if (approveUserSelectAssignees == null) {
  647 + approveUserSelectAssignees = new HashMap<>();
  648 + }
  649 + approveUserSelectAssignees.put(nextFlowNode.getId(), assignees);
  650 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, approveUserSelectAssignees);
641 651 }
642 652 }
643 653 return variables;
... ... @@ -1174,12 +1184,26 @@ public class BpmTaskServiceImpl implements BpmTaskService {
1174 1184 }
1175 1185 updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus());
1176 1186  
1177   - // 2. 处理自动通过的情况,例如说:1)无审批人时,是否自动通过、不通过;2)非【人工审核】时,是否自动通过、不通过
1178 1187 ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
1179 1188 if (processInstance == null) {
1180 1189 log.error("[processTaskCreated][taskId({}) 没有找到流程实例]", task.getId());
1181 1190 return;
1182 1191 }
  1192 + BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.
  1193 + getProcessDefinitionInfo(processInstance.getProcessDefinitionId());
  1194 + if (processDefinitionInfo == null) {
  1195 + log.error("[processTaskCreated][processDefinitionId({}) 没有找到流程定义]", processInstance.getProcessDefinitionId());
  1196 + return;
  1197 + }
  1198 +
  1199 + // 2. 任务前置通知
  1200 + if (ObjUtil.isNotNull(processDefinitionInfo.getTaskBeforeTriggerSetting())){
  1201 + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getTaskBeforeTriggerSetting();
  1202 + BpmHttpRequestUtils.executeBpmHttpRequest(processInstance,
  1203 + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
  1204 + }
  1205 +
  1206 + // 3. 处理自动通过的情况,例如说:1)无审批人时,是否自动通过、不通过;2)非【人工审核】时,是否自动通过、不通过
1183 1207 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
1184 1208 FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
1185 1209 Integer approveType = BpmnModelUtils.parseApproveType(userTaskElement);
... ... @@ -1392,6 +1416,28 @@ public class BpmTaskServiceImpl implements BpmTaskService {
1392 1416 }
1393 1417  
1394 1418 @Override
  1419 + public void processTaskCompleted(Task task) {
  1420 + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
  1421 + if (processInstance == null) {
  1422 + log.error("[processTaskCompleted][taskId({}) 没有找到流程实例]", task.getId());
  1423 + return;
  1424 + }
  1425 + BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.
  1426 + getProcessDefinitionInfo(processInstance.getProcessDefinitionId());
  1427 + if (processDefinitionInfo == null) {
  1428 + log.error("[processTaskCompleted][processDefinitionId({}) 没有找到流程定义]", processInstance.getProcessDefinitionId());
  1429 + return;
  1430 + }
  1431 +
  1432 + // 任务后置通知
  1433 + if (ObjUtil.isNotNull(processDefinitionInfo.getTaskAfterTriggerSetting())){
  1434 + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getTaskAfterTriggerSetting();
  1435 + BpmHttpRequestUtils.executeBpmHttpRequest(processInstance,
  1436 + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
  1437 + }
  1438 + }
  1439 +
  1440 + @Override
1395 1441 @Transactional(rollbackFor = Exception.class)
1396 1442 public void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType) {
1397 1443 ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java
... ... @@ -53,10 +53,7 @@ public class BpmUserTaskListener implements TaskListener {
53 53 listenerHandler.getBody().add(new BpmSimpleModelNodeVO.HttpRequestParam().setKey("taskId")
54 54 .setType(BpmHttpRequestParamTypeEnum.FIXED_VALUE.getType()).setValue(delegateTask.getId()));
55 55 BpmHttpRequestUtils.executeBpmHttpRequest(processInstance,
56   - listenerHandler.getPath(),
57   - listenerHandler.getHeader(),
58   - listenerHandler.getBody(),
59   - false, null);
  56 + listenerHandler.getPath(), listenerHandler.getHeader(), listenerHandler.getBody(), false, null);
60 57  
61 58 // 3. 是否需要后续操作?TODO 芋艿:待定!
62 59 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java
... ... @@ -45,10 +45,7 @@ public class BpmHttpCallbackTrigger extends BpmAbstractHttpRequestTrigger {
45 45 .setKey("taskDefineKey") // 重要:回调请求 taskDefineKey 需要传给被调用方,用于回调执行
46 46 .setType(BpmHttpRequestParamTypeEnum.FIXED_VALUE.getType()).setValue(setting.getCallbackTaskDefineKey()));
47 47 BpmHttpRequestUtils.executeBpmHttpRequest(processInstance,
48   - setting.getUrl(),
49   - setting.getHeader(),
50   - setting.getBody(),
51   - false, null);
  48 + setting.getUrl(), setting.getHeader(), setting.getBody(), false, null);
52 49 }
53 50  
54 51 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmSyncHttpRequestTrigger.java
... ... @@ -40,10 +40,7 @@ public class BpmSyncHttpRequestTrigger extends BpmAbstractHttpRequestTrigger {
40 40 // 2. 发起请求
41 41 ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
42 42 BpmHttpRequestUtils.executeBpmHttpRequest(processInstance,
43   - setting.getUrl(),
44   - setting.getHeader(),
45   - setting.getBody(),
46   - true, setting.getResponse());
  43 + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
47 44 }
48 45  
49 46 }
... ...