diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index 65605142c2..d5d6fa77c4 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/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 { ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_005, "流程取消失败,该流程不允许取消"); ErrorCode PROCESS_INSTANCE_HTTP_TRIGGER_CALL_ERROR = new ErrorCode(1_009_004_006, "流程 Http 触发器请求调用失败"); ErrorCode PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_007, "下一个任务({})的审批人未配置"); + ErrorCode PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_008, "子流程取消失败,子流程不允许取消"); // ========== 流程任务 1-009-005-000 ========== ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java index b0ade75299..46d1482a5e 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java +++ b/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 { REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法 CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程 + CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS("子流程自动取消,原因:主流程已取消"), // ========== 流程任务的独有原因 ========== diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/dept/DeptSimpleBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/dept/DeptSimpleBaseVO.java new file mode 100644 index 0000000000..ba8049a4b6 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/base/dept/DeptSimpleBaseVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.base.dept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "部门精简信息 VO") +@Data +public class DeptSimpleBaseVO { + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "技术部") + private String name; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java index 5578114f9d..aa4c484fee 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java +++ b/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; import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; @@ -53,6 +55,8 @@ public class BpmModelController { @Resource private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; @GetMapping("/list") @Operation(summary = "获得模型分页") @@ -79,14 +83,19 @@ public class BpmModelController { List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds( deploymentMap.keySet()); Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); - // 获得 User Map + // 获得 User Map、Dept Map Set userIds = convertSetByFlatMap(list, model -> { BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); return metaInfo != null ? metaInfo.getStartUserIds().stream() : Stream.empty(); }); Map userMap = adminUserApi.getUserMap(userIds); + Set deptIds = convertSetByFlatMap(list, model -> { + BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); + return metaInfo != null && metaInfo.getStartDeptIds() != null ? metaInfo.getStartDeptIds().stream() : Stream.empty(); + }); + Map deptMap = deptApi.getDeptMap(deptIds); return success(BpmModelConvert.INSTANCE.buildModelList(list, - formMap, categoryMap, deploymentMap, processDefinitionMap, userMap)); + formMap, categoryMap, deploymentMap, processDefinitionMap, userMap, deptMap)); } @GetMapping("/get") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java index cf9ca3e5fd..d2316f58eb 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java +++ b/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 { @Schema(description = "可发起用户编号数组", example = "[1,2,3]") private List startUserIds; + @Schema(description = "可发起部门编号数组", example = "[2,4,6]") + private List startDeptIds; + @Schema(description = "可管理用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2,4,6]") @NotEmpty(message = "可管理用户编号数组不能为空") private List managerUserIds; @@ -88,6 +91,12 @@ public class BpmModelMetaInfoVO { @Schema(description = "流程后置通知设置", example = "{}") private HttpRequestSetting processAfterTriggerSetting; + @Schema(description = "任务前置通知设置", example = "{}") + private HttpRequestSetting taskBeforeTriggerSetting; + + @Schema(description = "任务后置通知设置", example = "{}") + private HttpRequestSetting taskAfterTriggerSetting; + @Schema(description = "流程 ID 规则") @Data @Valid diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java index 275368c7c6..6a9150aa27 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; +import cn.iocoder.yudao.module.bpm.controller.admin.base.dept.DeptSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; @@ -39,6 +40,9 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO { @Schema(description = "可发起的用户数组") private List startUsers; + @Schema(description = "可发起的部门数组") + private List startDepts; + @Schema(description = "BPMN XML") private String bpmnXml; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java index f002e6894a..1cbebe06e4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java +++ b/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 { /** * 条件节点设置 */ - private ConditionSetting conditionSetting; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE + private ConditionSetting conditionSetting; // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE @Schema(description = "路由分支组", example = "[]") private List routerGroups; @@ -241,7 +241,7 @@ public class BpmSimpleModelNodeVO { @Schema(description = "条件设置") @Data @Valid - // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE + // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE public static class ConditionSetting { @Schema(description = "条件类型", example = "1") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java index 9316261678..8a3777772e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java +++ b/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 { processDefinition, processDefinitionInfo, startUser, dept)); } - // TODO @lesan:【子流程】子流程如果取消,主流程应该是通过、还是不通过哈?还是禁用掉子流程的取消? @DeleteMapping("/cancel-by-start-user") @Operation(summary = "用户取消流程实例", description = "取消发起的流程") @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java index 888f59ada2..38c2bc1013 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java +++ b/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 { @Schema(description = "候选人用户列表") private List candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表 + @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf") + private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段) + } @Schema(description = "活动节点的任务信息") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java index 19ec8491ee..2101b22b28 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java +++ b/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; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.base.dept.DeptSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; 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 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; @@ -43,7 +45,8 @@ public interface BpmModelConvert { Map categoryMap, Map deploymentMap, Map processDefinitionMap, - Map userMap) { + Map userMap, + Map deptMap) { List result = convertList(list, model -> { BpmModelMetaInfoVO metaInfo = parseMetaInfo(model); BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; @@ -52,7 +55,8 @@ public interface BpmModelConvert { ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null; List startUsers = metaInfo != null ? convertList(metaInfo.getStartUserIds(), userMap::get) : null; - return buildModel0(model, metaInfo, form, category, deployment, processDefinition, startUsers); + List startDepts = metaInfo != null ? convertList(metaInfo.getStartDeptIds(), deptMap::get) : null; + return buildModel0(model, metaInfo, form, category, deployment, processDefinition, startUsers, startDepts); }); // 排序 result.sort(Comparator.comparing(BpmModelMetaInfoVO::getSort)); @@ -61,7 +65,7 @@ public interface BpmModelConvert { default BpmModelRespVO buildModel(Model model, byte[] bpmnBytes, BpmSimpleModelNodeVO simpleModel) { BpmModelMetaInfoVO metaInfo = parseMetaInfo(model); - BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null); + BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null, null, null); if (ArrayUtil.isNotEmpty(bpmnBytes)) { modelVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnBytes)); } @@ -72,7 +76,7 @@ public interface BpmModelConvert { default BpmModelRespVO buildModel0(Model model, BpmModelMetaInfoVO metaInfo, BpmFormDO form, BpmCategoryDO category, Deployment deployment, ProcessDefinition processDefinition, - List startUsers) { + List startUsers, List startDepts) { BpmModelRespVO modelRespVO = new BpmModelRespVO().setId(model.getId()).setName(model.getName()) .setKey(model.getKey()).setCategory(model.getCategory()) .setCreateTime(DateUtils.of(model.getCreateTime())); @@ -94,8 +98,9 @@ public interface BpmModelConvert { modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime())); } } - // User - modelRespVO.setStartUsers(BeanUtils.toBean(startUsers, UserSimpleBaseVO.class)); + // User、Dept + modelRespVO.setStartUsers(BeanUtils.toBean(startUsers, UserSimpleBaseVO.class)) + .setStartDepts(BeanUtils.toBean(startDepts, DeptSimpleBaseVO.class)); return modelRespVO; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java index 86c83ed611..c2799ef67f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -151,6 +151,14 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { @TableField(typeHandler = LongListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤 private List startUserIds; + /** + * 可发起部门编号数组 + * + * 关联 {@link AdminUserRespDTO#getDeptId()} 字段的数组 + */ + @TableField(typeHandler = LongListTypeHandler.class) + private List startDeptIds; + /** * 可管理用户编号数组 * @@ -199,4 +207,16 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private BpmModelMetaInfoVO.HttpRequestSetting processAfterTriggerSetting; + /** + * 任务前置通知设置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private BpmModelMetaInfoVO.HttpRequestSetting taskBeforeTriggerSetting; + + /** + * 任务后置通知设置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java index 329241f799..e50df0bcf0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java +++ b/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 { public static final Set TASK_EVENTS = ImmutableSet.builder() .add(FlowableEngineEventType.TASK_CREATED) .add(FlowableEngineEventType.TASK_ASSIGNED) -// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。 + .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,这里仅处理任务后置通知。 .add(FlowableEngineEventType.ACTIVITY_CANCELLED) .add(FlowableEngineEventType.TIMER_FIRED) // 监听审批超时 .build(); @@ -66,6 +66,11 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { taskService.processTaskAssigned((Task) event.getEntity()); } + @Override + protected void taskCompleted(FlowableEngineEntityEvent event) { + taskService.processTaskCompleted((Task) event.getEntity()); + } + @Override protected void activityCancelled(FlowableActivityCancelledEvent event) { List activityList = taskService.getHistoricActivityListByExecutionId(event.getExecutionId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index 3b5bad52c7..bd427e32f2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/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 { /** * 构建有附加节点的连线 * - * @param nodeId 当前节点 ID + * @param nodeId 当前节点 ID * @param attachNodeId 附属节点 ID * @param targetNodeId 目标节点 ID */ @@ -662,6 +662,10 @@ public class SimpleModelUtils { * 构造条件表达式 */ public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { + // 并行网关不需要设置条件 + if (conditionSetting == null) { + return null; + } return buildConditionExpression(conditionSetting.getConditionType(), conditionSetting.getConditionExpression(), conditionSetting.getConditionGroups()); } @@ -813,7 +817,6 @@ public class SimpleModelUtils { callActivity.setCalledElementType("key"); // 1. 是否异步 if (node.getChildProcessSetting().getAsync()) { - // TODO @lesan: 这里目前测试没有跳过执行call activity 后面的节点 callActivity.setAsynchronous(true); } @@ -959,8 +962,8 @@ public class SimpleModelUtils { if (nodeType == BpmSimpleModelNodeTypeEnum.CONDITION_BRANCH_NODE) { // 查找满足条件的 BpmSimpleModelNodeVO 节点 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), - conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) - && evalConditionExpress(variables, conditionNode.getConditionSetting())); + conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) + && evalConditionExpress(variables, conditionNode.getConditionSetting())); if (matchConditionNode == null) { matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); @@ -974,8 +977,8 @@ public class SimpleModelUtils { if (nodeType == BpmSimpleModelNodeTypeEnum.INCLUSIVE_BRANCH_NODE) { // 查找满足条件的 BpmSimpleModelNodeVO 节点 Collection matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), - conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) - && evalConditionExpress(variables, conditionNode.getConditionSetting())); + conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) + && evalConditionExpress(variables, conditionNode.getConditionSetting())); if (CollUtil.isEmpty(matchConditionNodes)) { matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java index 14ee084063..836b5181c7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java +++ b/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 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionInfoMapper; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; @@ -50,6 +52,9 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ @Resource private BpmProcessDefinitionInfoMapper processDefinitionMapper; + @Resource + private AdminUserApi adminUserApi; + @Override public ProcessDefinition getProcessDefinition(String id) { return repositoryService.getProcessDefinition(id); @@ -88,12 +93,22 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ if (processDefinition == null) { return false; } - // 为空,则所有人都可以发起 - if (CollUtil.isEmpty(processDefinition.getStartUserIds())) { - return true; + + // 校验用户是否在允许发起的用户列表中 + if (CollUtil.isNotEmpty(processDefinition.getStartUserIds())) { + return processDefinition.getStartUserIds().contains(userId); } - // 不为空,则需要存在里面 - return processDefinition.getStartUserIds().contains(userId); + + // 校验用户是否在允许发起的部门列表中 + if (CollUtil.isNotEmpty(processDefinition.getStartDeptIds())) { + AdminUserRespDTO user = adminUserApi.getUser(userId); + return user != null + && user.getDeptId() != null + && processDefinition.getStartDeptIds().contains(user.getDeptId()); + } + + // 都为空,则所有人都可以发起 + return true; } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 1e0a777d02..a46068040e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; @@ -63,7 +62,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.client.RestTemplate; import java.util.*; @@ -263,30 +261,31 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService processVariables.putAll(reqVO.getProcessVariables()); } - // 3 获取当前任务节点的信息 - // 3.1 获取下一个将要执行的节点集合 + // 3. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); List nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); - return convertList(nextFlowNodes, node -> { - List candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), - loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables); - // 3.2 获取节点的审批人信息 - Map userMap = adminUserApi.getUserMap(candidateUserIds); - // 3.3 获取节点的审批人部门信息 - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 3.4 存在一个节点多人审批的情况,组装审批人信息 - List candidateUsers = new ArrayList<>(); - userMap.forEach((key, value) -> candidateUsers.add(BpmProcessInstanceConvert.INSTANCE.buildUser(key, userMap, deptMap))); - return new ActivityNode().setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) - .setId(node.getId()) - .setName(node.getName()) - .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) - .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) - // TODO @小北:先把 candidateUserIds 设置完,然后最后拼接 candidateUsers 信息。这样,如果有多个节点,就不用重复查询啦;类似 buildApprovalDetail 思路; - // TODO 先拼接处 List ActivityNode - // TODO 接着,再起一段,处理 adminUserApi.getUserMap(candidateUserIds)、deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)) - .setCandidateUsers(candidateUsers); - }); + List nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId()) + .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) + .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) + .setCandidateUserIds(getTaskCandidateUserList(bpmnModel, node.getId(), + loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables))); + if (CollUtil.isNotEmpty(nextActivityNodes)) { + return nextActivityNodes; + } + + // 4. 拼接基础信息 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(nextActivityNodes, ActivityNode::getCandidateUserIds, Collection::stream)); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + nextActivityNodes.forEach(node -> node.setCandidateUsers(convertList(node.getCandidateUserIds(), userId -> { + AdminUserRespDTO user = userMap.get(userId); + if (user != null) { + return BpmProcessInstanceConvert.INSTANCE.buildUser(userId, userMap, deptMap); + } + return null; + }))); + return nextActivityNodes; } @Override @@ -388,8 +387,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService List activities, List tasks) { // 遍历 tasks 列表,只处理已结束的 UserTask // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 - // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程; - // TODO @lesan:【子流程】基于 activities 查询出 usertask、callactivity,然后拼接?如果是子流程,就是可以点击过去? List endTasks = filterList(tasks, task -> task.getEndTime() != null); List approvalNodes = convertList(endTasks, task -> { FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); @@ -411,7 +408,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 遍历 activities,只处理已结束的 StartEvent、EndEvent List endActivities = filterList(activities, activity -> activity.getEndTime() != null - && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END))); + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_CALL_ACTIVITY, ELEMENT_EVENT_END))); endActivities.forEach(activity -> { // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 if (ELEMENT_EVENT_START.equals(activity.getActivityType()) @@ -445,7 +442,20 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } approvalNodes.add(endNode); } + // CallActivity + if (ELEMENT_CALL_ACTIVITY.equals(activity.getActivityType())) { + ActivityNode callActivity = new ActivityNode().setId(activity.getId()) + .setName(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getName()) + .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) + .setStartTime(DateUtils.of(activity.getStartTime())) + .setEndTime(DateUtils.of(activity.getEndTime())) + .setProcessInstanceId(activity.getProcessInstanceId()); + approvalNodes.add(callActivity); + } }); + + // 按照时间排序 + approvalNodes.sort(Comparator.comparing(ActivityNode::getStartTime)); return approvalNodes; } @@ -465,7 +475,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService HistoricActivityInstance::getActivityId); // 按照 activityId 分组,构建 ApprovalNodeInfo 节点 - // TODO @lesan:【子流程】在子流程进行审批的时候,HistoricActivityInstance 里面可以拿到 runActivities.get(0).getCalledProcessInstanceId()。要不要支持跳转??? Map taskMap = convertMap(tasks, HistoricTaskInstance::getId); return convertList(runningTaskMap.entrySet(), entry -> { String activityId = entry.getKey(); @@ -511,6 +520,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } + if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { + activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId()); + } return activityNode; }); } @@ -824,6 +836,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW); } + // 1.4 子流程不允许取消 + if (StrUtil.isNotBlank(instance.getSuperExecutionId())) { + throw exception(PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW); + } // 2. 取消流程 updateProcessInstanceCancel(cancelReqVO.getId(), @@ -850,7 +866,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService BpmProcessInstanceStatusEnum.CANCEL.getStatus()); runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); - // 2. 结束流程 + // 2. 取消所有子流程 + List childProcessInstances = runtimeService.createProcessInstanceQuery() + .superProcessInstanceId(id).list(); + childProcessInstances.forEach(processInstance -> updateProcessInstanceCancel( + processInstance.getProcessInstanceId(), BpmReasonEnum.CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS.getReason())); + + // 3. 结束流程 taskService.moveTaskToEnd(id, reason); } @@ -915,10 +937,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting(); BpmHttpRequestUtils.executeBpmHttpRequest(instance, - setting.getUrl(), - setting.getHeader(), - setting.getBody(), - true, setting.getResponse()); + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } } }); @@ -937,10 +956,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService } BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); BpmHttpRequestUtils.executeBpmHttpRequest(instance, - setting.getUrl(), - setting.getHeader(), - setting.getBody(), - true, setting.getResponse()); + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); }); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index e99d974356..0a5c866fda 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -278,6 +278,13 @@ public interface BpmTaskService { */ void processTaskAssigned(Task task); + /** + * 处理 Task 完成事件,目前是发送任务后置通知 + * + * @param task 任务实体 + */ + void processTaskCompleted(Task task); + /** * 处理 Task 审批超时事件,可能会处理多个当前审批中的任务 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 6263e21bc1..efdb41951c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/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; import cn.hutool.core.util.*; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; @@ -23,6 +25,7 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; @@ -597,47 +600,54 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private Map validateAndSetNextAssignees(String taskDefinitionKey, Map variables, BpmnModel bpmnModel, Map> nextAssignees, ProcessInstance processInstance) { + // simple 设计器第一个节点默认为发起人节点,不校验是否存在审批人 + if (Objects.equals(taskDefinitionKey, START_USER_NODE_ID)) { + return variables; + } // 1. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); // 2. 校验选择的下一个节点的审批人,是否合法 - Map> processVariables; for (FlowNode nextFlowNode : nextFlowNodes) { Integer candidateStrategy = parseCandidateStrategy(nextFlowNode); // 2.1 情况一:如果节点中的审批人策略为 发起人自选 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) { + // 特殊:如果当前节点已经存在审批人,则不允许覆盖 + Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); + if (startUserSelectAssignees != null && CollUtil.isNotEmpty(startUserSelectAssignees.get(nextFlowNode.getId()))) { + continue; + } // 如果节点存在,但未配置审批人 List assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } - processVariables = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); - // 特殊:如果当前节点已经存在审批人,则不允许覆盖 - if (processVariables != null && CollUtil.isNotEmpty(processVariables.get(nextFlowNode.getId()))) { - continue; - } + // 设置 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES - if (processVariables == null) { - processVariables = new HashMap<>(); + if (startUserSelectAssignees == null) { + startUserSelectAssignees = new HashMap<>(); } - processVariables.put(nextFlowNode.getId(), assignees); - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, processVariables); + startUserSelectAssignees.put(nextFlowNode.getId(), assignees); + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); + continue; } + // 2.2 情况二:如果节点中的审批人策略为 审批人,在审批时选择下一个节点的审批人,并且该节点的审批人为空 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) { // 如果节点存在,但未配置审批人 + Map> approveUserSelectAssignees = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); List assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); } - processVariables = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables()); - if (processVariables == null) { - processVariables = new HashMap<>(); - } + // 设置 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES - processVariables.put(nextFlowNode.getId(), assignees); - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, processVariables); + if (approveUserSelectAssignees == null) { + approveUserSelectAssignees = new HashMap<>(); + } + approveUserSelectAssignees.put(nextFlowNode.getId(), assignees); + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES, approveUserSelectAssignees); } } return variables; @@ -1174,12 +1184,26 @@ public class BpmTaskServiceImpl implements BpmTaskService { } updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus()); - // 2. 处理自动通过的情况,例如说:1)无审批人时,是否自动通过、不通过;2)非【人工审核】时,是否自动通过、不通过 ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); if (processInstance == null) { log.error("[processTaskCreated][taskId({}) 没有找到流程实例]", task.getId()); return; } + BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService. + getProcessDefinitionInfo(processInstance.getProcessDefinitionId()); + if (processDefinitionInfo == null) { + log.error("[processTaskCreated][processDefinitionId({}) 没有找到流程定义]", processInstance.getProcessDefinitionId()); + return; + } + + // 2. 任务前置通知 + if (ObjUtil.isNotNull(processDefinitionInfo.getTaskBeforeTriggerSetting())){ + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getTaskBeforeTriggerSetting(); + BpmHttpRequestUtils.executeBpmHttpRequest(processInstance, + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); + } + + // 3. 处理自动通过的情况,例如说:1)无审批人时,是否自动通过、不通过;2)非【人工审核】时,是否自动通过、不通过 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); Integer approveType = BpmnModelUtils.parseApproveType(userTaskElement); @@ -1391,6 +1415,28 @@ public class BpmTaskServiceImpl implements BpmTaskService { }); } + @Override + public void processTaskCompleted(Task task) { + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (processInstance == null) { + log.error("[processTaskCompleted][taskId({}) 没有找到流程实例]", task.getId()); + return; + } + BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService. + getProcessDefinitionInfo(processInstance.getProcessDefinitionId()); + if (processDefinitionInfo == null) { + log.error("[processTaskCompleted][processDefinitionId({}) 没有找到流程定义]", processInstance.getProcessDefinitionId()); + return; + } + + // 任务后置通知 + if (ObjUtil.isNotNull(processDefinitionInfo.getTaskAfterTriggerSetting())){ + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getTaskAfterTriggerSetting(); + BpmHttpRequestUtils.executeBpmHttpRequest(processInstance, + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); + } + } + @Override @Transactional(rollbackFor = Exception.class) public void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java index 54fa9b12cd..48e2393b0f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java +++ b/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 { listenerHandler.getBody().add(new BpmSimpleModelNodeVO.HttpRequestParam().setKey("taskId") .setType(BpmHttpRequestParamTypeEnum.FIXED_VALUE.getType()).setValue(delegateTask.getId())); BpmHttpRequestUtils.executeBpmHttpRequest(processInstance, - listenerHandler.getPath(), - listenerHandler.getHeader(), - listenerHandler.getBody(), - false, null); + listenerHandler.getPath(), listenerHandler.getHeader(), listenerHandler.getBody(), false, null); // 3. 是否需要后续操作?TODO 芋艿:待定! } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java index 351b57ddd4..d2cc03e27a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java +++ b/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 { .setKey("taskDefineKey") // 重要:回调请求 taskDefineKey 需要传给被调用方,用于回调执行 .setType(BpmHttpRequestParamTypeEnum.FIXED_VALUE.getType()).setValue(setting.getCallbackTaskDefineKey())); BpmHttpRequestUtils.executeBpmHttpRequest(processInstance, - setting.getUrl(), - setting.getHeader(), - setting.getBody(), - false, null); + setting.getUrl(), setting.getHeader(), setting.getBody(), false, null); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmSyncHttpRequestTrigger.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmSyncHttpRequestTrigger.java index 2ac04117e4..cecbe6a3c8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmSyncHttpRequestTrigger.java +++ b/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 { // 2. 发起请求 ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId); BpmHttpRequestUtils.executeBpmHttpRequest(processInstance, - setting.getUrl(), - setting.getHeader(), - setting.getBody(), - true, setting.getResponse()); + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } }