Commit d1fead11daccc23551750ae8aa2e42425b945984
Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm
Showing
23 changed files
with
288 additions
and
83 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmChildProcessMultiInstanceSourceTypeEnum.java
| @@ -17,8 +17,8 @@ import java.util.Arrays; | @@ -17,8 +17,8 @@ import java.util.Arrays; | ||
| 17 | public enum BpmChildProcessMultiInstanceSourceTypeEnum implements ArrayValuable<Integer> { | 17 | public enum BpmChildProcessMultiInstanceSourceTypeEnum implements ArrayValuable<Integer> { |
| 18 | 18 | ||
| 19 | FIXED_QUANTITY(1, "固定数量"), | 19 | FIXED_QUANTITY(1, "固定数量"), |
| 20 | - DIGITAL_FORM(2, "数字表单"), | ||
| 21 | - MULTI_FORM(3, "多项表单"); | 20 | + NUMBER_FORM(2, "数字表单"), |
| 21 | + MULTIPLE_FORM(3, "多选表单"); | ||
| 22 | 22 | ||
| 23 | private final Integer type; | 23 | private final Integer type; |
| 24 | private final String name; | 24 | private final String name; |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java
| @@ -16,8 +16,9 @@ import java.util.Arrays; | @@ -16,8 +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 请求"), | ||
| 20 | - HTTP_CALLBACK(2, "发起 HTTP 回调"), | 19 | + HTTP_REQUEST(1, "发起 HTTP 请求"), // BPM => 业务,流程继续执行,无需等待业务 |
| 20 | + HTTP_CALLBACK(2, "接收 HTTP 回调"), // BPM => 业务 => BPM,流程卡主,等待业务回调 | ||
| 21 | + | ||
| 21 | FORM_UPDATE(10, "更新流程表单数据"), | 22 | FORM_UPDATE(10, "更新流程表单数据"), |
| 22 | FORM_DELETE(11, "删除流程表单数据"), | 23 | FORM_DELETE(11, "删除流程表单数据"), |
| 23 | ; | 24 | ; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java
| @@ -57,7 +57,7 @@ public class BpmModelController { | @@ -57,7 +57,7 @@ public class BpmModelController { | ||
| 57 | @GetMapping("/list") | 57 | @GetMapping("/list") |
| 58 | @Operation(summary = "获得模型分页") | 58 | @Operation(summary = "获得模型分页") |
| 59 | @Parameter(name = "name", description = "模型名称", example = "芋艿") | 59 | @Parameter(name = "name", description = "模型名称", example = "芋艿") |
| 60 | - public CommonResult<List<BpmModelRespVO>> getModelPage(@RequestParam(value = "name", required = false) String name) { | 60 | + public CommonResult<List<BpmModelRespVO>> getModelList(@RequestParam(value = "name", required = false) String name) { |
| 61 | List<Model> list = modelService.getModelList(name); | 61 | List<Model> list = modelService.getModelList(name); |
| 62 | if (CollUtil.isEmpty(list)) { | 62 | if (CollUtil.isEmpty(list)) { |
| 63 | return success(Collections.emptyList()); | 63 | return success(Collections.emptyList()); |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java
| @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 17 | import io.swagger.v3.oas.annotations.tags.Tag; | 17 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 18 | import jakarta.annotation.Resource; | 18 | import jakarta.annotation.Resource; |
| 19 | import org.flowable.bpmn.model.BpmnModel; | 19 | import org.flowable.bpmn.model.BpmnModel; |
| 20 | +import org.flowable.common.engine.impl.db.SuspensionState; | ||
| 20 | import org.flowable.engine.repository.Deployment; | 21 | import org.flowable.engine.repository.Deployment; |
| 21 | import org.flowable.engine.repository.ProcessDefinition; | 22 | import org.flowable.engine.repository.ProcessDefinition; |
| 22 | import org.springframework.security.access.prepost.PreAuthorize; | 23 | import org.springframework.security.access.prepost.PreAuthorize; |
| @@ -31,6 +32,7 @@ import java.util.List; | @@ -31,6 +32,7 @@ import java.util.List; | ||
| 31 | import java.util.Map; | 32 | import java.util.Map; |
| 32 | 33 | ||
| 33 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 34 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 35 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 34 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 36 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 35 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 37 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 36 | 38 | ||
| @@ -99,6 +101,17 @@ public class BpmProcessDefinitionController { | @@ -99,6 +101,17 @@ public class BpmProcessDefinitionController { | ||
| 99 | list, null, processDefinitionMap, null, null)); | 101 | list, null, processDefinitionMap, null, null)); |
| 100 | } | 102 | } |
| 101 | 103 | ||
| 104 | + @GetMapping("/simple-list") | ||
| 105 | + @Operation(summary = "获得流程定义精简列表", description = "只包含未挂起的流程,主要用于前端的下拉选项") | ||
| 106 | + public CommonResult<List<BpmProcessDefinitionRespVO>> getSimpleProcessDefinitionList() { | ||
| 107 | + // 只查询未挂起的流程 | ||
| 108 | + List<ProcessDefinition> list = processDefinitionService.getProcessDefinitionListBySuspensionState( | ||
| 109 | + SuspensionState.ACTIVE.getStateCode()); | ||
| 110 | + // 拼接 VO 返回,只返回 id、name、key | ||
| 111 | + return success(convertList(list, definition -> new BpmProcessDefinitionRespVO() | ||
| 112 | + .setId(definition.getId()).setName(definition.getName()).setKey(definition.getKey()))); | ||
| 113 | + } | ||
| 114 | + | ||
| 102 | @GetMapping ("/get") | 115 | @GetMapping ("/get") |
| 103 | @Operation(summary = "获得流程定义") | 116 | @Operation(summary = "获得流程定义") |
| 104 | @Parameter(name = "id", description = "流程编号", required = true, example = "1024") | 117 | @Parameter(name = "id", description = "流程编号", required = true, example = "1024") |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java
| @@ -25,7 +25,7 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO { | @@ -25,7 +25,7 @@ public class BpmModelRespVO extends BpmModelMetaInfoVO { | ||
| 25 | @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") | 25 | @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") |
| 26 | private String icon; | 26 | private String icon; |
| 27 | 27 | ||
| 28 | - @Schema(description = "流程分类编码", example = "1") | 28 | + @Schema(description = "流程分类编号", example = "1") |
| 29 | private String category; | 29 | private String category; |
| 30 | @Schema(description = "流程分类名字", example = "请假") | 30 | @Schema(description = "流程分类名字", example = "请假") |
| 31 | private String categoryName; | 31 | private String categoryName; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
| @@ -509,7 +509,7 @@ public class BpmSimpleModelNodeVO { | @@ -509,7 +509,7 @@ public class BpmSimpleModelNodeVO { | ||
| 509 | 509 | ||
| 510 | @Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | 510 | @Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") |
| 511 | @NotNull(message = "完成比例不能为空") | 511 | @NotNull(message = "完成比例不能为空") |
| 512 | - private Integer completeRatio; // TODO @lesan:approveRatio 要不这个,和上面保持一致? | 512 | + private Integer approveRatio; |
| 513 | 513 | ||
| 514 | @Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 514 | @Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 515 | @NotNull(message = "多实例来源类型不能为空") | 515 | @NotNull(message = "多实例来源类型不能为空") |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java
| 1 | package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; | 1 | package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 5 | import lombok.Data; |
| 5 | 6 | ||
| 6 | import java.time.LocalDateTime; | 7 | import java.time.LocalDateTime; |
| 7 | -import java.util.List; | ||
| 8 | 8 | ||
| 9 | @Schema(description = "管理后台 - 流程定义 Response VO") | 9 | @Schema(description = "管理后台 - 流程定义 Response VO") |
| 10 | @Data | 10 | @Data |
| 11 | -public class BpmProcessDefinitionRespVO { | 11 | +public class BpmProcessDefinitionRespVO extends BpmModelMetaInfoVO { |
| 12 | 12 | ||
| 13 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | 13 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 14 | private String id; | 14 | private String id; |
| @@ -22,36 +22,19 @@ public class BpmProcessDefinitionRespVO { | @@ -22,36 +22,19 @@ public class BpmProcessDefinitionRespVO { | ||
| 22 | @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") | 22 | @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") |
| 23 | private String key; | 23 | private String key; |
| 24 | 24 | ||
| 25 | - @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") | ||
| 26 | - private String icon; | ||
| 27 | - | ||
| 28 | - @Schema(description = "流程描述", example = "我是描述") | ||
| 29 | - private String description; | ||
| 30 | - | ||
| 31 | @Schema(description = "流程分类", example = "1") | 25 | @Schema(description = "流程分类", example = "1") |
| 32 | private String category; | 26 | private String category; |
| 33 | @Schema(description = "流程分类名字", example = "请假") | 27 | @Schema(description = "流程分类名字", example = "请假") |
| 34 | private String categoryName; | 28 | private String categoryName; |
| 35 | 29 | ||
| 30 | + @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC") | ||
| 31 | + private String modelId; | ||
| 32 | + | ||
| 36 | @Schema(description = "流程模型的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | 33 | @Schema(description = "流程模型的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| 37 | private Integer modelType; // 参见 BpmModelTypeEnum 枚举类 | 34 | private Integer modelType; // 参见 BpmModelTypeEnum 枚举类 |
| 38 | 35 | ||
| 39 | - @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") | ||
| 40 | - private Integer formType; | ||
| 41 | - @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") | ||
| 42 | - private Long formId; | ||
| 43 | @Schema(description = "表单名字", example = "请假表单") | 36 | @Schema(description = "表单名字", example = "请假表单") |
| 44 | private String formName; | 37 | private String formName; |
| 45 | - @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 46 | - private String formConf; | ||
| 47 | - @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 48 | - private List<String> formFields; | ||
| 49 | - @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", | ||
| 50 | - example = "/bpm/oa/leave/create") | ||
| 51 | - private String formCustomCreatePath; | ||
| 52 | - @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", | ||
| 53 | - example = "/bpm/oa/leave/view") | ||
| 54 | - private String formCustomViewPath; | ||
| 55 | 38 | ||
| 56 | @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 39 | @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 57 | private Integer suspensionState; // 参见 SuspensionState 枚举 | 40 | private Integer suspensionState; // 参见 SuspensionState 枚举 |
| @@ -67,7 +50,7 @@ public class BpmProcessDefinitionRespVO { | @@ -67,7 +50,7 @@ public class BpmProcessDefinitionRespVO { | ||
| 67 | 50 | ||
| 68 | @Schema(description = "流程定义排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | 51 | @Schema(description = "流程定义排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 69 | private Long sort; | 52 | private Long sort; |
| 70 | - | 53 | + |
| 71 | @Schema(description = "BPMN UserTask 用户任务") | 54 | @Schema(description = "BPMN UserTask 用户任务") |
| 72 | @Data | 55 | @Data |
| 73 | public static class UserTask { | 56 | public static class UserTask { |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
| @@ -32,10 +32,10 @@ import org.springframework.web.bind.annotation.*; | @@ -32,10 +32,10 @@ import org.springframework.web.bind.annotation.*; | ||
| 32 | 32 | ||
| 33 | import java.util.List; | 33 | import java.util.List; |
| 34 | import java.util.Map; | 34 | import java.util.Map; |
| 35 | +import java.util.Set; | ||
| 35 | 36 | ||
| 36 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 37 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 37 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 38 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 38 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 39 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 39 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 40 | 40 | ||
| 41 | @Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” | 41 | @Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” |
| @@ -78,8 +78,14 @@ public class BpmProcessInstanceController { | @@ -78,8 +78,14 @@ public class BpmProcessInstanceController { | ||
| 78 | convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); | 78 | convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); |
| 79 | Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( | 79 | Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( |
| 80 | convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); | 80 | convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); |
| 81 | + Set<Long> userIds = convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId())); | ||
| 82 | + userIds.addAll(convertSetByFlatMap(taskMap.values(), | ||
| 83 | + tasks -> tasks.stream().map(Task::getAssignee).filter(StrUtil::isNotBlank).map(Long::parseLong))); | ||
| 84 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); | ||
| 85 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( | ||
| 86 | + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 81 | return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, | 87 | return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, |
| 82 | - processDefinitionMap, categoryMap, taskMap, null, null, processDefinitionInfoMap)); | 88 | + processDefinitionMap, categoryMap, taskMap, userMap, deptMap, processDefinitionInfoMap)); |
| 83 | } | 89 | } |
| 84 | 90 | ||
| 85 | @GetMapping("/manager-page") | 91 | @GetMapping("/manager-page") |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; | ||
| 3 | import cn.iocoder.yudao.framework.common.core.KeyValue; | 3 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 4 | import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; | 4 | import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; |
| 5 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; |
| 6 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 6 | import io.swagger.v3.oas.annotations.media.Schema; | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 7 | import lombok.Data; | 8 | import lombok.Data; |
| 8 | 9 | ||
| @@ -73,6 +74,13 @@ public class BpmProcessInstanceRespVO { | @@ -73,6 +74,13 @@ public class BpmProcessInstanceRespVO { | ||
| 73 | @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") | 74 | @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") |
| 74 | private String name; | 75 | private String name; |
| 75 | 76 | ||
| 77 | + @Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") | ||
| 78 | + @JsonIgnore // 不返回,只是方便后续读取,赋值给 assigneeUser | ||
| 79 | + private Long assignee; | ||
| 80 | + | ||
| 81 | + @Schema(description = "任务分配人", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") | ||
| 82 | + private UserSimpleBaseVO assigneeUser; | ||
| 83 | + | ||
| 76 | } | 84 | } |
| 77 | 85 | ||
| 78 | } | 86 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
| @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | import jakarta.validation.constraints.NotEmpty; | 4 | import jakarta.validation.constraints.NotEmpty; |
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | 6 | ||
| 7 | +import java.util.List; | ||
| 7 | import java.util.Map; | 8 | import java.util.Map; |
| 8 | 9 | ||
| 9 | @Schema(description = "管理后台 - 通过流程任务的 Request VO") | 10 | @Schema(description = "管理后台 - 通过流程任务的 Request VO") |
| @@ -23,4 +24,7 @@ public class BpmTaskApproveReqVO { | @@ -23,4 +24,7 @@ public class BpmTaskApproveReqVO { | ||
| 23 | @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) | 24 | @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) |
| 24 | private Map<String, Object> variables; | 25 | private Map<String, Object> variables; |
| 25 | 26 | ||
| 27 | + @Schema(description = "下一个节点审批人", example = "{nodeId:[1, 2]}") | ||
| 28 | + private Map<String, List<Long>> nextAssignees; // 为什么是 Map,而不是 List 呢?因为下一个节点可能是多个,例如说并行网关的情况 | ||
| 29 | + | ||
| 26 | } | 30 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java
| @@ -18,6 +18,9 @@ public class BpmTaskPageReqVO extends PageParam { | @@ -18,6 +18,9 @@ public class BpmTaskPageReqVO extends PageParam { | ||
| 18 | @Schema(description = "流程分类", example = "1") | 18 | @Schema(description = "流程分类", example = "1") |
| 19 | private String category; | 19 | private String category; |
| 20 | 20 | ||
| 21 | + @Schema(description = "流程定义的标识", example = "2048") | ||
| 22 | + private String processDefinitionKey; // 精准匹配 | ||
| 23 | + | ||
| 21 | @Schema(description = "创建时间") | 24 | @Schema(description = "创建时间") |
| 22 | @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 25 | @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 23 | private LocalDateTime[] createTime; | 26 | private LocalDateTime[] createTime; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
| @@ -76,6 +76,15 @@ public interface BpmProcessInstanceConvert { | @@ -76,6 +76,15 @@ public interface BpmProcessInstanceConvert { | ||
| 76 | respVO.setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class)); | 76 | respVO.setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class)); |
| 77 | MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); | 77 | MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); |
| 78 | } | 78 | } |
| 79 | + if (CollUtil.isNotEmpty(respVO.getTasks())) { | ||
| 80 | + respVO.getTasks().forEach(task -> { | ||
| 81 | + AdminUserRespDTO assigneeUser = userMap.get(task.getAssignee()); | ||
| 82 | + if (assigneeUser!= null) { | ||
| 83 | + task.setAssigneeUser(BeanUtils.toBean(assigneeUser, UserSimpleBaseVO.class)); | ||
| 84 | + MapUtils.findAndThen(deptMap, assigneeUser.getDeptId(), dept -> task.getAssigneeUser().setDeptName(dept.getName())); | ||
| 85 | + } | ||
| 86 | + }); | ||
| 87 | + } | ||
| 79 | } | 88 | } |
| 80 | // 摘要 | 89 | // 摘要 |
| 81 | respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()), | 90 | respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()), |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java
| @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; | 4 | import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; |
| 5 | -import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; | ||
| 6 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; |
| 7 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmAutoApproveTypeEnum; | 6 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmAutoApproveTypeEnum; |
| 8 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; | 7 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; |
| @@ -61,6 +60,14 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { | @@ -61,6 +60,14 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { | ||
| 61 | private Integer modelType; | 60 | private Integer modelType; |
| 62 | 61 | ||
| 63 | /** | 62 | /** |
| 63 | + * 流程分类的编码 | ||
| 64 | + * | ||
| 65 | + * 关联 {@link BpmCategoryDO#getCode()} | ||
| 66 | + * | ||
| 67 | + * 为什么要存储?原因是,{@link ProcessDefinition#getCategory()} 无法设置 | ||
| 68 | + */ | ||
| 69 | + private String category; | ||
| 70 | + /** | ||
| 64 | * 图标 | 71 | * 图标 |
| 65 | */ | 72 | */ |
| 66 | private String icon; | 73 | private String icon; |
| @@ -149,7 +156,7 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { | @@ -149,7 +156,7 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { | ||
| 149 | * | 156 | * |
| 150 | * 关联 {@link AdminUserRespDTO#getId()} 字段的数组 | 157 | * 关联 {@link AdminUserRespDTO#getId()} 字段的数组 |
| 151 | */ | 158 | */ |
| 152 | - @TableField(typeHandler = StringListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤 | 159 | + @TableField(typeHandler = LongListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤 |
| 153 | private List<Long> managerUserIds; | 160 | private List<Long> managerUserIds; |
| 154 | 161 | ||
| 155 | /** | 162 | /** |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java
| @@ -77,10 +77,10 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav | @@ -77,10 +77,10 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav | ||
| 77 | if (execution.getCurrentFlowElement() instanceof CallActivity) { | 77 | if (execution.getCurrentFlowElement() instanceof CallActivity) { |
| 78 | FlowElement flowElement = execution.getCurrentFlowElement(); | 78 | FlowElement flowElement = execution.getCurrentFlowElement(); |
| 79 | Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); | 79 | Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); |
| 80 | - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { | 80 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType())) { |
| 81 | return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); | 81 | return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); |
| 82 | } | 82 | } |
| 83 | - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | 83 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { |
| 84 | return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); | 84 | return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); |
| 85 | } | 85 | } |
| 86 | } | 86 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java
| @@ -71,10 +71,10 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB | @@ -71,10 +71,10 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB | ||
| 71 | if (execution.getCurrentFlowElement() instanceof CallActivity) { | 71 | if (execution.getCurrentFlowElement() instanceof CallActivity) { |
| 72 | FlowElement flowElement = execution.getCurrentFlowElement(); | 72 | FlowElement flowElement = execution.getCurrentFlowElement(); |
| 73 | Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); | 73 | Integer sourceType = BpmnModelUtils.parseMultiInstanceSourceType(flowElement); |
| 74 | - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType())) { | 74 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType())) { |
| 75 | return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); | 75 | return execution.getVariable(super.collectionExpression.getExpressionText(), Integer.class); |
| 76 | } | 76 | } |
| 77 | - if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | 77 | + if (sourceType.equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { |
| 78 | return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); | 78 | return execution.getVariable(super.collectionExpression.getExpressionText(), List.class).size(); |
| 79 | } | 79 | } |
| 80 | } | 80 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java
| @@ -2,24 +2,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d | @@ -2,24 +2,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | -import cn.hutool.core.util.ObjectUtil; | ||
| 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; | 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; |
| 7 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; | 6 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; |
| 8 | -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | ||
| 9 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; | 7 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| 10 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | 8 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 11 | import com.google.common.collect.Sets; | 9 | import com.google.common.collect.Sets; |
| 12 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 13 | import org.flowable.bpmn.model.BpmnModel; | 11 | import org.flowable.bpmn.model.BpmnModel; |
| 14 | -import org.flowable.bpmn.model.ServiceTask; | ||
| 15 | -import org.flowable.bpmn.model.Task; | ||
| 16 | -import org.flowable.bpmn.model.UserTask; | ||
| 17 | import org.flowable.engine.delegate.DelegateExecution; | 12 | import org.flowable.engine.delegate.DelegateExecution; |
| 18 | import org.flowable.engine.runtime.ProcessInstance; | 13 | import org.flowable.engine.runtime.ProcessInstance; |
| 19 | import org.springframework.context.annotation.Lazy; | 14 | import org.springframework.context.annotation.Lazy; |
| 20 | import org.springframework.stereotype.Component; | 15 | import org.springframework.stereotype.Component; |
| 21 | 16 | ||
| 22 | -import java.util.*; | 17 | +import java.util.LinkedHashSet; |
| 18 | +import java.util.List; | ||
| 19 | +import java.util.Map; | ||
| 23 | 20 | ||
| 24 | /** | 21 | /** |
| 25 | * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 | 22 | * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 |
| @@ -55,7 +52,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand | @@ -55,7 +52,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand | ||
| 55 | execution.getProcessInstanceId()); | 52 | execution.getProcessInstanceId()); |
| 56 | // 获得审批人 | 53 | // 获得审批人 |
| 57 | List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); | 54 | List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); |
| 58 | - return new LinkedHashSet<>(assignees); | 55 | + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet(); |
| 59 | } | 56 | } |
| 60 | 57 | ||
| 61 | @Override | 58 | @Override |
| @@ -70,28 +67,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand | @@ -70,28 +67,7 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand | ||
| 70 | } | 67 | } |
| 71 | // 获得审批人 | 68 | // 获得审批人 |
| 72 | List<Long> assignees = startUserSelectAssignees.get(activityId); | 69 | List<Long> assignees = startUserSelectAssignees.get(activityId); |
| 73 | - return new LinkedHashSet<>(assignees); | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - /** | ||
| 77 | - * 获得发起人自选审批人或抄送人的 Task 列表 | ||
| 78 | - * | ||
| 79 | - * @param bpmnModel BPMN 模型 | ||
| 80 | - * @return Task 列表 | ||
| 81 | - */ | ||
| 82 | - public static List<Task> getStartUserSelectTaskList(BpmnModel bpmnModel) { | ||
| 83 | - if (bpmnModel == null) { | ||
| 84 | - return Collections.emptyList(); | ||
| 85 | - } | ||
| 86 | - List<Task> tasks = new ArrayList<>(); | ||
| 87 | - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class)); | ||
| 88 | - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, ServiceTask.class)); | ||
| 89 | - if (CollUtil.isEmpty(tasks)) { | ||
| 90 | - return Collections.emptyList(); | ||
| 91 | - } | ||
| 92 | - tasks.removeIf(task -> ObjectUtil.notEqual(BpmnModelUtils.parseCandidateStrategy(task), | ||
| 93 | - BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())); | ||
| 94 | - return tasks; | 70 | + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet(); |
| 95 | } | 71 | } |
| 96 | 72 | ||
| 97 | } | 73 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| @@ -809,6 +809,7 @@ public class BpmnModelUtils { | @@ -809,6 +809,7 @@ public class BpmnModelUtils { | ||
| 809 | if (currentElement instanceof ExclusiveGateway) { | 809 | if (currentElement instanceof ExclusiveGateway) { |
| 810 | // 查找满足条件的 SequenceFlow 路径 | 810 | // 查找满足条件的 SequenceFlow 路径 |
| 811 | Gateway gateway = (Gateway) currentElement; | 811 | Gateway gateway = (Gateway) currentElement; |
| 812 | + // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题。需要优化,具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761 | ||
| 812 | SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | 813 | SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), |
| 813 | flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) | 814 | flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) |
| 814 | && (evalConditionExpress(variables, flow.getConditionExpression()))); | 815 | && (evalConditionExpress(variables, flow.getConditionExpression()))); |
| @@ -858,6 +859,130 @@ public class BpmnModelUtils { | @@ -858,6 +859,130 @@ public class BpmnModelUtils { | ||
| 858 | } | 859 | } |
| 859 | 860 | ||
| 860 | /** | 861 | /** |
| 862 | + * 根据当前节点,获取下一个节点 | ||
| 863 | + * | ||
| 864 | + * @param currentElement 当前节点 | ||
| 865 | + * @param bpmnModel BPMN模型 | ||
| 866 | + * @param variables 流程变量 | ||
| 867 | + */ | ||
| 868 | + @SuppressWarnings("PatternVariableCanBeUsed") | ||
| 869 | + public static List<FlowNode> getNextFlowNodes(FlowElement currentElement, BpmnModel bpmnModel, | ||
| 870 | + Map<String, Object> variables){ | ||
| 871 | + List<FlowNode> nextFlowNodes = new ArrayList<>(); // 下一个执行的流程节点集合 | ||
| 872 | + FlowNode currentNode = (FlowNode) currentElement; // 当前执行节点的基本属性 | ||
| 873 | + List<SequenceFlow> outgoingFlows = currentNode.getOutgoingFlows(); // 当前节点的关联节点 | ||
| 874 | + if (CollUtil.isEmpty(outgoingFlows)) { | ||
| 875 | + log.warn("[getNextFlowNodes][当前节点({}) 的 outgoingFlows 为空]", currentNode.getId()); | ||
| 876 | + return nextFlowNodes; | ||
| 877 | + } | ||
| 878 | + | ||
| 879 | + // 遍历每个出口流 | ||
| 880 | + for (SequenceFlow outgoingFlow : outgoingFlows) { | ||
| 881 | + // 获取目标节点的基本属性 | ||
| 882 | + FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef()); | ||
| 883 | + if (targetElement == null) { | ||
| 884 | + continue; | ||
| 885 | + } | ||
| 886 | + // 情况一:处理不同类型的网关 | ||
| 887 | + if (targetElement instanceof Gateway) { | ||
| 888 | + Gateway gateway = (Gateway) targetElement; | ||
| 889 | + if (gateway instanceof ExclusiveGateway) { | ||
| 890 | + handleExclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); | ||
| 891 | + } else if (gateway instanceof InclusiveGateway) { | ||
| 892 | + handleInclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); | ||
| 893 | + } else if (gateway instanceof ParallelGateway) { | ||
| 894 | + handleParallelGateway(gateway, bpmnModel, variables, nextFlowNodes); | ||
| 895 | + } | ||
| 896 | + } else { | ||
| 897 | + // 情况二:如果不是网关,直接添加到下一个节点列表 | ||
| 898 | + nextFlowNodes.add((FlowNode) targetElement); | ||
| 899 | + } | ||
| 900 | + } | ||
| 901 | + return nextFlowNodes; | ||
| 902 | + } | ||
| 903 | + | ||
| 904 | + /** | ||
| 905 | + * 处理排它网关 | ||
| 906 | + * | ||
| 907 | + * @param gateway 排他网关 | ||
| 908 | + * @param bpmnModel BPMN模型 | ||
| 909 | + * @param variables 流程变量 | ||
| 910 | + * @param nextFlowNodes 下一个执行的流程节点集合 | ||
| 911 | + */ | ||
| 912 | + private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, | ||
| 913 | + Map<String, Object> variables, List<FlowNode> nextFlowNodes) { | ||
| 914 | + // TODO @小北: 这里和 simulateNextFlowElements 中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋艿 | ||
| 915 | + // TODO @小北:ok,把 simulateNextFlowElements 里面处理网关的,复用这个方法,可以么? | ||
| 916 | + SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||
| 917 | + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) | ||
| 918 | + && (evalConditionExpress(variables, flow.getConditionExpression()))); | ||
| 919 | + if (matchSequenceFlow == null) { | ||
| 920 | + matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), | ||
| 921 | + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); | ||
| 922 | + // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 | ||
| 923 | + if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) { | ||
| 924 | + matchSequenceFlow = gateway.getOutgoingFlows().get(0); | ||
| 925 | + } | ||
| 926 | + } | ||
| 927 | + // 遍历满足条件的 SequenceFlow 路径 | ||
| 928 | + if (matchSequenceFlow != null) { | ||
| 929 | + FlowElement targetElement = bpmnModel.getFlowElement(matchSequenceFlow.getTargetRef()); | ||
| 930 | + if (targetElement instanceof FlowNode) { | ||
| 931 | + nextFlowNodes.add((FlowNode) targetElement); | ||
| 932 | + } | ||
| 933 | + } | ||
| 934 | + } | ||
| 935 | + | ||
| 936 | + /** | ||
| 937 | + * 处理包容网关 | ||
| 938 | + * | ||
| 939 | + * @param gateway 排他网关 | ||
| 940 | + * @param bpmnModel BPMN模型 | ||
| 941 | + * @param variables 流程变量 | ||
| 942 | + * @param nextFlowNodes 下一个执行的流程节点集合 | ||
| 943 | + */ | ||
| 944 | + private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel, | ||
| 945 | + Map<String, Object> variables, List<FlowNode> nextFlowNodes) { | ||
| 946 | + Collection<SequenceFlow> matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), | ||
| 947 | + flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) | ||
| 948 | + && evalConditionExpress(variables, flow.getConditionExpression())); | ||
| 949 | + if (CollUtil.isEmpty(matchSequenceFlows)) { | ||
| 950 | + matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), | ||
| 951 | + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId())); | ||
| 952 | + // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的 | ||
| 953 | + if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) { | ||
| 954 | + matchSequenceFlows = gateway.getOutgoingFlows(); | ||
| 955 | + } | ||
| 956 | + } | ||
| 957 | + // 遍历满足条件的 SequenceFlow 路径,获取目标节点 | ||
| 958 | + matchSequenceFlows.forEach(flow -> { | ||
| 959 | + FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); | ||
| 960 | + if (targetElement instanceof FlowNode) { | ||
| 961 | + nextFlowNodes.add((FlowNode) targetElement); | ||
| 962 | + } | ||
| 963 | + }); | ||
| 964 | + } | ||
| 965 | + | ||
| 966 | + /** | ||
| 967 | + * 处理并行网关 | ||
| 968 | + * | ||
| 969 | + * @param gateway 排他网关 | ||
| 970 | + * @param bpmnModel BPMN模型 | ||
| 971 | + * @param variables 流程变量 | ||
| 972 | + * @param nextFlowNodes 下一个执行的流程节点集合 | ||
| 973 | + */ | ||
| 974 | + private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel, | ||
| 975 | + Map<String, Object> variables, List<FlowNode> nextFlowNodes) { | ||
| 976 | + // 并行网关,遍历所有出口路径,获取目标节点 | ||
| 977 | + gateway.getOutgoingFlows().forEach(flow -> { | ||
| 978 | + FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); | ||
| 979 | + if (targetElement instanceof FlowNode) { | ||
| 980 | + nextFlowNodes.add((FlowNode) targetElement); | ||
| 981 | + } | ||
| 982 | + }); | ||
| 983 | + } | ||
| 984 | + | ||
| 985 | + /** | ||
| 861 | * 计算条件表达式是否为 true 满足条件 | 986 | * 计算条件表达式是否为 true 满足条件 |
| 862 | * | 987 | * |
| 863 | * @param variables 流程实例 | 988 | * @param variables 流程实例 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| @@ -25,7 +25,6 @@ import org.springframework.util.MultiValueMap; | @@ -25,7 +25,6 @@ import org.springframework.util.MultiValueMap; | ||
| 25 | 25 | ||
| 26 | import java.util.*; | 26 | import java.util.*; |
| 27 | 27 | ||
| 28 | -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum.HTTP_CALLBACK; | ||
| 29 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | 28 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; |
| 30 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; | 29 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; |
| 31 | import static java.util.Arrays.asList; | 30 | import static java.util.Arrays.asList; |
| @@ -737,13 +736,12 @@ public class SimpleModelUtils { | @@ -737,13 +736,12 @@ public class SimpleModelUtils { | ||
| 737 | 736 | ||
| 738 | public static class TriggerNodeConvert implements NodeConvert { | 737 | public static class TriggerNodeConvert implements NodeConvert { |
| 739 | 738 | ||
| 740 | - // TODO @芋艿:【回调】在看看 | ||
| 741 | @Override | 739 | @Override |
| 742 | public List<? extends FlowElement> convertList(BpmSimpleModelNodeVO node) { | 740 | public List<? extends FlowElement> convertList(BpmSimpleModelNodeVO node) { |
| 743 | Assert.notNull(node.getTriggerSetting(), "触发器节点设置不能为空"); | 741 | Assert.notNull(node.getTriggerSetting(), "触发器节点设置不能为空"); |
| 744 | List<FlowElement> flowElements = new ArrayList<>(2); | 742 | List<FlowElement> flowElements = new ArrayList<>(2); |
| 745 | // HTTP 回调请求。需要附加一个 ReceiveTask、发起请求后、等待回调执行 | 743 | // HTTP 回调请求。需要附加一个 ReceiveTask、发起请求后、等待回调执行 |
| 746 | - if (HTTP_CALLBACK.getType().equals(node.getTriggerSetting().getType())) { | 744 | + if (BpmTriggerTypeEnum.HTTP_CALLBACK.getType().equals(node.getTriggerSetting().getType())) { |
| 747 | Assert.notNull(node.getTriggerSetting().getHttpRequestSetting(), "触发器 HTTP 回调请求设置不能为空"); | 745 | Assert.notNull(node.getTriggerSetting().getHttpRequestSetting(), "触发器 HTTP 回调请求设置不能为空"); |
| 748 | ReceiveTask receiveTask = new ReceiveTask(); | 746 | ReceiveTask receiveTask = new ReceiveTask(); |
| 749 | receiveTask.setId("Activity_" + IdUtil.fastUUID()); | 747 | receiveTask.setId("Activity_" + IdUtil.fastUUID()); |
| @@ -875,13 +873,12 @@ public class SimpleModelUtils { | @@ -875,13 +873,12 @@ public class SimpleModelUtils { | ||
| 875 | if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY.getType())) { | 873 | if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY.getType())) { |
| 876 | multiInstanceCharacteristics.setLoopCardinality(childProcessSetting.getMultiInstanceSetting().getSource()); | 874 | multiInstanceCharacteristics.setLoopCardinality(childProcessSetting.getMultiInstanceSetting().getSource()); |
| 877 | } | 875 | } |
| 878 | - if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.DIGITAL_FORM.getType()) || | ||
| 879 | - childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTI_FORM.getType())) { | 876 | + if (childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM.getType()) || |
| 877 | + childProcessSetting.getMultiInstanceSetting().getSourceType().equals(BpmChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM.getType())) { | ||
| 880 | multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource()); | 878 | multiInstanceCharacteristics.setInputDataItem(childProcessSetting.getMultiInstanceSetting().getSource()); |
| 881 | } | 879 | } |
| 882 | -// TODO @lesan:String.format(approveMethodEnum.getCompletionCondition(), String.format("%.2f", approveRatio / 100D))); | ||
| 883 | - multiInstanceCharacteristics.setCompletionCondition(String.format("${ nrOfCompletedInstances/nrOfInstances >= %s}", | ||
| 884 | - String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getCompleteRatio() / 100D))); | 880 | + multiInstanceCharacteristics.setCompletionCondition(String.format(BpmUserTaskApproveMethodEnum.RATIO.getCompletionCondition(), |
| 881 | + String.format("%.2f", childProcessSetting.getMultiInstanceSetting().getApproveRatio() / 100D))); | ||
| 885 | callActivity.setLoopCharacteristics(multiInstanceCharacteristics); | 882 | callActivity.setLoopCharacteristics(multiInstanceCharacteristics); |
| 886 | addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType()); | 883 | addExtensionElement(callActivity, CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE, childProcessSetting.getMultiInstanceSetting().getSourceType()); |
| 887 | } | 884 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
| @@ -143,9 +143,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | @@ -143,9 +143,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||
| 143 | 143 | ||
| 144 | // 插入拓展表 | 144 | // 插入拓展表 |
| 145 | BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) | 145 | BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) |
| 146 | - .setModelId(model.getId()).setProcessDefinitionId(definition.getId()) | 146 | + .setModelId(model.getId()).setCategory(model.getCategory()).setProcessDefinitionId(definition.getId()) |
| 147 | .setModelType(modelMetaInfo.getType()).setSimpleModel(simpleJson); | 147 | .setModelType(modelMetaInfo.getType()).setSimpleModel(simpleJson); |
| 148 | - | ||
| 149 | if (form != null) { | 148 | if (form != null) { |
| 150 | definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); | 149 | definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); |
| 151 | } | 150 | } |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
| @@ -85,7 +85,6 @@ public interface BpmProcessInstanceService { | @@ -85,7 +85,6 @@ public interface BpmProcessInstanceService { | ||
| 85 | PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, | 85 | PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, |
| 86 | @Valid BpmProcessInstancePageReqVO pageReqVO); | 86 | @Valid BpmProcessInstancePageReqVO pageReqVO); |
| 87 | 87 | ||
| 88 | - // TODO @芋艿:重点在 review 下 | ||
| 89 | /** | 88 | /** |
| 90 | * 获取审批详情。 | 89 | * 获取审批详情。 |
| 91 | * <p> | 90 | * <p> |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| @@ -175,7 +175,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -175,7 +175,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 175 | } | 175 | } |
| 176 | startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); | 176 | startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); |
| 177 | processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); | 177 | processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); |
| 178 | - processVariables = historicProcessInstance.getProcessVariables(); | 178 | + // 合并 DB 和前端传递的流量变量,以前端的为主 |
| 179 | + Map<String, Object> historicVariables = historicProcessInstance.getProcessVariables(); | ||
| 180 | + if (CollUtil.isNotEmpty(processVariables)) { | ||
| 181 | + historicVariables.putAll(processVariables); | ||
| 182 | + } | ||
| 183 | + processVariables = historicVariables; | ||
| 179 | } | 184 | } |
| 180 | // 1.3 读取其它相关数据 | 185 | // 1.3 读取其它相关数据 |
| 181 | ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( | 186 | ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| @@ -20,6 +20,8 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; | @@ -20,6 +20,8 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; | ||
| 20 | import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; | 20 | import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; |
| 21 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; | 21 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; |
| 22 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; | 22 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; |
| 23 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; | ||
| 24 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | ||
| 23 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; | 25 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; |
| 24 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | 26 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| 25 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; | 27 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; |
| @@ -120,6 +122,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -120,6 +122,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 120 | if (StrUtil.isNotEmpty(pageVO.getCategory())) { | 122 | if (StrUtil.isNotEmpty(pageVO.getCategory())) { |
| 121 | taskQuery.taskCategory(pageVO.getCategory()); | 123 | taskQuery.taskCategory(pageVO.getCategory()); |
| 122 | } | 124 | } |
| 125 | + if (StrUtil.isNotEmpty(pageVO.getProcessDefinitionKey())) { | ||
| 126 | + taskQuery.processDefinitionKey(pageVO.getProcessDefinitionKey()); | ||
| 127 | + } | ||
| 123 | if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { | 128 | if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { |
| 124 | taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); | 129 | taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); |
| 125 | taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); | 130 | taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); |
| @@ -548,7 +553,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -548,7 +553,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 548 | // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 | 553 | // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 |
| 549 | if (CollUtil.isNotEmpty(reqVO.getVariables())) { | 554 | if (CollUtil.isNotEmpty(reqVO.getVariables())) { |
| 550 | Map<String, Object> variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); | 555 | Map<String, Object> variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); |
| 551 | - // 修改表单的值需要存储到 ProcessInstance 变量 | 556 | + // 校验传递的参数中是否为下一个将要执行的任务节点 |
| 557 | + validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance); | ||
| 558 | + // 如果有下一个审批人,则设置到流程变量中 | ||
| 559 | + // TODO @小北:validateNextAssignees 升级成 validateAndSetNextAssignees,然后里面吧下面这一小段逻辑,抽进去如何? | ||
| 560 | + if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { | ||
| 561 | + // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 | ||
| 562 | + // TODO @小北:这里有个需要讨论的点,微信哈; | ||
| 563 | + // TODO 因为 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES 定位是发起人,那么审批人选择的,放在 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES。目前想到两个方案: | ||
| 564 | + // TODO 方案一:增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,然后设置到这里面。然后,BpmTaskCandidateStartUserSelectStrategy 也从这里读 | ||
| 565 | + // TODO 方案二:也是增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,根据节点审批人类型,放到 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES、PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES | ||
| 566 | + // TODO 方案三:融合成 PROCESS_INSTANCE_VARIABLE_USER_SELECT_ASSIGNEES,不再区分是发起人选择、还是审批人选择。 | ||
| 567 | + Map<String, List<Long>> hisProcessVariables = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); | ||
| 568 | + hisProcessVariables.putAll(reqVO.getNextAssignees()); | ||
| 569 | + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, hisProcessVariables); | ||
| 570 | + } | ||
| 552 | runtimeService.setVariables(task.getProcessInstanceId(), variables); | 571 | runtimeService.setVariables(task.getProcessInstanceId(), variables); |
| 553 | taskService.complete(task.getId(), variables, true); | 572 | taskService.complete(task.getId(), variables, true); |
| 554 | } else { | 573 | } else { |
| @@ -559,6 +578,57 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -559,6 +578,57 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 559 | handleParentTaskIfSign(task.getParentTaskId()); | 578 | handleParentTaskIfSign(task.getParentTaskId()); |
| 560 | } | 579 | } |
| 561 | 580 | ||
| 581 | + | ||
| 582 | + /** | ||
| 583 | + * 校验选择的下一个节点的审批人,是否合法 | ||
| 584 | + * | ||
| 585 | + * 1. 是否有漏选:没有选择审批人 | ||
| 586 | + * 2. 是否有多选:非下一个节点 | ||
| 587 | + * | ||
| 588 | + * @param taskDefinitionKey 当前任务节点标识 | ||
| 589 | + * @param variables 流程变量 | ||
| 590 | + * @param bpmnModel 流程模型 | ||
| 591 | + * @param nextAssignees 下一个节点审批人集合(参数) | ||
| 592 | + * @param processInstance 流程实例 | ||
| 593 | + */ | ||
| 594 | + private void validateNextAssignees(String taskDefinitionKey, Map<String, Object> variables, BpmnModel bpmnModel, | ||
| 595 | + Map<String, List<Long>> nextAssignees, ProcessInstance processInstance) { | ||
| 596 | + // 1. 获取当前任务节点的信息 | ||
| 597 | + FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); | ||
| 598 | + // 2. 获取下一个将要执行的节点集合 | ||
| 599 | + List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); | ||
| 600 | + | ||
| 601 | + // 3. 循环下一个将要执行的节点集合 | ||
| 602 | + for (FlowNode nextFlowNode : nextFlowNodes) { | ||
| 603 | + // 3.1 获取下一个将要执行节点的属性(是否为自选审批人等) | ||
| 604 | + // TODO @小北:public static Integer parseCandidateStrategy(FlowElement userTask) 使用这个工具方法哈。 | ||
| 605 | + Map<String, List<ExtensionElement>> extensionElements = nextFlowNode.getExtensionElements(); | ||
| 606 | + List<ExtensionElement> elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); | ||
| 607 | + if (CollUtil.isEmpty(elements)) { | ||
| 608 | + continue; | ||
| 609 | + } | ||
| 610 | + // 3.2 获取节点中的审批人策略 | ||
| 611 | + Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText()); | ||
| 612 | + // 3.3 获取流程实例中的发起人自选审批人 | ||
| 613 | + Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); | ||
| 614 | + List<Long> startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId()); | ||
| 615 | + // 3.4 如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空 | ||
| 616 | + if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) { | ||
| 617 | + // 先判断前端传递的参数节点节点是否为将要执行的节点 | ||
| 618 | + // TODO @小北:!nextAssignees.containsKey(nextFlowNode.getId())、和 CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) 是不是等价的? | ||
| 619 | + if (!nextAssignees.containsKey(nextFlowNode.getId())) { | ||
| 620 | + throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); | ||
| 621 | + } | ||
| 622 | + // 如果前端传递的节点为空,则抛出异常 | ||
| 623 | + // TODO @小北:换一个错误码哈。 | ||
| 624 | + if (CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) { | ||
| 625 | + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); | ||
| 626 | + } | ||
| 627 | + } | ||
| 628 | + // TODO @小北:加一个“审批人选择”的校验; | ||
| 629 | + } | ||
| 630 | + } | ||
| 631 | + | ||
| 562 | /** | 632 | /** |
| 563 | * 审批通过存在“后加签”的任务。 | 633 | * 审批通过存在“后加签”的任务。 |
| 564 | * <p> | 634 | * <p> |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/http/BpmHttpCallbackTrigger.java
| @@ -42,8 +42,8 @@ public class BpmHttpCallbackTrigger extends BpmAbstractHttpRequestTrigger { | @@ -42,8 +42,8 @@ public class BpmHttpCallbackTrigger extends BpmAbstractHttpRequestTrigger { | ||
| 42 | MultiValueMap<String, String> headers = buildHttpHeaders(processInstance, setting.getHeader()); | 42 | MultiValueMap<String, String> headers = buildHttpHeaders(processInstance, setting.getHeader()); |
| 43 | // 2.2 设置请求体 | 43 | // 2.2 设置请求体 |
| 44 | MultiValueMap<String, String> body = buildHttpBody(processInstance, setting.getBody()); | 44 | MultiValueMap<String, String> body = buildHttpBody(processInstance, setting.getBody()); |
| 45 | - // TODO @芋艿:【回调】在看看 | ||
| 46 | - body.add("callbackId", setting.getCallbackTaskDefineKey()); // 回调请求 callbackId 需要传给被调用方,用于回调执行 | 45 | + // 重要:回调请求 taskDefineKey 需要传给被调用方,用于回调执行 |
| 46 | + body.add("taskDefineKey", setting.getCallbackTaskDefineKey()); | ||
| 47 | 47 | ||
| 48 | // 3. 发起请求 | 48 | // 3. 发起请求 |
| 49 | sendHttpRequest(setting.getUrl(), headers, body); | 49 | sendHttpRequest(setting.getUrl(), headers, body); |