From cdbcd4d673d491ad5203b8cdb05b00919deda6c9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 13 Mar 2024 21:18:07 +0800 Subject: [PATCH 01/26] =?UTF-8?q?BPM=EF=BC=9A=E9=87=8D=E6=9E=84=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E4=BA=BA=E7=9A=84=E5=88=86=E9=85=8D=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=EF=BC=8C=E7=A7=BB=E9=99=A4=20bpm=5Ftask=5Fas?= =?UTF-8?q?sign=5Frule=20=E8=A1=A8=EF=BC=8C=E5=AD=98=E5=82=A8=E5=9C=A8=20b?= =?UTF-8?q?pmn=20=E7=9A=84=20userTask=20=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/number/NumberUtils.java | 4 + .../common/util/string/StrUtils.java | 6 + .../module/bpm/enums/ErrorCodeConstants.java | 2 +- .../candidate/vo/BpmTaskCandidateRuleVO.java | 3 - .../BpmTaskAssignRuleController.java | 58 ---- .../vo/rule/BpmTaskAssignRuleBaseVO.java | 24 -- .../vo/rule/BpmTaskAssignRuleCreateReqVO.java | 24 -- .../vo/rule/BpmTaskAssignRuleRespVO.java | 28 -- .../vo/rule/BpmTaskAssignRuleUpdateReqVO.java | 20 -- .../definition/BpmTaskAssignRuleConvert.java | 40 --- .../definition/BpmTaskAssignRuleDO.java | 83 ------ .../definition/BpmTaskAssignRuleMapper.java | 37 --- .../definition/BpmModelServiceImpl.java | 24 +- .../BpmProcessDefinitionServiceImpl.java | 16 +- .../definition/BpmTaskAssignRuleService.java | 71 +---- .../BpmTaskAssignRuleServiceImpl.java | 256 +++++------------- .../definition/BpmUserGroupService.java | 11 +- .../definition/BpmUserGroupServiceImpl.java | 16 +- .../flowable/core/util/BpmnModelUtils.java | 11 + 19 files changed, 110 insertions(+), 624 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java index ea131e86e..c928e2fcf 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java @@ -16,6 +16,10 @@ public class NumberUtils { return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null; } + public static Integer parseInt(String str) { + return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null; + } + /** * 通过经纬度获取地球上两点之间的距离 * diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java index 08cea833f..c434b2577 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java @@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; /** @@ -45,6 +46,11 @@ public class StrUtils { return Arrays.stream(longs).boxed().collect(Collectors.toList()); } + public static Set splitToLongSet(String value, CharSequence separator) { + long[] longs = StrUtil.splitToLong(value, separator); + return Arrays.stream(longs).boxed().collect(Collectors.toSet()); + } + public static List splitToInteger(String value, CharSequence separator) { int[] integers = StrUtil.splitToInt(value, separator); return Arrays.stream(integers).boxed().collect(Collectors.toList()); 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 51eebda23..646841b34 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 @@ -27,7 +27,7 @@ public interface ErrorCodeConstants { ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"); ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + - "原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置"); + "原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置"); ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化"); // ========== 流程定义 1-009-003-000 ========== diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java index 25426f604..62b1dff1c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleBaseVO; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -10,8 +9,6 @@ import java.util.Set; /** * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 - * - * @see BpmTaskAssignRuleBaseVO */ @Data public class BpmTaskCandidateRuleVO { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java deleted file mode 100644 index 3c7e404de..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - 任务分配规则") -@RestController -@RequestMapping("/bpm/task-assign-rule") -@Validated -public class BpmTaskAssignRuleController { - - @Resource - private BpmTaskAssignRuleService taskAssignRuleService; - - @GetMapping("/list") - @Operation(summary = "获得任务分配规则列表") - @Parameters({ - @Parameter(name = "modelId", description = "模型编号", example = "1024"), - @Parameter(name = "processDefinitionId", description = "流程定义的编号", example = "2048") - }) - @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:query')") - public CommonResult> getTaskAssignRuleList( - @RequestParam(value = "modelId", required = false) String modelId, - @RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) { - return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId)); - } - - @PostMapping("/create") - @Operation(summary = "创建任务分配规则") - @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:create')") - public CommonResult createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) { - return success(taskAssignRuleService.createTaskAssignRule(reqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新任务分配规则") - @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:update')") - public CommonResult updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) { - taskAssignRuleService.updateTaskAssignRule(reqVO); - return success(true); - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java deleted file mode 100644 index 1521abc8e..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import jakarta.validation.constraints.NotNull; -import java.util.Set; - -/** - * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 - */ -@Data -public class BpmTaskAssignRuleBaseVO { - - @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type") - @NotNull(message = "规则类型不能为空") - private Integer type; - - @Schema(description = "规则值数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") - @NotNull(message = "规则值数组不能为空") - private Set options; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java deleted file mode 100644 index 90e6b7e33..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import jakarta.validation.constraints.NotEmpty; - -@Schema(description = "管理后台 - 流程任务分配规则的创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO { - - @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotEmpty(message = "流程模型的编号不能为空") - private String modelId; - - @Schema(description = "流程任务定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") - @NotEmpty(message = "流程任务定义的编号不能为空") - private String taskDefinitionKey; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java deleted file mode 100644 index ac4f85e78..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - 流程任务分配规则的 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO { - - @Schema(description = "任务分配规则的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long id; - - @Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") - private String modelId; - - @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") - private String processDefinitionId; - - @Schema(description = "流程任务定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") - private String taskDefinitionKey; - @Schema(description = "流程任务定义的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "关注芋道") - private String taskDefinitionName; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java deleted file mode 100644 index 7d13cc07a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import jakarta.validation.constraints.NotNull; - -@Schema(description = "管理后台 - 流程任务分配规则的更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO { - - @Schema(description = "任务分配规则的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "任务分配规则的编号不能为空") - private Long id; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java deleted file mode 100644 index c616e90b0..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.definition; - -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; -import org.flowable.bpmn.model.UserTask; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; - -@Mapper -public interface BpmTaskAssignRuleConvert { - BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class); - - default List convertList(List tasks, List rules) { - Map ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey); - // 以 UserTask 为主维度,原因是:流程图编辑后,一些规则实际就没用了。 - return CollectionUtils.convertList(tasks, task -> { - BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId())); - if (respVO == null) { - respVO = new BpmTaskAssignRuleRespVO(); - respVO.setTaskDefinitionKey(task.getId()); - } - respVO.setTaskDefinitionName(task.getName()); - return respVO; - }); - } - - BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean); - - BpmTaskAssignRuleDO convert(BpmTaskAssignRuleCreateReqVO bean); - - BpmTaskAssignRuleDO convert(BpmTaskAssignRuleUpdateReqVO bean); - - List convertList2(List list); -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java deleted file mode 100644 index e65764f1a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.util.Set; - -/** - * Bpm 任务分配的规则表,用于自定义配置每个任务的负责人、候选人的分配规则。 - * 也就是说,废弃 BPMN 原本的 UserTask 设置的 assignee、candidateUsers 等配置,而是通过使用该规则进行计算对应的负责人。 - * - * 1. 默认情况下,{@link #processDefinitionId} 为 {@link #PROCESS_DEFINITION_ID_NULL} 值,表示贵改则与流程模型关联 - * 2. 在流程模型部署后,会将他的所有规则记录,复制出一份新部署出来的流程定义,通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联 - * - * @author 芋道源码 - */ -@TableName(value = "bpm_task_assign_rule", autoResultMap = true) -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class BpmTaskAssignRuleDO extends BaseDO { - - /** - * {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义 - */ - public static final String PROCESS_DEFINITION_ID_NULL = ""; - - /** - * 编号 - */ - @TableId - private Long id; - - /** - * 流程模型编号 - * - * 关联 Model 的 id 属性 - */ - private String modelId; - /** - * 流程定义编号 - * - * 关联 ProcessDefinition 的 id 属性 - */ - private String processDefinitionId; - /** - * 流程任务的定义 Key - * - * 关联 Task 的 taskDefinitionKey 属性 - */ - private String taskDefinitionKey; - - /** - * 规则类型 - * - * 枚举 {@link BpmTaskAssignRuleTypeEnum} - */ - @TableField("`type`") - private Integer type; - /** - * 规则值数组,一般关联指定表的编号 - * 根据 type 不同,对应的值是不同的: - * - * 1. {@link BpmTaskAssignRuleTypeEnum#ROLE} 时:角色编号 - * 2. {@link BpmTaskAssignRuleTypeEnum#DEPT_MEMBER} 时:部门编号 - * 3. {@link BpmTaskAssignRuleTypeEnum#DEPT_LEADER} 时:部门编号 - * 4. {@link BpmTaskAssignRuleTypeEnum#USER} 时:用户编号 - * 5. {@link BpmTaskAssignRuleTypeEnum#USER_GROUP} 时:用户组编号 - * 6. {@link BpmTaskAssignRuleTypeEnum#SCRIPT} 时:脚本编号,目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识 - */ - @TableField(typeHandler = JsonLongSetTypeHandler.class) - private Set options; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java deleted file mode 100644 index c4061c0f8..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.mysql.definition; - -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; -import org.apache.ibatis.annotations.Mapper; -import org.springframework.lang.Nullable; - -import java.util.List; - -@Mapper -public interface BpmTaskAssignRuleMapper extends BaseMapperX { - - default List selectListByProcessDefinitionId(String processDefinitionId, - @Nullable String taskDefinitionKey) { - return selectList(new QueryWrapperX() - .eq("process_definition_id", processDefinitionId) - .eqIfPresent("task_definition_key", taskDefinitionKey)); - } - - default List selectListByModelId(String modelId) { - return selectList(new QueryWrapperX() - .eq("model_id", modelId) - .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)); - } - - default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId, - String taskDefinitionKey) { - return selectOne(new QueryWrapperX() - .eq("model_id", modelId) - .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL) - .eq("task_definition_key", taskDefinitionKey)); - } - - - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 08f8acf6b..7012fa9f8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; @@ -17,10 +17,8 @@ import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCr import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.impl.db.SuspensionState; -import org.flowable.common.engine.impl.util.io.BytesStreamSource; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Model; @@ -168,15 +166,13 @@ public class BpmModelServiceImpl implements BpmModelService { // 1.3 校验表单已配 BpmFormDO form = checkFormConfig(model.getMetaInfo()); // 1.4 校验任务分配规则已配置 - taskAssignRuleService.checkTaskAssignRuleAllConfig(id); + taskAssignRuleService.checkTaskAssignRuleAllConfig(bpmnBytes); // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 - BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes); + BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) + .setBpmnBytes(bpmnBytes); if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 - ProcessDefinition oldProcessDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); - if (oldProcessDefinition != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessDefinition.getId())) { - throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); - } + throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); } // 2.1 创建流程定义 @@ -189,12 +185,8 @@ public class BpmModelServiceImpl implements BpmModelService { ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId); model.setDeploymentId(definition.getDeploymentId()); repositoryService.saveModel(model); - - // 2.4 复制任务分配规则 - taskAssignRuleService.copyTaskAssignRules(id, definition.getId()); } - @Override @Transactional(rollbackFor = Exception.class) public void deleteModel(String id) { @@ -229,11 +221,7 @@ public class BpmModelServiceImpl implements BpmModelService { @Override public BpmnModel getBpmnModel(String id) { byte[] bpmnBytes = repositoryService.getModelEditorSource(id); - if (ArrayUtil.isEmpty(bpmnBytes)) { - return null; - } - BpmnXMLConverter converter = new BpmnXMLConverter(); - return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); + return BpmnModelUtils.getBpmnModel(bpmnBytes); } @Override 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 c9b3872cd..dd5f035a9 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 @@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.impl.db.SuspensionState; -import org.flowable.common.engine.impl.util.io.BytesStreamSource; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; @@ -124,6 +123,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) .addBytes(createReqDTO.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) .tenantId(TenantContextHolder.getTenantIdStr()) + .disableSchemaValidation() // 禁用 XML Schema 验证,因为有自定义的属性 .deploy(); // 设置 ProcessDefinition 的 category 分类 @@ -197,7 +197,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ return false; } // 校验 BPMN XML 信息 - BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); + BpmnModel newModel = BpmnModelUtils.getBpmnModel(createReqDTO.getBpmnBytes()); BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); // 对比字节变化 if (!BpmnModelUtils.equals(oldModel, newModel)) { @@ -207,18 +207,6 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ return true; } - /** - * 构建对应的 BPMN Model - * - * @param bpmnBytes 原始的 BPMN XML 字节数组 - * @return BPMN Model - */ - private BpmnModel buildBpmnModel(byte[] bpmnBytes) { - // 转换成 BpmnModel 对象 - BpmnXMLConverter converter = new BpmnXMLConverter(); - return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); - } - @Override public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) { return processDefinitionMapper.selectByProcessDefinitionId(id); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java index 47cf2c0ed..012141adf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java @@ -1,14 +1,7 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.lang.Nullable; -import jakarta.validation.Valid; -import java.util.List; import java.util.Set; /** @@ -18,73 +11,13 @@ import java.util.Set; */ public interface BpmTaskAssignRuleService { - /** - * 获得流程定义的任务分配规则数组 - * - * @param processDefinitionId 流程定义的编号 - * @param taskDefinitionKey 流程任务定义的 Key。允许空 - * @return 任务规则数组 - */ - List getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, - @Nullable String taskDefinitionKey); - - /** - * 获得流程模型的任务规则数组 - * - * @param modelId 流程模型的编号 - * @return 任务规则数组 - */ - List getTaskAssignRuleListByModelId(String modelId); - - /** - * 获得流程定义的任务分配规则数组 - * - * @param modelId 流程模型的编号 - * @param processDefinitionId 流程定义的编号 - * @return 任务规则数组 - */ - List getTaskAssignRuleList(String modelId, String processDefinitionId); - - /** - * 创建任务分配规则 - * - * @param reqVO 创建信息 - * @return 规则编号 - */ - Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO); - - /** - * 更新任务分配规则 - * - * @param reqVO 创建信息 - */ - void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO); - - /** - * 判断指定流程模型和流程定义的分配规则是否相等 - * - * @param modelId 流程模型编号 - * @param processDefinitionId 流程定义编号 - * @return 是否相等 - */ - boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId); - - /** - * 将流程流程模型的任务分配规则,复制一份给流程定义 - * 目的:每次流程模型部署时,都会生成一个新的流程定义,此时考虑到每次部署的流程不可变性,所以需要复制一份给该流程定义 - * - * @param fromModelId 流程模型编号 - * @param toProcessDefinitionId 流程定义编号 - */ - void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId); - /** * 校验流程模型的任务分配规则全部都配置了 * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! * - * @param id 流程模型编号 + * @param bpmnBytes BPMN XML */ - void checkTaskAssignRuleAllConfig(String id); + void checkTaskAssignRuleAllConfig(byte[] bpmnBytes); /** * 计算当前执行任务的处理人 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java index e035be070..b7bab5753 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java @@ -1,20 +1,16 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +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.string.StrUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; @@ -28,17 +24,16 @@ import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; -import org.flowable.common.engine.api.FlowableException; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; import java.util.*; import java.util.function.Function; @@ -46,7 +41,6 @@ import static cn.hutool.core.text.CharSequenceUtil.format; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** @@ -57,16 +51,12 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; @Slf4j public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { - @Resource - private BpmTaskAssignRuleMapper taskRuleMapper; - @Resource - @Lazy // 解决循环依赖 - private BpmModelService modelService; - @Resource - @Lazy // 解决循环依赖 - private BpmProcessDefinitionService processDefinitionService; @Resource private BpmUserGroupService userGroupService; + @Resource + @Lazy // 解决循环依赖 + private BpmProcessInstanceService processInstanceService; + @Resource private RoleApi roleApi; @Resource @@ -79,9 +69,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { private DictDataApi dictDataApi; @Resource private PermissionApi permissionApi; - @Resource - @Lazy // 解决循环依赖 - private BpmProcessInstanceService processInstanceService; + /** * 任务分配脚本 */ @@ -93,130 +81,23 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { } @Override - public List getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, - String taskDefinitionKey) { - return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); - } - - @Override - public List getTaskAssignRuleListByModelId(String modelId) { - return taskRuleMapper.selectListByModelId(modelId); - } - - @Override - public List getTaskAssignRuleList(String modelId, String processDefinitionId) { - // 获得规则 - List rules = Collections.emptyList(); - BpmnModel model = null; - if (StrUtil.isNotEmpty(modelId)) { - rules = getTaskAssignRuleListByModelId(modelId); - model = modelService.getBpmnModel(modelId); - } else if (StrUtil.isNotEmpty(processDefinitionId)) { - rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null); - model = processDefinitionService.getBpmnModel(processDefinitionId); - } - if (model == null) { - return Collections.emptyList(); - } - // 获得用户任务,只有用户任务才可以设置分配规则 - List userTasks = BpmnModelUtils.getBpmnModelElements(model, UserTask.class); - if (CollUtil.isEmpty(userTasks)) { - return Collections.emptyList(); - } - // 转换数据 - return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules); - } - - @Override - public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) { - // 校验参数 - validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); - // 校验是否已经配置 - BpmTaskAssignRuleDO existRule = - taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); - if (existRule != null) { - throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey()); - } - - // 存储 - BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO) - .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 - taskRuleMapper.insert(rule); - return rule.getId(); - } - - @Override - public void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO) { - // 校验参数 - validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); - // 校验是否存在 - BpmTaskAssignRuleDO existRule = taskRuleMapper.selectById(reqVO.getId()); - if (existRule == null) { - throw exception(TASK_ASSIGN_RULE_NOT_EXISTS); - } - // 只允许修改流程模型的规则 - if (!Objects.equals(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL, existRule.getProcessDefinitionId())) { - throw exception(TASK_UPDATE_FAIL_NOT_MODEL); - } - - // 执行更新 - taskRuleMapper.updateById(BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)); - } - - @Override - public boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId) { - // 调用 VO 接口的原因是,过滤掉流程模型不需要的规则,保持和 copyTaskAssignRules 方法的一致性 - List modelRules = getTaskAssignRuleList(modelId, null); - List processInstanceRules = getTaskAssignRuleList(null, processDefinitionId); - if (modelRules.size() != processInstanceRules.size()) { - return false; - } - - // 遍历,匹配对应的规则 - Map processInstanceRuleMap = - CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); - for (BpmTaskAssignRuleRespVO modelRule : modelRules) { - BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey()); - if (processInstanceRule == null) { - return false; - } - if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal( - modelRule.getOptions(), processInstanceRule.getOptions())) { - return false; - } - } - return true; - } - - @Override - public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) { - List rules = getTaskAssignRuleList(fromModelId, null); - if (CollUtil.isEmpty(rules)) { - return; - } - // 开始复制 - List newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules); - newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null) - .setUpdateTime(null)); - taskRuleMapper.insertBatch(newRules); - } - - @Override - public void checkTaskAssignRuleAllConfig(String id) { - // 一个用户任务都没配置,所以无需配置规则 - List taskAssignRules = getTaskAssignRuleList(id, null); - if (CollUtil.isEmpty(taskAssignRules)) { - return; - } - // 校验未配置规则的任务 - taskAssignRules.forEach(rule -> { - if (CollUtil.isEmpty(rule.getOptions())) { - throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName()); + public void checkTaskAssignRuleAllConfig(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + assert bpmnModel != null; + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + // 遍历所有的 UserTask,校验审批人配置 + userTaskList.forEach(userTask -> { + // TODO 芋艿:assignType/assignOptions/, 枚举 + Integer type = NumberUtils.parseInt(userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); + String options = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); + if (type == null || StrUtil.isBlank(options)) { + throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName()); } + validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ",")); }); } - private void validTaskAssignRuleOptions(Integer type, Set options) { + private void validTaskAssignRuleOptions(Integer type, Collection options) { if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { roleApi.validRoleList(options); } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), @@ -247,92 +128,83 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { return convertSet(assignee, Function.identity()); } // 2. 通过分配规则,计算审批人 - BpmTaskAssignRuleDO rule = getTaskRule(execution); - return calculateTaskCandidateUsers(execution, rule); + return calculateTaskCandidateUsers0(execution); } @VisibleForTesting - BpmTaskAssignRuleDO getTaskRule(DelegateExecution execution) { - List taskRules = getTaskAssignRuleListByProcessDefinitionId( - execution.getProcessDefinitionId(), execution.getCurrentActivityId()); - if (CollUtil.isEmpty(taskRules)) { - throw new FlowableException(format("流程任务({}/{}/{}) 找不到符合的任务规则", - execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId())); - } - if (taskRules.size() > 1) { - throw new FlowableException(format("流程任务({}/{}/{}) 找到过多任务规则({})", - execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId())); - } - return taskRules.get(0); - } + Set calculateTaskCandidateUsers0(DelegateExecution execution) { + // 获得审批人配置 + // TODO 芋艿:assignType/assignOptions/, 枚举 + FlowElement flowElement = execution.getCurrentFlowElement(); + Integer type = NumberUtils.parseInt(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); + Set options = StrUtils.splitToLongSet(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"), ","); - @VisibleForTesting - Set calculateTaskCandidateUsers(DelegateExecution execution, BpmTaskAssignRuleDO rule) { + // 计算审批人 Set assigneeUserIds = null; - if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByRole(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByDeptMember(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByPost(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByUser(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByUserGroup(rule); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { - assigneeUserIds = calculateTaskCandidateUsersByScript(execution, rule); + if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByRole(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByDeptMember(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByPost(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByUser(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) { + assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options); } // 移除被禁用的用户 removeDisableUsers(assigneeUserIds); // 如果候选人为空,抛出异常 if (CollUtil.isEmpty(assigneeUserIds)) { - log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", execution.getId(), - execution.getProcessDefinitionId(), execution.getCurrentActivityId(), toJsonString(rule)); + log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), + execution.getProcessDefinitionId(), execution.getCurrentActivityId(), type, options); throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); } return assigneeUserIds; } - private Set calculateTaskCandidateUsersByRole(BpmTaskAssignRuleDO rule) { - return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); + private Set calculateTaskCandidateUsersByRole(Set roleIds) { + return permissionApi.getUserRoleIdListByRoleIds(roleIds); } - private Set calculateTaskCandidateUsersByDeptMember(BpmTaskAssignRuleDO rule) { - List users = adminUserApi.getUserListByDeptIds(rule.getOptions()); + private Set calculateTaskCandidateUsersByDeptMember(Set deptIds) { + List users = adminUserApi.getUserListByDeptIds(deptIds); return convertSet(users, AdminUserRespDTO::getId); } - private Set calculateTaskCandidateUsersByDeptLeader(BpmTaskAssignRuleDO rule) { - List depts = deptApi.getDeptList(rule.getOptions()); + private Set calculateTaskCandidateUsersByDeptLeader(Set deptIds) { + List depts = deptApi.getDeptList(deptIds); return convertSet(depts, DeptRespDTO::getLeaderUserId); } - private Set calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) { - List users = adminUserApi.getUserListByPostIds(rule.getOptions()); + private Set calculateTaskCandidateUsersByPost(Set postIds) { + List users = adminUserApi.getUserListByPostIds(postIds); return convertSet(users, AdminUserRespDTO::getId); } - private Set calculateTaskCandidateUsersByUser(BpmTaskAssignRuleDO rule) { - return rule.getOptions(); + private Set calculateTaskCandidateUsersByUser(Set userIds) { + return userIds; } - private Set calculateTaskCandidateUsersByUserGroup(BpmTaskAssignRuleDO rule) { - List userGroups = userGroupService.getUserGroupList(rule.getOptions()); + private Set calculateTaskCandidateUsersByUserGroup(Set groupIds) { + List userGroups = userGroupService.getUserGroupList(groupIds); Set userIds = new HashSet<>(); userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); return userIds; } - private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, BpmTaskAssignRuleDO rule) { + private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, Set scriptIds) { // 获得对应的脚本 - List scripts = new ArrayList<>(rule.getOptions().size()); - rule.getOptions().forEach(id -> { - BpmTaskAssignScript script = scriptMap.get(id); + List scripts = new ArrayList<>(scriptIds.size()); + scriptIds.forEach(scriptId -> { + BpmTaskAssignScript script = scriptMap.get(scriptId); if (script == null) { - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); + throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, scriptId); } scripts.add(script); }); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java index 2ce14a201..6ae6e06ca 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java @@ -1,13 +1,14 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import java.util.*; -import jakarta.validation.*; - +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; /** * 用户组 Service 接口 @@ -77,6 +78,6 @@ public interface BpmUserGroupService { * * @param ids 用户组编号数组 */ - void validUserGroups(Set ids); + void validUserGroups(Collection ids); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java index d41ae4c14..269078761 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java @@ -1,27 +1,27 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_IS_DISABLE; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; /** * 用户组 Service 实现类 @@ -89,7 +89,7 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService { } @Override - public void validUserGroups(Set ids) { + public void validUserGroups(Collection ids) { if (CollUtil.isEmpty(ids)) { return; } diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java index 7b23a467a..6de30aa94 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; +import org.flowable.common.engine.impl.util.io.BytesStreamSource; import java.util.*; @@ -91,6 +93,15 @@ public class BpmnModelUtils { return converter.convertToXML(model); } + public static BpmnModel getBpmnModel(byte[] bpmnBytes) { + if (ArrayUtil.isEmpty(bpmnBytes)) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + // 补充说明:由于在 Flowable 中自定义了属性,所以 validateSchema 传递 false + return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), false, false); + } + // ========== 遍历相关的方法 ========== /** From 797fddfb3d495303378a4798d7934086cdedc9ae Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 14 Mar 2024 12:54:16 +0800 Subject: [PATCH 02/26] =?UTF-8?q?BPM=EF=BC=9A=E6=96=B0=E5=A2=9E=20flowable?= =?UTF-8?q?=20expression=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=EF=BC=8C=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=E7=8E=B0=E6=9C=89=20BpmTaskAssignScript=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E5=8A=A0=E7=81=B5=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmTaskAssignRuleTypeEnum.java | 2 + .../behavior/script/BpmTaskAssignScript.java | 2 + .../BpmTaskAssignLeaderAbstractScript.java | 1 + .../impl/BpmTaskAssignLeaderX1Script.java | 1 + .../impl/BpmTaskAssignLeaderX2Script.java | 1 + .../impl/BpmTaskAssignStartUserScript.java | 1 + .../core/handler/MultiInstanceHandler.java | 76 ------------------- .../definition/BpmModelServiceImpl.java | 7 +- .../BpmTaskAssignRuleServiceImpl.java | 27 ++++++- .../core/enums/BpmnModelConstants.java | 5 -- .../flowable/core/util/FlowableUtils.java | 16 ++++ yudao-server/pom.xml | 10 +-- 12 files changed, 59 insertions(+), 90 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/handler/MultiInstanceHandler.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java index b7ccc7ae8..d220da746 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java @@ -18,7 +18,9 @@ public enum BpmTaskAssignRuleTypeEnum { POST(22, "岗位"), USER(30, "用户"), USER_GROUP(40, "用户组"), + @Deprecated SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 + EXPRESS(60, "流程表达式"), // 表达式 ExpressionManager ; /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java index b5c91ebad..c39059048 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java @@ -14,6 +14,7 @@ import java.util.Set; * * @author 芋道源码 */ +@Deprecated public interface BpmTaskAssignScript { /** @@ -30,5 +31,6 @@ public interface BpmTaskAssignScript { * @return 枚举值 */ BpmTaskRuleScriptEnum getEnum(); + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java index 9ef7d3b30..22ef4cde7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java @@ -24,6 +24,7 @@ import static java.util.Collections.emptySet; * * @author 芋道源码 */ +@Deprecated public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript { @Resource diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java index af7d8b5a7..9c31970f7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java @@ -11,6 +11,7 @@ import java.util.Set; * * @author 芋道源码 */ +@Deprecated @Component public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java index 068ab3d2f..935545100 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java @@ -11,6 +11,7 @@ import java.util.Set; * * @author 芋道源码 */ +@Deprecated @Component public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java index 8f4c2c265..0329aec6a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java @@ -18,6 +18,7 @@ import java.util.Set; * * @author 芋道源码 */ +@Deprecated @Component public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/handler/MultiInstanceHandler.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/handler/MultiInstanceHandler.java deleted file mode 100644 index ee81a9cf4..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/handler/MultiInstanceHandler.java +++ /dev/null @@ -1,76 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.handler; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -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.AllArgsConstructor; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - -// TODO @芋艿:bpmn 分配人融合时,需要搞下这块; -/** - * 多实例处理类 - */ -@AllArgsConstructor -@Component("multiInstanceHandler") -public class MultiInstanceHandler { - - @Resource - private AdminUserApi userApi; - - @Resource - private PermissionApi permissionApi; - - /** - * 流程发起人那种情况不需要处理, - * 由 flowable 完成 - * - * @param execution flowable的执行对象 - * @return 用户ID - */ - public Set getUserIds(DelegateExecution execution) { - Set candidateUserIds = new LinkedHashSet<>(); - FlowElement flowElement = execution.getCurrentFlowElement(); - if (ObjectUtil.isNotEmpty(flowElement) && flowElement instanceof UserTask userTask) { - String dataType = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, BpmnModelConstants.PROCESS_CUSTOM_DATA_TYPE); - if ("USERS".equals(dataType) && CollUtil.isNotEmpty(userTask.getCandidateUsers())) { - // 添加候选用户id - candidateUserIds.addAll(userTask.getCandidateUsers()); - } else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) { - // 获取组的ID,角色ID集合或部门ID集合 - List groups = userTask.getCandidateGroups().stream() - // 例如部门DEPT100,100才是部门id - .map(item -> Long.parseLong(item.substring(4))) - .collect(Collectors.toList()); - List userIds = new ArrayList<>(); - if ("ROLES".equals(dataType)) { - // 通过角色id,获取所有用户id集合 - Set userRoleIdListByRoleIds = permissionApi.getUserRoleIdListByRoleIds(groups); - userIds = new ArrayList<>(userRoleIdListByRoleIds); - } else if ("DEPTS".equals(dataType)) { - // 通过部门id,获取所有用户id集合 - List userListByDeptIds = userApi.getUserListByDeptIds(groups); - userIds = convertList(userListByDeptIds, AdminUserRespDTO::getId); - } - // 添加候选用户id - userIds.forEach(id -> candidateUserIds.add(String.valueOf(id))); - } - } - return candidateUserIds; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 7012fa9f8..00ba49de4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -171,9 +171,10 @@ public class BpmModelServiceImpl implements BpmModelService { // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) .setBpmnBytes(bpmnBytes); - if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 - throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); - } + // TODO @芋艿:这里比较可能有点问题 +// if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 +// throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); +// } // 2.1 创建流程定义 String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java index b7bab5753..a1474afd0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -10,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; @@ -26,6 +28,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.dromara.hutool.core.convert.Convert; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; @@ -57,6 +60,9 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @Lazy // 解决循环依赖 private BpmProcessInstanceService processInstanceService; +// @Resource +// private ExpressionManager expressionManager; + @Resource private RoleApi roleApi; @Resource @@ -93,6 +99,10 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { if (type == null || StrUtil.isBlank(options)) { throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName()); } + // TODO 芋艿:校验 options + if (ObjectUtil.equal(type, BpmTaskAssignRuleTypeEnum.EXPRESS.getType())) { + return; + } validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ",")); }); } @@ -117,6 +127,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { } } + public Long test(DelegateExecution execution) { + return 1L; + } + + public Long test2(DelegateExecution execution, Long id) { + return id; + } + @Override @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题 public Set calculateTaskCandidateUsers(DelegateExecution execution) { @@ -137,7 +155,11 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { // TODO 芋艿:assignType/assignOptions/, 枚举 FlowElement flowElement = execution.getCurrentFlowElement(); Integer type = NumberUtils.parseInt(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); - Set options = StrUtils.splitToLongSet(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"), ","); + String optionStr = flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); + Set options = null; + if (ObjectUtil.notEqual(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { + options = StrUtils.splitToLongSet(optionStr, ","); + } // 计算审批人 Set assigneeUserIds = null; @@ -155,6 +177,9 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options); } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) { assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { + Object result = FlowableUtils.getExpressionValue(execution, optionStr); + assigneeUserIds = Convert.toSet(Long.class, result); } // 移除被禁用的用户 diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java index c3cce4272..f279e95df 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java +++ b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java @@ -14,9 +14,4 @@ public interface BpmnModelConstants { */ String NAMESPACE = "http://flowable.org/bpmn"; - /** - * 自定义属性 dataType - */ - String PROCESS_CUSTOM_DATA_TYPE = "dataType"; - } diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java index 2a0fc38ac..d69798995 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java @@ -1,6 +1,11 @@ package cn.iocoder.yudao.framework.flowable.core.util; +import org.flowable.common.engine.api.delegate.Expression; +import org.flowable.common.engine.api.variable.VariableContainer; +import org.flowable.common.engine.impl.el.ExpressionManager; import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.CommandContextUtil; /** * Flowable 相关的工具方法 @@ -29,4 +34,15 @@ public class FlowableUtils { return activityId + "_assignee"; } + // ========== Expression 相关的工具方法 ========== + + public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) { + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + assert processEngineConfiguration != null; + ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager(); + assert expressionManager != null; + Expression expression = expressionManager.createExpression(expressionString); + return expression.getValue(variableContainer); + } + } diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index bc850b590..e5b816b9b 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-bpm-biz + ${revision} + From f5f73adcbbe3a5b8c0636c453512d05232d41c26 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 15 Mar 2024 00:19:09 +0800 Subject: [PATCH 03/26] =?UTF-8?q?BPM=EF=BC=9A=E9=87=8D=E6=9E=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=88=86=E9=85=8D=E4=BA=BA=E7=9A=84=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E9=80=9A=E8=BF=87=20BpmTaskCandidateStrategy=20?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../common/util/string/StrUtils.java | 5 + .../module/bpm/enums/ErrorCodeConstants.java | 2 +- .../definition/BpmTaskAssignRuleTypeEnum.java | 35 --- .../definition/BpmTaskRuleScriptEnum.java | 30 --- .../BpmCandidateProcessorConfiguration.java | 52 ---- .../config/BpmFlowableConfiguration.java | 21 +- .../behavior/BpmActivityBehaviorFactory.java | 16 +- .../BpmParallelMultiInstanceBehavior.java | 6 +- .../behavior/BpmUserTaskActivityBehavior.java | 6 +- .../behavior/script/BpmTaskAssignScript.java | 36 --- .../impl/BpmTaskAssignLeaderX1Script.java | 28 -- .../impl/BpmTaskAssignLeaderX2Script.java | 28 -- .../candidate/BpmTaskCandidateInvoker.java | 134 +++++++++ .../candidate/BpmTaskCandidateStrategy.java | 39 +++ .../BpmTaskAssignLeaderExpression.java} | 17 +- .../BpmTaskAssignStartUserExpression.java} | 21 +- .../BpmTaskCandidateDeptLeaderStrategy.java | 46 ++++ .../BpmTaskCandidateDeptMemberStrategy.java | 49 ++++ .../BpmTaskCandidateExpressionStrategy.java | 36 +++ .../BpmTaskCandidateGroupStrategy.java | 47 ++++ .../BpmTaskCandidatePostStrategy.java | 49 ++++ .../BpmTaskCandidateRoleStrategy.java | 44 +++ .../BpmTaskCandidateUserStrategy.java | 39 +++ .../enums/BpmTaskCandidateStrategyEnum.java | 40 +++ .../core/enums/BpmnModelConstants.java | 24 ++ .../candidate/BpmCandidateSourceInfo.java | 45 ---- .../BpmCandidateSourceInfoProcessor.java | 53 ---- .../BpmCandidateSourceInfoProcessorChain.java | 107 -------- ...didateAdminUserApiSourceInfoProcessor.java | 32 --- ...pmCandidateDeptApiSourceInfoProcessor.java | 50 ---- ...pmCandidatePostApiSourceInfoProcessor.java | 40 --- ...pmCandidateRoleApiSourceInfoProcessor.java | 37 --- ...CandidateScriptApiSourceInfoProcessor.java | 73 ----- ...didateUserGroupApiSourceInfoProcessor.java | 41 --- .../definition/BpmModelServiceImpl.java | 6 +- .../BpmProcessDefinitionServiceImpl.java | 2 +- .../definition/BpmTaskAssignRuleService.java | 30 --- .../BpmTaskAssignRuleServiceImpl.java | 254 ------------------ .../cc/BpmProcessInstanceCopyService.java | 9 - .../cc/BpmProcessInstanceCopyServiceImpl.java | 68 ----- .../BpmTaskCandidateInvokerTest.java | 93 +++++++ .../BpmTaskAssignLeaderExpressionTest.java} | 18 +- ...pmTaskCandidateDeptLeaderStrategyTest.java | 42 +++ ...pmTaskCandidateDeptMemberStrategyTest.java | 42 +++ ...pmTaskCandidateExpressionStrategyTest.java | 39 +++ .../BpmTaskCandidateGroupStrategyTest.java | 42 +++ .../BpmTaskCandidatePostStrategyTest.java | 45 ++++ .../BpmTaskCandidateRoleStrategyTest.java | 41 +++ .../BpmTaskCandidateUserStrategyTest.java | 28 ++ ...CandidateSourceInfoProcessorChainTest.java | 244 ----------------- .../BpmTaskAssignRuleServiceImplTest.java | 227 ---------------- .../core/enums/BpmnModelConstants.java | 17 -- .../framework/flowable/core/package-info.java | 1 - .../framework/flowable/package-info.java | 1 - 55 files changed, 981 insertions(+), 1598 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/{behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java => candidate/expression/BpmTaskAssignLeaderExpression.java} (81%) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/{behavior/script/impl/BpmTaskAssignStartUserScript.java => candidate/expression/BpmTaskAssignStartUserExpression.java} (54%) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java rename yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/{behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java => candidate/expression/BpmTaskAssignLeaderExpressionTest.java} (86%) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java diff --git a/pom.xml b/pom.xml index 3a66524bc..1b5fc92c1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - + yudao-module-bpm diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java index c434b2577..d236d1817 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.common.util.string; +import cn.hutool.core.text.StrPool; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; @@ -46,6 +47,10 @@ public class StrUtils { return Arrays.stream(longs).boxed().collect(Collectors.toList()); } + public static Set splitToLongSet(String value) { + return splitToLongSet(value, StrPool.COMMA); + } + public static Set splitToLongSet(String value, CharSequence separator) { long[] longs = StrUtil.splitToLong(value, separator); return Arrays.stream(longs).boxed().collect(Collectors.toSet()); 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 646841b34..bdc3d17ce 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 @@ -26,7 +26,7 @@ public interface ErrorCodeConstants { ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1_009_002_001, "流程模型不存在"); ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"); ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); - ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + + ErrorCode MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + "原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置"); ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java deleted file mode 100644 index d220da746..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.definition; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * BPM 任务分配规则的类型枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum BpmTaskAssignRuleTypeEnum { - - ROLE(10, "角色"), - DEPT_MEMBER(20, "部门的成员"), // 包括负责人 - DEPT_LEADER(21, "部门的负责人"), - POST(22, "岗位"), - USER(30, "用户"), - USER_GROUP(40, "用户组"), - @Deprecated - SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 - EXPRESS(60, "流程表达式"), // 表达式 ExpressionManager - ; - - /** - * 类型 - */ - private final Integer type; - /** - * 描述 - */ - private final String desc; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java deleted file mode 100644 index 7fc0e3b8b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.definition; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * BPM 任务规则的脚本枚举 - * 目前暂时通过 TODO 芋艿:硬编码,未来可以考虑 Groovy 动态脚本的方式 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum BpmTaskRuleScriptEnum { - - START_USER(10L, "流程发起人"), - - LEADER_X1(20L, "流程发起人的一级领导"), - LEADER_X2(21L, "流程发起人的二级领导"); - - /** - * 脚本编号 - */ - private final Long id; - /** - * 脚本描述 - */ - private final String desc; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java deleted file mode 100644 index cff03488b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.bpm.config; - -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.*; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -// TODO @芋艿:Candidate 相关还在完善中,用户可以暂时忽略,仅 yudao 开发的同学需要关注~计划是把 Candidate 和 Assign 融合成一套 -/** - * BPM 通用的 Configuration 配置类,提供给 Activiti 和 Flowable - * @author kyle - */ -@Configuration(proxyBeanMethods = false) -public class BpmCandidateProcessorConfiguration { - @Bean - public BpmCandidateAdminUserApiSourceInfoProcessor bpmCandidateAdminUserApiSourceInfoProcessor() { - return new BpmCandidateAdminUserApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateDeptApiSourceInfoProcessor bpmCandidateDeptApiSourceInfoProcessor() { - return new BpmCandidateDeptApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidatePostApiSourceInfoProcessor bpmCandidatePostApiSourceInfoProcessor() { - return new BpmCandidatePostApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateRoleApiSourceInfoProcessor bpmCandidateRoleApiSourceInfoProcessor() { - return new BpmCandidateRoleApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateUserGroupApiSourceInfoProcessor bpmCandidateUserGroupApiSourceInfoProcessor() { - return new BpmCandidateUserGroupApiSourceInfoProcessor(); - } - - /** - * 可以自己定制脚本,然后通过这里设置到处理器里面去 - * @param scriptsOp 脚本包装对象 - * @return - */ - @Bean - public BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor(ObjectProvider scriptsOp) { - BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor = new BpmCandidateScriptApiSourceInfoProcessor(); - bpmCandidateScriptApiSourceInfoProcessor.setScripts(scriptsOp); - return bpmCandidateScriptApiSourceInfoProcessor; - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java index c048d9c73..9248da552 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.config; import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; @@ -10,6 +12,8 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + /** * BPM 模块的 Flowable 配置类 * @@ -36,11 +40,20 @@ public class BpmFlowableConfiguration { }; } + // =========== 审批人相关的 Bean ========== + @Bean - public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService) { + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskCandidateInvoker bpmTaskCandidateInvoker) { BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); - bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); + bpmActivityBehaviorFactory.setTaskCandidateInvoker(bpmTaskCandidateInvoker); return bpmActivityBehaviorFactory; } -} + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") // adminUserApi 可以注入成功 + public BpmTaskCandidateInvoker bpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + return new BpmTaskCandidateInvoker(strategyList, adminUserApi); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java index dced1c5bd..e9f1f32d7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; -import lombok.Data; -import lombok.EqualsAndHashCode; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; -import lombok.ToString; import org.flowable.bpmn.model.Activity; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; @@ -18,25 +15,22 @@ import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFacto * * @author 芋道源码 */ -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) +@Setter public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { - @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; @Override public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { return new BpmUserTaskActivityBehavior(userTask) - .setBpmTaskRuleService(bpmTaskRuleService); + .setTaskCandidateInvoker(taskCandidateInvoker); } @Override public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior) - .setBpmTaskRuleService(bpmTaskRuleService); + .setTaskCandidateInvoker(taskCandidateInvoker); } // TODO @ke:SequentialMultiInstanceBehavior 这个抽空也可以看看 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index 0b60faa06..ed51b23fa 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Activity; @@ -23,7 +23,7 @@ import java.util.Set; public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; public BpmParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { @@ -50,7 +50,7 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); // 第二步,获取任务的所有处理人 - Set assigneeUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + Set assigneeUserIds = taskCandidateInvoker.calculateUsers(execution); execution.setVariable(super.collectionVariable, assigneeUserIds); return assigneeUserIds.size(); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java index aeda4d52c..de17502bf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.UserTask; @@ -29,7 +29,7 @@ import java.util.Set; public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; public BpmUserTaskActivityBehavior(UserTask userTask) { super(userTask); @@ -54,7 +54,7 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { // 情况二,如果非多实例的任务,则计算任务处理人 // 第一步,先计算可处理该任务的处理人们 - Set candidateUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + Set candidateUserIds = taskCandidateInvoker.calculateUsers(execution); // 第二步,后随机选择一个任务的处理人 // 疑问:为什么一定要选择一个任务处理人? // 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java deleted file mode 100644 index c39059048..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Set; - -/** - * Bpm 任务分配的自定义 Script 脚本 - * 使用场景: - * 1. 设置审批人为发起人 - * 2. 设置审批人为发起人的 Leader - * 3. 甚至审批人为发起人的 Leader 的 Leader - * - * @author 芋道源码 - */ -@Deprecated -public interface BpmTaskAssignScript { - - /** - * 基于执行任务,获得任务的候选用户们 - * - * @param execution 执行任务 - * @return 候选人用户的编号数组 - */ - Set calculateTaskCandidateUsers(DelegateExecution execution); - - /** - * 获得枚举值 - * - * @return 枚举值 - */ - BpmTaskRuleScriptEnum getEnum(); - -} - diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java deleted file mode 100644 index 9c31970f7..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Component; - -import java.util.Set; - -/** - * 分配给发起人的一级 Leader 审批的 Script 实现类 - * - * @author 芋道源码 - */ -@Deprecated -@Component -public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - return calculateTaskCandidateUsers(execution, 1); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java deleted file mode 100644 index 935545100..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Component; - -import java.util.Set; - -/** - * 分配给发起人的二级 Leader 审批的 Script 实现类 - * - * @author 芋道源码 - */ -@Deprecated -@Component -public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - return calculateTaskCandidateUsers(execution, 2); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java new file mode 100644 index 000000000..d1ba65df2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; + +/** + * {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算 + * + * @author 芋道源码 + */ +@Slf4j +public class BpmTaskCandidateInvoker { + + private final Map strategyMap = new HashMap<>(); + + private final AdminUserApi adminUserApi; + + public BpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + strategyList.forEach(strategy -> { + BpmTaskCandidateStrategy oldStrategy = strategyMap.put(strategy.getStrategy(), strategy); + Assert.isNull(oldStrategy, "策略(%s) 重复", strategy.getStrategy()); + }); + this.adminUserApi = adminUserApi; + } + + /** + * 校验流程模型的任务分配规则全部都配置了 + * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! + * + * @param bpmnBytes BPMN XML + */ + public void validateBpmnConfig(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + assert bpmnModel != null; + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + // 遍历所有的 UserTask,校验审批人配置 + userTaskList.forEach(userTask -> { + // 1. 非空校验 + Integer strategy = parseCandidateStrategy(userTask); + String param = parseCandidateParam(userTask); + if (strategy == null || StrUtil.isBlank(param)) { + throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); + } + // 2. 具体策略校验 + getCandidateStrategy(strategy).validateParam(param); + }); + } + + /** + * 计算任务的候选人 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + public Set calculateUsers(DelegateExecution execution) { + // TODO 芋艿:这里需要重构 +// // 1. 先从提前选好的审批人中获取 +// List assignee = processInstanceService.getAssigneeByProcessInstanceIdAndTaskDefinitionKey( +// execution.getProcessInstanceId(), execution.getCurrentActivityId()); +// if (CollUtil.isNotEmpty(assignee)) { +// // TODO @hai:new HashSet 即可 +// return convertSet(assignee, Function.identity()); +// } + Integer strategy = parseCandidateStrategy(execution.getCurrentFlowElement()); + String param = parseCandidateParam(execution.getCurrentFlowElement()); + // 1.1 计算任务的候选人 + Set userIds = getCandidateStrategy(strategy).calculateUsers(execution, param); + // 1.2 移除被禁用的用户 + removeDisableUsers(userIds); + + // 2. 校验是否有候选人 + if (CollUtil.isEmpty(userIds)) { + log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), + execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param); + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); + } + return userIds; + } + + @VisibleForTesting + void removeDisableUsers(Set assigneeUserIds) { + if (CollUtil.isEmpty(assigneeUserIds)) { + return; + } + Map userMap = adminUserApi.getUserMap(assigneeUserIds); + assigneeUserIds.removeIf(id -> { + AdminUserRespDTO user = userMap.get(id); + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); + }); + } + + private static Integer parseCandidateStrategy(FlowElement userTask) { + return NumberUtils.parseInt(userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); + } + + private static String parseCandidateParam(FlowElement userTask) { + return userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); + } + + private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) { + BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy); + Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy); + BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum); + Assert.notNull(strategyObj, "策略(%s) 不存在", strategy); + return strategyObj; + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java new file mode 100644 index 000000000..a5c5c9b4d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.Set; + +/** + * BPM 任务的候选人的策略接口 + * + * 例如说:分配审批人 + * + * @author 芋道源码 + */ +public interface BpmTaskCandidateStrategy { + + /** + * 对应策略 + * + * @return 策略 + */ + BpmTaskCandidateStrategyEnum getStrategy(); + + /** + * 校验参数 + * + * @param param 参数 + */ + void validateParam(String param); + + /** + * 基于执行任务,获得任务的候选用户们 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + Set calculateUsers(DelegateExecution execution, String param); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java similarity index 81% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java index 22ef4cde7..cb5306548 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -1,7 +1,6 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -9,7 +8,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; -import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import org.springframework.util.Assert; import jakarta.annotation.Resource; @@ -19,23 +18,23 @@ import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static java.util.Collections.emptySet; /** - * 分配给发起人的 Leader 审批的 Script 实现类 - * 目前 Leader 的定义是, + * 分配给发起人的 Leader 审批的 Expression 流程表达式 + * 目前 Leader 的定义是,发起人所在部门的 Leader * * @author 芋道源码 */ -@Deprecated -public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript { +@Component +public class BpmTaskAssignLeaderExpression { @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; + @Resource - @Lazy // 解决循环依赖 private BpmProcessInstanceService bpmProcessInstanceService; - protected Set calculateTaskCandidateUsers(DelegateExecution execution, int level) { + protected Set calculateUsers(DelegateExecution execution, int level) { Assert.isTrue(level > 0, "level 必须大于 0"); // 获得发起人 ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java similarity index 54% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java index 0329aec6a..c4d8811b4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -1,41 +1,30 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import jakarta.annotation.Resource; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import jakarta.annotation.Resource; import java.util.Set; /** - * 分配给发起人审批的 Script 实现类 + * 分配给发起人审批的 Expression 流程表达式 * * @author 芋道源码 */ -@Deprecated @Component -public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript { +public class BpmTaskAssignStartUserExpression { @Resource - @Lazy // 解决循环依赖 private BpmProcessInstanceService bpmProcessInstanceService; - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { + public Set calculateUsers(DelegateExecution execution) { ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); return SetUtils.asSet(startUserId); } - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.START_USER; - } - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java new file mode 100644 index 000000000..485552f91 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的负责人 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_LEADER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List depts = deptApi.getDeptList(deptIds); + return convertSet(depts, DeptRespDTO::getLeaderUserId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java new file mode 100644 index 000000000..f60b1cc8b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的成员 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_MEMBER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByDeptIds(deptIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java new file mode 100644 index 000000000..f8be5fe3e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import org.dromara.hutool.core.convert.Convert; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 流程表达式 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy { + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.EXPRESSION; + } + + @Override + public void validateParam(String param) { + // do nothing 因为它基本做不了校验 + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Object result = FlowableUtils.getExpressionValue(execution, param); + return Convert.toSet(Long.class, result); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java new file mode 100644 index 000000000..b8fa00f84 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; + +/** + * 用户组 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy { + + @Resource + private BpmUserGroupService userGroupService; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER_GROUP; + } + + @Override + public void validateParam(String param) { + Set groupIds = StrUtils.splitToLongSet(param); + userGroupService.getUserGroupList(groupIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set groupIds = StrUtils.splitToLongSet(param); + List groups = userGroupService.getUserGroupList(groupIds); + return convertSetByFlatMap(groups, BpmUserGroupDO::getMemberUserIds, Collection::stream); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java new file mode 100644 index 000000000..3f2ae58f1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 岗位 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidatePostStrategy implements BpmTaskCandidateStrategy { + + @Resource + private PostApi postApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.POST; + } + + @Override + public void validateParam(String param) { + Set postIds = StrUtils.splitToLongSet(param); + postApi.validPostList(postIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set postIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByPostIds(postIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java new file mode 100644 index 000000000..0dd178626 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 角色 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy { + + @Resource + private RoleApi roleApi; + @Resource + private PermissionApi permissionApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.ROLE; + } + + @Override + public void validateParam(String param) { + Set roleIds = StrUtils.splitToLongSet(param); + roleApi.validRoleList(roleIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set roleIds = StrUtils.splitToLongSet(param); + return permissionApi.getUserRoleIdListByRoleIds(roleIds); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java new file mode 100644 index 000000000..390e4903a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 用户 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy { + + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER; + } + + @Override + public void validateParam(String param) { + adminUserApi.validateUserList(StrUtils.splitToLongSet(param)); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + return StrUtils.splitToLongSet(param); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java new file mode 100644 index 000000000..0c3199821 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 任务的候选人策略枚举 + * + * 例如说:分配给指定人审批 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmTaskCandidateStrategyEnum { + + ROLE(10, "角色"), + DEPT_MEMBER(20, "部门的成员"), // 包括负责人 + DEPT_LEADER(21, "部门的负责人"), + POST(22, "岗位"), + USER(30, "用户"), + USER_GROUP(40, "用户组"), + EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager + ; + + /** + * 类型 + */ + private final Integer strategy; + /** + * 描述 + */ + private final String description; + + public static BpmTaskCandidateStrategyEnum valueOf(Integer strategy) { + return ArrayUtil.firstMatch(o -> o.getStrategy().equals(strategy), values()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java new file mode 100644 index 000000000..c8fefd55b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +/** + * 流程常量信息 + */ +public interface BpmnModelConstants { + + String BPMN_FILE_SUFFIX = ".bpmn"; + + /** + * BPMN 中的命名空间 + */ + String NAMESPACE = "http://flowable.org/bpmn"; + + /** + * BPMN UserTask 的扩展属性,用于标记候选人策略 + */ + String USER_TASK_CANDIDATE_STRATEGY = "candidateStrategy"; + /** + * BPMN UserTask 的扩展属性,用于标记候选人参数 + */ + String USER_TASK_CANDIDATE_PARAM = "candidateParam"; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java deleted file mode 100644 index 0c5f099d6..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashSet; -import java.util.Set; - -/** - * 获取候选人信息 - */ -@AllArgsConstructor -@NoArgsConstructor -@Data -public class BpmCandidateSourceInfo { - @Schema(description = "当前任务ID") - @NotNull - private String taskId; - /** - * 通过这些规则,生成最终需要生成的用户 - */ - @Schema(description = "当前任务预选规则") - @NotEmpty(message = "不允许空规则") - private Set rules; - - @Schema(description = "发起抄送的用户") - private String creator; - - @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!") - @NotEmpty(message = "抄送原因不能为空") - private String reason; - - public void addRule(BpmTaskCandidateRuleVO vo) { - assert vo != null; - if (rules == null) { - rules = new HashSet<>(); - } - rules.add(vo); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java deleted file mode 100644 index 0fe741c20..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public interface BpmCandidateSourceInfoProcessor { - /** - * 获取该处理器支持的类型 - * 来自 {@link BpmTaskAssignRuleTypeEnum} - * - * @return - */ - Set getSupportedTypes(); - - /** - * 对规则和人员做校验 - * - * @param type 规则 - * @param options 人员id - */ - void validRuleOptions(Integer type, Set options); - - /** - * 默认的处理 - * 如果想去操作所有的规则,则可以覆盖此方法 - * - * @param request 原始请求 - * @param delegateExecution 审批过程中的对象 - * @return 必须包含的是用户ID,而不是其他的ID - * @throws Exception - */ - default Set process(BpmCandidateSourceInfo request, DelegateExecution delegateExecution) throws Exception { - Set rules = request.getRules(); - Set results = new HashSet<>(); - for (BpmTaskCandidateRuleVO rule : rules) { - // 每个处理器都有机会处理自己支持的事件 - if (CollUtil.contains(getSupportedTypes(), rule.getType())) { - results.addAll(doProcess(request, rule, delegateExecution)); - } - } - return results; - } - - default Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return Collections.emptySet(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java deleted file mode 100644 index dafc0835a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.util.*; - -@Service -public class BpmCandidateSourceInfoProcessorChain { - - // 保存处理节点 - - private List processorList; - @Resource - private AdminUserApi adminUserApi; - - /** - * 可添加其他处理器 - * - * @param processorOp - * @return - */ - @Resource - // 动态扩展处理节点 - public BpmCandidateSourceInfoProcessorChain addProcessor(ObjectProvider processorOp) { - List processor = ListUtil.toList(processorOp.iterator()); - if (null == processorList) { - processorList = new ArrayList<>(processor.size()); - } - processorList.addAll(processor); - return this; - } - - // 获取处理器处理 - public Set process(BpmCandidateSourceInfo sourceInfo, DelegateExecution execution) throws Exception { - // Verify our parameters - if (sourceInfo == null) { - throw new IllegalArgumentException(); - } - for (BpmCandidateSourceInfoProcessor processor : processorList) { - try { - for (BpmTaskCandidateRuleVO vo : sourceInfo.getRules()) { - if (CollUtil.contains(processor.getSupportedTypes(), vo.getType())) { - processor.validRuleOptions(vo.getType(), vo.getOptions()); - } - } - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - Set saveResult = Collections.emptySet(); - Exception saveException = null; - for (BpmCandidateSourceInfoProcessor processor : processorList) { - try { - saveResult = processor.process(sourceInfo, execution); - if (CollUtil.isNotEmpty(saveResult)) { - removeDisableUsers(saveResult); - break; - } - } catch (Exception e) { - saveException = e; - break; - } - } - // Return the exception or result state from the last execute() - if ((saveException != null)) { - throw saveException; - } else { - return (saveResult); - } - } - - public Set calculateTaskCandidateUsers(DelegateExecution execution, BpmCandidateSourceInfo sourceInfo) { - Set results = Collections.emptySet(); - try { - results = process(sourceInfo, execution); - } catch (Exception e) { - e.printStackTrace(); - } - return results; - } - - /** - * 移除禁用用户 - * - * @param assigneeUserIds - */ - public void removeDisableUsers(Set assigneeUserIds) { - if (CollUtil.isEmpty(assigneeUserIds)) { - return; - } - Map userMap = adminUserApi.getUserMap(assigneeUserIds); - assigneeUserIds.removeIf(id -> { - AdminUserRespDTO user = userMap.get(id); - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); - }); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java deleted file mode 100644 index 536b3eec2..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Set; - -public class BpmCandidateAdminUserApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private AdminUserApi api; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validateUserList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return rule.getOptions(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java deleted file mode 100644 index 6fcfa23fd..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -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 org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -public class BpmCandidateDeptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private DeptApi api; - @Resource - private AdminUserApi adminUserApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validateDeptList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { - List users = adminUserApi.getUserListByDeptIds(rule.getOptions()); - return convertSet(users, AdminUserRespDTO::getId); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { - List depts = api.getDeptList(rule.getOptions()); - return convertSet(depts, DeptRespDTO::getLeaderUserId); - } - return Collections.emptySet(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java deleted file mode 100644 index f924d87ef..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.dept.PostApi; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.List; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -public class BpmCandidatePostApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private PostApi api; - @Resource - private AdminUserApi adminUserApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.POST.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validPostList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - List users = adminUserApi.getUserListByPostIds(rule.getOptions()); - return convertSet(users, AdminUserRespDTO::getId); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java deleted file mode 100644 index f3ba5b92b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.permission.RoleApi; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Set; - -public class BpmCandidateRoleApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private RoleApi api; - - @Resource - private PermissionApi permissionApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.ROLE.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validRoleList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java deleted file mode 100644 index 4bf25694d..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.ObjectProvider; - -import jakarta.annotation.Resource; -import java.util.*; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS; - -public class BpmCandidateScriptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private DictDataApi dictDataApi; - - /** - * 任务分配脚本 - */ - private Map scriptMap = Collections.emptyMap(); - - public void setScripts(ObjectProvider scriptsOp) { - List scripts = scriptsOp.orderedStream().collect(Collectors.toList()); - setScripts(scripts); - } - - public void setScripts(List scripts) { - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); - } - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, - CollectionUtils.convertSet(options, String::valueOf)); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return calculateTaskCandidateUsersByScript(delegateExecution, rule.getOptions()); - } - - private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, Set options) { - // 获得对应的脚本 - List scripts = new ArrayList<>(options.size()); - options.forEach(id -> { - BpmTaskAssignScript script = scriptMap.get(id); - if (script == null) { - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); - } - scripts.add(script); - }); - // 逐个计算任务 - Set userIds = new HashSet<>(); - scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); - return userIds; - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java deleted file mode 100644 index b0720b0d5..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class BpmCandidateUserGroupApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private BpmUserGroupService api; - @Resource - private BpmUserGroupService userGroupService; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validUserGroups(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - List userGroups = userGroupService.getUserGroupList(rule.getOptions()); - Set userIds = new HashSet<>(); - userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); - return userIds; - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 00ba49de4..729e176b0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import jakarta.annotation.Resource; @@ -54,8 +55,9 @@ public class BpmModelServiceImpl implements BpmModelService { private BpmProcessDefinitionService processDefinitionService; @Resource private BpmFormService bpmFormService; + @Resource - private BpmTaskAssignRuleService taskAssignRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; @Override public PageResult getModelPage(BpmModelPageReqVO pageVO) { @@ -166,7 +168,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 1.3 校验表单已配 BpmFormDO form = checkFormConfig(model.getMetaInfo()); // 1.4 校验任务分配规则已配置 - taskAssignRuleService.checkTaskAssignRuleAllConfig(bpmnBytes); + taskCandidateInvoker.validateBpmnConfig(bpmnBytes); // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) 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 dd5f035a9..82f15beec 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 @@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.PageUtils; -import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java deleted file mode 100644 index 012141adf..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Set; - -/** - * BPM 任务分配规则 Service 接口 - * - * @author 芋道源码 - */ -public interface BpmTaskAssignRuleService { - - /** - * 校验流程模型的任务分配规则全部都配置了 - * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! - * - * @param bpmnBytes BPMN XML - */ - void checkTaskAssignRuleAllConfig(byte[] bpmnBytes); - - /** - * 计算当前执行任务的处理人 - * - * @param execution 执行任务 - * @return 处理人的编号数组 - */ - Set calculateTaskCandidateUsers(DelegateExecution execution); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java deleted file mode 100644 index a1474afd0..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java +++ /dev/null @@ -1,254 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -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.string.StrUtils; -import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; -import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.PostApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.permission.RoleApi; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import com.google.common.annotations.VisibleForTesting; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.dromara.hutool.core.convert.Convert; -import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.UserTask; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.*; -import java.util.function.Function; - -import static cn.hutool.core.text.CharSequenceUtil.format; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; - -/** - * BPM 任务分配规则 Service 实现类 - */ -@Service -@Validated -@Slf4j -public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { - - @Resource - private BpmUserGroupService userGroupService; - @Resource - @Lazy // 解决循环依赖 - private BpmProcessInstanceService processInstanceService; - -// @Resource -// private ExpressionManager expressionManager; - - @Resource - private RoleApi roleApi; - @Resource - private DeptApi deptApi; - @Resource - private PostApi postApi; - @Resource - private AdminUserApi adminUserApi; - @Resource - private DictDataApi dictDataApi; - @Resource - private PermissionApi permissionApi; - - /** - * 任务分配脚本 - */ - private Map scriptMap = Collections.emptyMap(); - - @Resource - public void setScripts(List scripts) { - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); - } - - @Override - public void checkTaskAssignRuleAllConfig(byte[] bpmnBytes) { - BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); - assert bpmnModel != null; - List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); - // 遍历所有的 UserTask,校验审批人配置 - userTaskList.forEach(userTask -> { - // TODO 芋艿:assignType/assignOptions/, 枚举 - Integer type = NumberUtils.parseInt(userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); - String options = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); - if (type == null || StrUtil.isBlank(options)) { - throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName()); - } - // TODO 芋艿:校验 options - if (ObjectUtil.equal(type, BpmTaskAssignRuleTypeEnum.EXPRESS.getType())) { - return; - } - validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ",")); - }); - } - - private void validTaskAssignRuleOptions(Integer type, Collection options) { - if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { - roleApi.validRoleList(options); - } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { - deptApi.validateDeptList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { - postApi.validPostList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER.getType())) { - adminUserApi.validateUserList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) { - userGroupService.validUserGroups(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { - dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, - CollectionUtils.convertSet(options, String::valueOf)); - } else { - throw new IllegalArgumentException(format("未知的规则类型({})", type)); - } - } - - public Long test(DelegateExecution execution) { - return 1L; - } - - public Long test2(DelegateExecution execution, Long id) { - return id; - } - - @Override - @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题 - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - // 1. 先从提前选好的审批人中获取 - List assignee = processInstanceService.getAssigneeByProcessInstanceIdAndTaskDefinitionKey( - execution.getProcessInstanceId(), execution.getCurrentActivityId()); - if (CollUtil.isNotEmpty(assignee)) { - // TODO @hai:new HashSet 即可 - return convertSet(assignee, Function.identity()); - } - // 2. 通过分配规则,计算审批人 - return calculateTaskCandidateUsers0(execution); - } - - @VisibleForTesting - Set calculateTaskCandidateUsers0(DelegateExecution execution) { - // 获得审批人配置 - // TODO 芋艿:assignType/assignOptions/, 枚举 - FlowElement flowElement = execution.getCurrentFlowElement(); - Integer type = NumberUtils.parseInt(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); - String optionStr = flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); - Set options = null; - if (ObjectUtil.notEqual(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { - options = StrUtils.splitToLongSet(optionStr, ","); - } - - // 计算审批人 - Set assigneeUserIds = null; - if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByRole(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByDeptMember(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByPost(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByUser(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { - Object result = FlowableUtils.getExpressionValue(execution, optionStr); - assigneeUserIds = Convert.toSet(Long.class, result); - } - - // 移除被禁用的用户 - removeDisableUsers(assigneeUserIds); - // 如果候选人为空,抛出异常 - if (CollUtil.isEmpty(assigneeUserIds)) { - log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), - execution.getProcessDefinitionId(), execution.getCurrentActivityId(), type, options); - throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); - } - return assigneeUserIds; - } - - private Set calculateTaskCandidateUsersByRole(Set roleIds) { - return permissionApi.getUserRoleIdListByRoleIds(roleIds); - } - - private Set calculateTaskCandidateUsersByDeptMember(Set deptIds) { - List users = adminUserApi.getUserListByDeptIds(deptIds); - return convertSet(users, AdminUserRespDTO::getId); - } - - private Set calculateTaskCandidateUsersByDeptLeader(Set deptIds) { - List depts = deptApi.getDeptList(deptIds); - return convertSet(depts, DeptRespDTO::getLeaderUserId); - } - - private Set calculateTaskCandidateUsersByPost(Set postIds) { - List users = adminUserApi.getUserListByPostIds(postIds); - return convertSet(users, AdminUserRespDTO::getId); - } - - private Set calculateTaskCandidateUsersByUser(Set userIds) { - return userIds; - } - - private Set calculateTaskCandidateUsersByUserGroup(Set groupIds) { - List userGroups = userGroupService.getUserGroupList(groupIds); - Set userIds = new HashSet<>(); - userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); - return userIds; - } - - private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, Set scriptIds) { - // 获得对应的脚本 - List scripts = new ArrayList<>(scriptIds.size()); - scriptIds.forEach(scriptId -> { - BpmTaskAssignScript script = scriptMap.get(scriptId); - if (script == null) { - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, scriptId); - } - scripts.add(script); - }); - // 逐个计算任务 - Set userIds = new HashSet<>(); - scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); - return userIds; - } - - @VisibleForTesting - void removeDisableUsers(Set assigneeUserIds) { - if (CollUtil.isEmpty(assigneeUserIds)) { - return; - } - Map userMap = adminUserApi.getUserMap(assigneeUserIds); - assigneeUserIds.removeIf(id -> { - AdminUserRespDTO user = userMap.get(id); - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); - }); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java index 208749a57..4d1db2958 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; /** * 流程抄送 Service 接口 @@ -13,14 +12,6 @@ import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; */ public interface BpmProcessInstanceCopyService { - // TODO 芋艿:这块要 review 下;思考下~~ - /** - * 抄送 - * @param sourceInfo 抄送源信息,方便抄送处理 - * @return - */ - boolean makeCopy(BpmCandidateSourceInfo sourceInfo); - /** * 流程实例的抄送 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java index 50d042cdc..d800d1932 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java @@ -1,35 +1,22 @@ package cn.iocoder.yudao.module.bpm.service.task.cc; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; -import cn.iocoder.yudao.module.bpm.service.task.cc.dto.BpmDelegateExecutionDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.flowable.engine.RuntimeService; -import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -45,12 +32,6 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @Resource private BpmProcessInstanceCopyMapper processInstanceCopyMapper; - @Resource - private RuntimeService runtimeService; - - @Resource - private BpmCandidateSourceInfoProcessorChain processorChain; - @Resource @Lazy private BpmTaskService bpmTaskService; @@ -58,55 +39,6 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @Lazy private BpmProcessInstanceService bpmProcessInstanceService; - @Override - public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) { - if (null == sourceInfo) { - return false; - } - - Task task = bpmTaskService.getTask(sourceInfo.getTaskId()); - if (ObjectUtil.isNull(task)) { - return false; - } - String processInstanceId = task.getProcessInstanceId(); - if (StrUtil.isBlank(processInstanceId)) { - return false; - } - DelegateExecution executionEntity = new BpmDelegateExecutionDTO(processInstanceId); - Set ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo); - if (CollUtil.isEmpty(ccCandidates)) { - log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId()); - return false; - } else { - BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO(); - // 调用 - // 设置任务id - copyDO.setTaskId(sourceInfo.getTaskId()); - copyDO.setTaskName(task.getName()); - copyDO.setProcessInstanceId(processInstanceId); - ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId) - .singleResult(); - if (null == processInstance) { - log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId()); - return false; - } - copyDO.setStartUserId(Long.parseLong(processInstance.getStartUserId())); - copyDO.setProcessInstanceName(processInstance.getName()); - copyDO.setCategory(processInstance.getProcessDefinitionCategory()); - copyDO.setReason(sourceInfo.getReason()); - copyDO.setCreator(sourceInfo.getCreator()); - copyDO.setCreateTime(LocalDateTime.now()); - List copyList = new ArrayList<>(ccCandidates.size()); - for (Long userId : ccCandidates) { - BpmProcessInstanceCopyDO copy = BeanUtil.copyProperties(copyDO, BpmProcessInstanceCopyDO.class); - copy.setUserId(userId); - copyList.add(copy); - } - return processInstanceCopyMapper.insertBatch(copyList); - } - } - @Override public void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO reqVO) { // 1.1 校验任务存在 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java new file mode 100644 index 000000000..702dce3f1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateUserStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * {@link BpmTaskCandidateInvoker} 的单元测试 + * + * @author 芋道源码 + */ +public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateInvoker taskCandidateInvoker; + + @Mock + private AdminUserApi adminUserApi; + @Spy + private BpmTaskCandidateStrategy strategy = new BpmTaskCandidateUserStrategy(); + @Spy + private List strategyList = Collections.singletonList(strategy); + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法(DelegateExecution) + UserTask userTask = mock(UserTask.class); + when(execution.getCurrentFlowElement()).thenReturn(userTask); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY))) + .thenReturn(BpmTaskCandidateStrategyEnum.USER.getStrategy().toString()); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM))) + .thenReturn(param); + // mock 方法(adminUserApi) + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap); + + // 调用 + Set results = taskCandidateInvoker.calculateUsers(execution); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + + @Test + public void testRemoveDisableUsers() { + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 + Set assigneeUserIds = asSet(1L, 2L, 3L); + // mock 方法 + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); + + // 调用 + taskCandidateInvoker.removeDisableUsers(assigneeUserIds); + // 断言 + assertEquals(asSet(1L), assigneeUserIds); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java similarity index 86% rename from yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java index f46278083..b9a77ca79 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; @@ -21,10 +21,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { +public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest { @InjectMocks - private BpmTaskAssignLeaderX2Script script; + private BpmTaskAssignLeaderExpression expression; @Mock private AdminUserApi adminUserApi; @@ -34,7 +34,7 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { private BpmProcessInstanceService bpmProcessInstanceService; @Test - public void testCalculateTaskCandidateUsers_noDept() { + public void testCalculateUsers_noDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -44,13 +44,13 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(10L))).thenReturn(null); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 1); // 断言 assertEquals(0, result.size()); } @Test - public void testCalculateTaskCandidateUsers_noParentDept() { + public void testCalculateUsers_noParentDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -63,13 +63,13 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(100L))).thenReturn(null); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 2); // 断言 assertEquals(asSet(20L), result); } @Test - public void testCalculateTaskCandidateUsers_existParentDept() { + public void testCalculateUsers_existParentDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -84,7 +84,7 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(100L))).thenReturn(parentDept); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 2); // 断言 assertEquals(asSet(200L), result); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java new file mode 100644 index 000000000..9b89e2bd3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptLeaderStrategy strategy; + + @Mock + private DeptApi deptApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); + DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); + when(deptApi.getDeptList(eq(asSet(1L, 2L)))).thenReturn(asList(dept1, dept2)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java new file mode 100644 index 000000000..4e72c0281 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptMemberStrategy strategy; + + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "11,22"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java new file mode 100644 index 000000000..caa668eac --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateExpressionStrategy strategy; + + @Test + public void testCalculateUsers() { + try (MockedStatic flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法 + flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(execution), eq(param))) + .thenReturn(asSet(1L, 2L)); + + // 调用 + Set results = strategy.calculateUsers(execution, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java new file mode 100644 index 000000000..07958a51b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Arrays; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateGroupStrategy strategy; + + @Mock + private BpmUserGroupService userGroupService; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); + when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 12L, 21L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java new file mode 100644 index 000000000..a30ce28eb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidatePostStrategy strategy; + + @Mock + private PostApi postApi; + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java new file mode 100644 index 000000000..7c4247bcd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateRoleStrategy strategy; + + @Mock + private RoleApi roleApi; + @Mock + private PermissionApi permissionApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + when(permissionApi.getUserRoleIdListByRoleIds(eq(asSet(1L, 2L)))) + .thenReturn(asSet(11L, 22L)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java new file mode 100644 index 000000000..d71ccebfd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateUserStrategy strategy; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java deleted file mode 100644 index 29caf9ced..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java +++ /dev/null @@ -1,244 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX1Script; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX2Script; -import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.BpmCandidateScriptApiSourceInfoProcessor; -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.PostApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.permission.RoleApi; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import jakarta.annotation.Resource; -import org.flowable.engine.delegate.DelegateExecution; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static java.util.Collections.singleton; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -@Disabled // TODO 芋艿:临时禁用,暂时不修复,等重构后解决 -@Import({BpmCandidateSourceInfoProcessorChain.class, - BpmCandidateScriptApiSourceInfoProcessor.class, BpmTaskAssignLeaderX1Script.class, - BpmTaskAssignLeaderX2Script.class}) -public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest { - @Resource - private BpmCandidateSourceInfoProcessorChain processorChain; - - @MockBean - private BpmUserGroupService userGroupService; - @MockBean - private DeptApi deptApi; - @MockBean - private AdminUserApi adminUserApi; - @MockBean - private PermissionApi permissionApi; - @MockBean - private RoleApi roleApi; - @MockBean - private PostApi postApi; - @MockBean - private DictDataApi dictDataApi; - @Resource - private BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor; - - @Test - public void testCalculateTaskCandidateUsers_Role() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); - // mock 方法 - when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) - .thenReturn(asSet(11L, 22L)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptMember() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByDeptIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptLeader() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); - // mock 方法 - DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); - DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); - when(deptApi.getDeptList(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_Post() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_User() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); - // mock 方法 - mockGetUserMap(asSet(1L, 2L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(1L, 2L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_UserGroup() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); - // mock 方法 - BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); - BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); - when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2)); - mockGetUserMap(asSet(11L, 12L, 21L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 12L, 21L, 22L), results); - } - - private void mockGetUserMap(Set assigneeUserIds) { - Map userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, - id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - } - - @Test - public void testCalculateTaskCandidateUsers_Script() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(20L, 21L)) - .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); - // mock 方法 - BpmTaskAssignScript script1 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(11L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - }; - BpmTaskAssignScript script2 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(22L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - }; - bpmCandidateScriptApiSourceInfoProcessor.setScripts(Arrays.asList(script1, script2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testRemoveDisableUsers() { - // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 - Set assigneeUserIds = asSet(1L, 2L, 3L); - // mock 方法 - AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) - .setStatus(CommonStatusEnum.DISABLE.getStatus())); - Map userMap = MapUtil.builder(user1.getId(), user1) - .put(user2.getId(), user2).build(); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - - // 调用 - processorChain.removeDisableUsers(assigneeUserIds); - // 断言 - assertEquals(asSet(1L), assigneeUserIds); - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java deleted file mode 100644 index 2ca2ff914..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java +++ /dev/null @@ -1,227 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignStartUserScript; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.PostApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.permission.RoleApi; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.delegate.DelegateExecution; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import jakarta.annotation.Resource; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static java.util.Collections.singleton; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -/** - * {@link BpmTaskAssignRuleService} 的单元测试 - * - * @author 芋道源码 - */ -@Import({BpmTaskAssignRuleServiceImpl.class, BpmTaskAssignStartUserScript.class}) // Import 引入 BpmTaskAssignStartUserScript 目的是保证不报错 -public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest { - - @Resource - private BpmTaskAssignRuleServiceImpl bpmTaskRuleService; - - @MockBean - private BpmUserGroupService userGroupService; - @MockBean - private DeptApi deptApi; - @MockBean - private AdminUserApi adminUserApi; - @MockBean - private PermissionApi permissionApi; - @MockBean - private RoleApi roleApi; - @MockBean - private PostApi postApi; - @MockBean - private DictDataApi dictDataApi; - - @Test - public void testCalculateTaskCandidateUsers_Role() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); - // mock 方法 - when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) - .thenReturn(asSet(11L, 22L)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptMember() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByDeptIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptLeader() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); - // mock 方法 - DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); - DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); - when(deptApi.getDeptList(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_Post() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_User() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); - // mock 方法 - mockGetUserMap(asSet(1L, 2L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(1L, 2L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_UserGroup() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); - // mock 方法 - BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); - BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); - when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2)); - mockGetUserMap(asSet(11L, 12L, 21L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 12L, 21L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_Script() { - // 准备参数 - BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(20L, 21L)) - .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); - // mock 方法 - BpmTaskAssignScript script1 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(11L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - }; - BpmTaskAssignScript script2 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(22L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - }; - bpmTaskRuleService.setScripts(Arrays.asList(script1, script2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testRemoveDisableUsers() { - // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 - Set assigneeUserIds = asSet(1L, 2L, 3L); - // mock 方法 - AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) - .setStatus(CommonStatusEnum.ENABLE.getStatus())); - AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) - .setStatus(CommonStatusEnum.DISABLE.getStatus())); - Map userMap = MapUtil.builder(user1.getId(), user1) - .put(user2.getId(), user2).build(); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - - // 调用 - bpmTaskRuleService.removeDisableUsers(assigneeUserIds); - // 断言 - assertEquals(asSet(1L), assigneeUserIds); - } - - private void mockGetUserMap(Set assigneeUserIds) { - Map userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, - id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java deleted file mode 100644 index f279e95df..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.enums; - -/** - * 流程常量信息 - */ -public interface BpmnModelConstants { - - String BPMN_FILE_SUFFIX = ".bpmn"; - - /** - * BPMN 中的命名空间 - * - * 这个东西有可能导致无法切换工作流程的实现 - */ - String NAMESPACE = "http://flowable.org/bpmn"; - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java deleted file mode 100644 index de8d6279d..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java deleted file mode 100644 index 324d3de0e..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable; From a1defeb48af149a3277498a41b84642560ecdb5a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 15 Mar 2024 21:08:43 +0800 Subject: [PATCH 04/26] =?UTF-8?q?BPM=EF=BC=9A=E6=96=B0=E5=A2=9E=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=E4=BC=9A=E7=AD=BE=E3=80=81=E6=88=96=E7=AD=BE=E7=9A=84?= =?UTF-8?q?=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/BpmActivityBehaviorFactory.java | 12 +++-- .../BpmParallelMultiInstanceBehavior.java | 6 +-- .../BpmSequentialMultiInstanceBehavior.java | 50 +++++++++++++++++++ .../behavior/BpmUserTaskActivityBehavior.java | 3 +- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java index e9f1f32d7..b5278f5ab 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java @@ -6,6 +6,7 @@ import org.flowable.bpmn.model.Activity; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; @@ -28,11 +29,16 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { @Override public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, - AbstractBpmnActivityBehavior innerActivityBehavior) { - return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior) + AbstractBpmnActivityBehavior behavior) { + return new BpmParallelMultiInstanceBehavior(activity, behavior) .setTaskCandidateInvoker(taskCandidateInvoker); } - // TODO @ke:SequentialMultiInstanceBehavior 这个抽空也可以看看 + @Override + public SequentialMultiInstanceBehavior createSequentialMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior behavior) { + return new BpmSequentialMultiInstanceBehavior(activity, behavior) + .setTaskCandidateInvoker(taskCandidateInvoker); + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index ed51b23fa..938d04ed1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; -import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Activity; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; @@ -17,12 +16,11 @@ import java.util.Set; * 第二步,将【多个】任务候选人们,设置到 DelegateExecution 的 collectionVariable 变量中,以便 BpmUserTaskActivityBehavior 使用它 * * @author kemengkai - * @date 2022-04-21 16:57 + * @since 2022-04-21 16:57 */ -@Slf4j +@Setter public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { - @Setter private BpmTaskCandidateInvoker taskCandidateInvoker; public BpmParallelMultiInstanceBehavior(Activity activity, diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java new file mode 100644 index 000000000..1e4ebc141 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import lombok.Setter; +import org.flowable.bpmn.model.Activity; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * 自定义的【串行】的【多个】流程任务的 assignee 负责人的分配 + * + * 本质上,实现和 {@link BpmParallelMultiInstanceBehavior} 一样,只是继承的类不一样 + * + * @author 芋道源码 + */ +@Setter +public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceBehavior { + + private BpmTaskCandidateInvoker taskCandidateInvoker; + + public BpmSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + /** + * 逻辑和 {@link BpmParallelMultiInstanceBehavior#resolveNrOfInstances(DelegateExecution)} 类似 + * + * 差异的点:是在【第二步】的时候,需要返回 LinkedHashSet 集合!因为它需要有序! + */ + @Override + protected int resolveNrOfInstances(DelegateExecution execution) { + // 第一步,设置 collectionVariable 和 CollectionVariable + // 从 execution.getVariable() 读取所有任务处理人的 key + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 + super.collectionVariable = FlowableUtils.formatCollectionVariable(execution.getCurrentActivityId()); + // 从 execution.getVariable() 读取当前所有任务处理的人的 key + super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); + + // 第二步,获取任务的所有处理人 + Set assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!! + execution.setVariable(super.collectionVariable, assigneeUserIds); + return assigneeUserIds.size(); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java index de17502bf..c49465273 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java @@ -47,7 +47,8 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { } private Long calculateTaskCandidateUsers(DelegateExecution execution) { - // 情况一,如果是多实例的任务,例如说会签、或签等情况,则从 Variable 中获取。它的任务处理人在 BpmParallelMultiInstanceBehavior 中已经被分配了 + // 情况一,如果是多实例的任务,例如说会签、或签等情况,则从 Variable 中获取。 + // 顺序审批可见 BpmSequentialMultiInstanceBehavior,并发审批可见 BpmSequentialMultiInstanceBehavior if (super.multiInstanceActivityBehavior != null) { return execution.getVariable(super.multiInstanceActivityBehavior.getCollectionElementVariable(), Long.class); } From 7967a2a195f93e153e320ac08176dfa2e1298254 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 16 Mar 2024 16:43:53 +0800 Subject: [PATCH 05/26] =?UTF-8?q?BPM=EF=BC=9A=E6=B5=81=E7=A8=8B=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E7=9A=84=20`status`=20=E7=8A=B6=E6=80=81=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=8C=E4=BD=BF=E7=94=A8=20Flowable=20=E7=9A=84=20`?= =?UTF-8?q?variables`=20=E5=AD=98=E5=82=A8=EF=BC=8C=E7=A7=BB=E9=99=A4=20`b?= =?UTF-8?q?pm=5Fprocess=5Finstance=5Fext`=20=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceStatusEnum.java | 6 +- .../task/BpmProcessInstanceStatusOldEnum.java | 28 ++++++ .../candidate/vo/BpmTaskCandidateRuleVO.java | 24 ----- .../task/BpmProcessInstanceController.java | 28 +++++- .../BpmProcessInstancePageItemRespVO.java | 7 +- .../vo/instance/BpmProcessInstanceRespVO.java | 4 +- .../task/vo/task/BpmTaskApproveReqVO.java | 1 - .../task/BpmProcessInstanceConvert.java | 35 +++---- .../task/BpmProcessInstanceExtDO.java | 98 ------------------- .../task/BpmProcessInstanceExtMapper.java | 34 ------- .../flowable/core/enums/BpmConstants.java | 19 ++++ .../core/enums/BpmnModelConstants.java | 4 +- .../BpmProcessInstanceEventListener.java | 11 +-- .../BpmProcessDefinitionService.java | 22 +++-- .../BpmProcessDefinitionServiceImpl.java | 4 +- .../task/BpmProcessInstanceService.java | 65 ++++++------ .../task/BpmProcessInstanceServiceImpl.java | 2 +- 17 files changed, 150 insertions(+), 242 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java index 70a31dd34..089690457 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 流程实例的状态 + * 流程实例 ProcessInstance 的状态 * * @author 芋道源码 */ @@ -13,7 +13,9 @@ import lombok.Getter; public enum BpmProcessInstanceStatusEnum { RUNNING(1, "进行中"), - FINISH(2, "已完成"); + APPROVE(2, "通过"), + REJECT(3, "不通过"), + CANCEL(4, "已取消"); /** * 状态 diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java new file mode 100644 index 000000000..1db19cf64 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例的状态 + * + * @author 芋道源码 + */ +@Deprecated +@Getter +@AllArgsConstructor +public enum BpmProcessInstanceStatusOldEnum { + + RUNNING(1, "进行中"), + FINISH(2, "已完成"); + + /** + * 状态 + */ + private final Integer status; + /** + * 描述 + */ + private final String desc; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java deleted file mode 100644 index 62b1dff1c..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.util.Set; - -/** - * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 - */ -@Data -public class BpmTaskCandidateRuleVO { - - @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type") - @NotNull(message = "规则类型不能为空") - private Integer type; - - @Schema(description = "规则值数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") - @NotNull(message = "规则值数组不能为空") - private Set options; - -} 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 9d1301a27..c22ee3c6b 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 @@ -1,19 +1,31 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.task.api.Task; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.Map; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” @@ -24,13 +36,27 @@ public class BpmProcessInstanceController { @Resource private BpmProcessInstanceService processInstanceService; + @Resource + private BpmTaskService taskService; + @Resource + private BpmProcessDefinitionService processDefinitionService; @GetMapping("/my-page") @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult> getMyProcessInstancePage( @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { - return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO)); + PageResult pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + Map> taskMap = taskService.getTaskMapByProcessInstanceIds( + convertList(pageResult.getList(), HistoricProcessInstance::getId)); + Map processDefinitionMap = processDefinitionService.getProcessDefinitionMap( + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); + return success(BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, processDefinitionMap, taskMap)); } @PostMapping("/create") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java index 6bb269f1d..4cfaf171d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java @@ -23,13 +23,10 @@ public class BpmProcessInstancePageItemRespVO { private String category; @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; - - @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer result; + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; + private LocalDateTime startTime; @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime endTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java index a9cc810f7..faa770c47 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -20,8 +20,8 @@ public class BpmProcessInstanceRespVO { @Schema(description = "流程分类-参见 bpm_model_category 数据字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String category; - @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; + @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer result; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index 1a79441ce..14dca13ea 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 41f2184c5..11166c62e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -1,13 +1,15 @@ package cn.iocoder.yudao.module.bpm.convert.task; 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.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -34,25 +36,26 @@ public interface BpmProcessInstanceConvert { BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); - default PageResult convertPage(PageResult page, + default PageResult convertPage(PageResult pageResult, + Map processDefinitionMap, Map> taskMap) { - List list = convertList(page.getList()); - list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId())))); - return new PageResult<>(list, page.getTotal()); + PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); + for (int i = 0; i < pageResult.getList().size(); i++) { + BpmProcessInstancePageItemRespVO respVO = vpPageResult.getList().get(i); + respVO.setStatus((Integer) pageResult.getList().get(i).getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); + MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), + processDefinition -> respVO.setCategory(processDefinition.getCategory())); + respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstancePageItemRespVO.Task.class)); + } + return vpPageResult; } - List convertList(List list); - - @Mapping(source = "processInstanceId", target = "id") - BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean); - - List convertList2(List tasks); - - default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt, + default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt, String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { BpmProcessInstanceRespVO respVO = convert2(processInstance); - copyTo(processInstanceExt, respVO); + respVO.setStatus((Integer) processInstance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); + respVO.setFormVariables(processInstance.getProcessVariables()); // TODO 芋艿:真的这么搞么???formVariable 要不要换个 key 之类的 // definition respVO.setProcessDefinition(convert2(processDefinition)); copyTo(processDefinitionExt, respVO.getProcessDefinition()); @@ -69,9 +72,6 @@ public interface BpmProcessInstanceConvert { BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean); - @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to); - BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); @Mapping(source = "from.id", target = "to.id", ignore = true) @@ -88,6 +88,7 @@ public interface BpmProcessInstanceConvert { return event; } + // TODO @芋艿:需要改下 key! default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); event.setId(instance.getId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java deleted file mode 100644 index 5a481fff0..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java +++ /dev/null @@ -1,98 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.dataobject.task; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -/** - * Bpm 流程实例的拓展表 - * 主要解决 Activiti ProcessInstance 和 HistoricProcessInstance 不支持拓展字段,所以新建拓展表 - * - * @author 芋道源码 - */ -@TableName(value = "bpm_process_instance_ext", autoResultMap = true) -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmProcessInstanceExtDO extends BaseDO { - - /** - * 编号,自增 - */ - @TableId - private Long id; - /** - * 发起流程的用户编号 - * - * 冗余 HistoricProcessInstance 的 startUserId 属性 - */ - private Long startUserId; - /** - * 流程实例的名字 - * - * 冗余 ProcessInstance 的 name 属性,用于筛选 - */ - private String name; - /** - * 流程实例的编号 - * - * 关联 ProcessInstance 的 id 属性 - */ - private String processInstanceId; - /** - * 流程定义的编号 - * - * 关联 ProcessDefinition 的 id 属性 - */ - private String processDefinitionId; - /** - * 流程分类 - * - * 冗余 ProcessDefinition 的 category 属性 - * 数据字典 bpm_model_category - */ - private String category; - /** - * 流程实例的状态 - * - * 枚举 {@link BpmProcessInstanceStatusEnum} - */ - private Integer status; - /** - * 流程实例的结果 - * - * 枚举 {@link BpmProcessInstanceResultEnum} - */ - private Integer result; - /** - * 结束时间 - * - * 冗余 HistoricProcessInstance 的 endTime 属性 - */ - private LocalDateTime endTime; - - /** - * 提交的表单值 - */ - @TableField(typeHandler = JacksonTypeHandler.class) - private Map formVariables; - - // TODO @hai:assignees 复数 - /** - * 提前设定好的审批人 - */ - @TableField(typeHandler = JacksonTypeHandler.class, exist = false) // TODO 芋艿:临时 exist = false,避免 db 报错; - private Map> assignee; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java deleted file mode 100644 index 52e66219c..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.mysql.task; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; -import org.apache.ibatis.annotations.Mapper; - -@Mapper -public interface BpmProcessInstanceExtMapper extends BaseMapperX { - - default PageResult selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(BpmProcessInstanceExtDO::getStartUserId, userId) - .likeIfPresent(BpmProcessInstanceExtDO::getName, reqVO.getName()) - .eqIfPresent(BpmProcessInstanceExtDO::getProcessDefinitionId, reqVO.getProcessDefinitionId()) - .eqIfPresent(BpmProcessInstanceExtDO::getCategory, reqVO.getCategory()) - .eqIfPresent(BpmProcessInstanceExtDO::getStatus, reqVO.getStatus()) - .eqIfPresent(BpmProcessInstanceExtDO::getResult, reqVO.getResult()) - .betweenIfPresent(BpmProcessInstanceExtDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(BpmProcessInstanceExtDO::getId)); - } - - default BpmProcessInstanceExtDO selectByProcessInstanceId(String processInstanceId) { - return selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, processInstanceId); - } - - default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) { - update(updateObj, new LambdaQueryWrapperX() - .eq(BpmProcessInstanceExtDO::getProcessInstanceId, updateObj.getProcessInstanceId())); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java new file mode 100644 index 000000000..b2bd419e6 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +import org.flowable.engine.runtime.ProcessInstance; + +/** + * BPM 通用常量 + * + * @author 芋道源码 + */ +public class BpmConstants { + + /** + * 流程实例的变量 - 状态 + * + * @see ProcessInstance#getProcessVariables() + */ + public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS"; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java index c8fefd55b..3eb6981ef 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; /** - * 流程常量信息 + * BPMN XML 常量信息 + * + * @author 芋道源码 */ public interface BpmnModelConstants { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java index 9f37c9ae7..f8e5920f1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import com.google.common.collect.ImmutableSet; +import jakarta.annotation.Resource; import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; @@ -11,11 +11,10 @@ import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; -import jakarta.annotation.Resource; import java.util.Set; /** - * 监听 {@link ProcessInstance} 的开始与完成,创建与更新对应的 {@link BpmProcessInstanceExtDO} 记录 + * 监听 {@link ProcessInstance} 的状态变更,更新其对应的 status 状态 * * @author jason */ @@ -27,7 +26,6 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent private BpmProcessInstanceService processInstanceService; public static final Set PROCESS_INSTANCE_EVENTS = ImmutableSet.builder() - .add(FlowableEngineEventType.PROCESS_CREATED) .add(FlowableEngineEventType.PROCESS_CANCELLED) .add(FlowableEngineEventType.PROCESS_COMPLETED) .build(); @@ -36,11 +34,6 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent super(PROCESS_INSTANCE_EVENTS); } - @Override - protected void processCreated(FlowableEngineEntityEvent event) { - processInstanceService.createProcessInstanceExt((ProcessInstance)event.getEntity()); - } - @Override protected void processCancelled(FlowableCancelledEvent event) { processInstanceService.updateProcessInstanceExtCancel(event); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java index f2d5c9d0e..5f6d5f148 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -1,21 +1,23 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import jakarta.validation.Valid; import org.flowable.bpmn.model.BpmnModel; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; -import jakarta.validation.Valid; import java.util.List; import java.util.Map; import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * Flowable流程定义接口 * @@ -90,14 +92,16 @@ public interface BpmProcessDefinitionService { ProcessDefinition getProcessDefinition(String id); /** - * 获得编号对应的 ProcessDefinition + * 获得 ids 对应的 ProcessDefinition 数组 * - * 相比 {@link #getProcessDefinition(String)} 方法,category 的取值是正确 - * - * @param id 编号 - * @return 流程定义 + * @param ids 编号的数组 + * @return 流程定义的数组 */ - ProcessDefinition getProcessDefinition2(String id); + List getProcessDefinitionList(Set ids); + + default Map getProcessDefinitionMap(Set ids) { + return convertMap(getProcessDefinitionList(ids), ProcessDefinition::getId); + } /** * 获得 deploymentId 对应的 ProcessDefinition @@ -130,7 +134,7 @@ public interface BpmProcessDefinitionService { * @return 流程部署 Map */ default Map getDeploymentMap(Set ids) { - return CollectionUtils.convertMap(getDeployments(ids), Deployment::getId); + return convertMap(getDeployments(ids), Deployment::getId); } /** 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 82f15beec..ef8fd6e4d 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 @@ -66,8 +66,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } @Override - public ProcessDefinition getProcessDefinition2(String id) { - return repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult(); + public List getProcessDefinitionList(Set ids) { + return repositoryService.createProcessDefinitionQuery().processDefinitionIds(ids).list(); } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index 01a29c559..ca312df81 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -4,11 +4,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import jakarta.validation.Valid; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; -import jakarta.validation.Valid; import java.util.List; import java.util.Map; import java.util.Set; @@ -57,6 +57,32 @@ public interface BpmProcessInstanceService { ProcessInstance::getProcessInstanceId, ProcessInstance::getName); } + /** + * 获得历史的流程实例 + * + * @param id 流程实例的编号 + * @return 历史的流程实例 + */ + HistoricProcessInstance getHistoricProcessInstance(String id); + + /** + * 获得历史的流程实例列表 + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 + */ + List getHistoricProcessInstances(Set ids); + + /** + * 获得历史的流程实例 Map + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 Map + */ + default Map getHistoricProcessInstanceMap(Set ids) { + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); + } + /** * 获得流程实例的分页 * @@ -64,8 +90,8 @@ public interface BpmProcessInstanceService { * @param pageReqVO 分页请求 * @return 流程实例的分页 */ - PageResult getMyProcessInstancePage(Long userId, - @Valid BpmProcessInstanceMyPageReqVO pageReqVO); + PageResult getMyProcessInstancePage(Long userId, + @Valid BpmProcessInstanceMyPageReqVO pageReqVO); /** * 创建流程实例(提供给前端) @@ -101,39 +127,6 @@ public interface BpmProcessInstanceService { */ void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); - /** - * 获得历史的流程实例 - * - * @param id 流程实例的编号 - * @return 历史的流程实例 - */ - HistoricProcessInstance getHistoricProcessInstance(String id); - - /** - * 获得历史的流程实例列表 - * - * @param ids 流程实例的编号集合 - * @return 历史的流程实例列表 - */ - List getHistoricProcessInstances(Set ids); - - /** - * 获得历史的流程实例 Map - * - * @param ids 流程实例的编号集合 - * @return 历史的流程实例列表 Map - */ - default Map getHistoricProcessInstanceMap(Set ids) { - return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); - } - - /** - * 创建 ProcessInstance 拓展记录 - * - * @param instance 流程任务 - */ - void createProcessInstanceExt(ProcessInstance instance); - /** * 更新 ProcessInstance 拓展记录为取消 * 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 1a4b437e1..fa92e7e6e 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import jakarta.annotation.Resource; import jakarta.validation.Valid; import java.time.LocalDateTime; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables).setAssignee(assignee)); return instance.getId(); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } if (CollUtil.isNotEmpty(instance.getAssignee())) { return instance.getAssignee().get(taskDefinitionKey); } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 更新拓展表 runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file From d40fa0f929224e0eb2ac55236d651487cccf6318 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 17 Mar 2024 10:10:42 +0800 Subject: [PATCH 06/26] =?UTF-8?q?BPM=EF=BC=9A=E6=B5=81=E7=A8=8B=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=20`status`=20=E7=8A=B6=E6=80=81=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=EF=BC=8C=E4=BD=BF=E7=94=A8=20Flowable=20=E7=9A=84=20`?= =?UTF-8?q?variables`=20=E5=AD=98=E5=82=A8=EF=BC=8C=E7=A7=BB=E9=99=A4=20`b?= =?UTF-8?q?pm=5Ftask=5Fext`=20=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 6 +- .../task/BpmProcessInstanceResultEnum.java | 45 +-- .../task/BpmProcessInstanceStatusEnum.java | 6 +- .../enums/task/BpmTaskAddSignTypeEnum.java | 9 +- .../vo/task/BpmTaskDonePageItemRespVO.java | 5 +- .../task/vo/task/BpmTaskSubSignRespVO.java | 4 + .../bpm/convert/task/BpmTaskConvert.java | 43 +-- .../bpm/dal/dataobject/task/BpmTaskExtDO.java | 2 + .../bpm/dal/mysql/task/BpmTaskExtMapper.java | 40 +- .../flowable/core/enums/BpmConstants.java | 7 + .../core/listener/BpmTaskEventListener.java | 3 +- .../bpm/service/oa/BpmOALeaveServiceImpl.java | 2 +- .../task/BpmProcessInstanceService.java | 14 +- .../bpm/service/task/BpmTaskService.java | 11 - .../bpm/service/task/BpmTaskServiceImpl.java | 361 +++++++++--------- 15 files changed, 260 insertions(+), 298 deletions(-) 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 bdc3d17ce..e88e27b1f 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 @@ -55,12 +55,8 @@ public interface ErrorCodeConstants { ErrorCode TASK_ADD_SIGN_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); ErrorCode TASK_SUB_SIGN_NO_PARENT = new ErrorCode(1_009_005_011, "任务减签失败,被减签的任务必须是通过加签生成的任务"); - // ========== 流程任务分配规则 1-009-006-000 ========== - ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1_009_006_000, "流程({}) 的任务({}) 已经存在分配规则"); - ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1_009_006_001, "流程任务分配规则不存在"); - ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1_009_006_002, "只有流程模型的任务分配规则,才允许被修改"); + // ========== 流程任务分配规则 1-009-006-000 TODO 芋艿:这里要改下 ========== ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); - ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1_009_006_004, "操作失败,原因:任务分配脚本({}) 不存在"); // ========== 动态表单模块 1-009-010-000 ========== ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java index 615416c73..bd4f361d5 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java @@ -4,9 +4,6 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import lombok.AllArgsConstructor; import lombok.Getter; -import java.util.Arrays; -import java.util.List; - /** * 流程实例的结果 * @@ -16,38 +13,34 @@ import java.util.List; @AllArgsConstructor public enum BpmProcessInstanceResultEnum { - PROCESS(1, "处理中"), - APPROVE(2, "通过"), - REJECT(3, "不通过"), + RUNNING(1, "审批中"), + APPROVE(2, "审批通过"), + REJECT(3, "审批不通过"), CANCEL(4, "已取消"), // ========== 流程任务独有的状态 ========== - BACK(5, "驳回"), // 退回 - DELEGATE(6, "委派"), + BACK(5, "已驳回"), // 退回 + DELEGATE(6, "委派中"), + /** * 【加签】源任务已经审批完成,但是它使用了后加签,后加签的任务未完成,源任务就会是这个状态 * 相当于是 通过 APPROVE 的特殊状态 - * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” + * 例如:A 审批,A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” */ - SIGN_AFTER(7, "待后加签任务完成"), + APPROVING(7, "审批通过中"), /** * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” * 相当于是 处理中 PROCESS 的特殊状态 - * 例如:A 审批, A 前加签了 B,B 还未审核 + * 例如:A 审批,A 前加签了 B,B 还未审核 */ - SIGN_BEFORE(8, "待前加签任务完成"), - /** - * 【加签】后加签任务被创建时的初始状态 - * 相当于是 处理中 PROCESS 的特殊状态 - * 因为需要源任务先完成,才能到后加签的人来审批,所以加了一个状态区分 - */ - WAIT_BEFORE_TASK(9, "待前置任务完成"); - - /** - * 能被减签的状态 - */ - public static final List CAN_SUB_SIGN_STATUS_LIST = Arrays.asList(PROCESS.result, WAIT_BEFORE_TASK.result); + WAIT(0, "待审批"); +// /** +// * 【加签】后加签任务被创建时的初始状态 +// * 相当于是 处理中 PROCESS 的特殊状态 +// * 因为需要源任务先完成,才能到后加签的人来审批,所以加了一个状态区分 +// */ +// WAIT_BEFORE_TASK(9, "处理中【待前置任务完成】"); /** * 结果 @@ -69,9 +62,9 @@ public enum BpmProcessInstanceResultEnum { * @return 是否 */ public static boolean isEndResult(Integer result) { - return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), - CANCEL.getResult(), BACK.getResult(), - SIGN_AFTER.getResult()); + return ObjectUtils.equalsAny(result, + APPROVE.getResult(), REJECT.getResult(), CANCEL.getResult(), + BACK.getResult(), APPROVING.getResult()); } } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java index 089690457..b8c05ad98 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java @@ -12,9 +12,9 @@ import lombok.Getter; @AllArgsConstructor public enum BpmProcessInstanceStatusEnum { - RUNNING(1, "进行中"), - APPROVE(2, "通过"), - REJECT(3, "不通过"), + RUNNING(1, "审批中"), + APPROVE(2, "审批通过"), + REJECT(3, "审批不通过"), CANCEL(4, "已取消"); /** diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java index 42c212e28..47e06bf6f 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java @@ -17,15 +17,11 @@ public enum BpmTaskAddSignTypeEnum { /** * 向后加签,需要后置任务全部审批完,才会通过原审批人节点 */ - AFTER("after", "向后加签"), - /** - * 创建后置加签时的过度状态,用于控制向后加签生成的任务状态 - */ - AFTER_CHILDREN_TASK("afterChildrenTask", "向后加签生成的子任务"); + AFTER("after", "向后加签"); private final String type; - private final String desc; + private final String desc; // TODO 芋艿:desc public static String formatDesc(String type) { for (BpmTaskAddSignTypeEnum value : values()) { @@ -37,4 +33,3 @@ public enum BpmTaskAddSignTypeEnum { } } - \ 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/task/vo/task/BpmTaskDonePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java index 8f5144158..c7fd78cac 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java @@ -18,8 +18,9 @@ public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO { @Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") private Long durationInMillis; - @Schema(description = "任务结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer result; + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 + @Schema(description = "审批建议", requiredMode = Schema.RequiredMode.REQUIRED, example = "不请假了!") private String reason; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java index efecbf582..c78d8a432 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java @@ -6,10 +6,14 @@ import lombok.Data; @Schema(description = "管理后台 - 减签流程任务的 Response VO") @Data public class BpmTaskSubSignRespVO { + @Schema(description = "审核的用户信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "小李") private BpmTaskRespVO.User assigneeUser; + @Schema(description = "任务 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12312") private String id; + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批") private String name; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 60ce84021..2f9421983 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.bpm.convert.task; -import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -8,7 +7,7 @@ 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.module.bpm.controller.admin.task.vo.task.*; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -19,7 +18,10 @@ import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; -import org.mapstruct.*; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.Date; @@ -62,12 +64,12 @@ public interface BpmTaskConvert { } default List convertList2(List tasks, - Map bpmTaskExtDOMap, Map historicProcessInstanceMap, + Map historicProcessInstanceMap, Map userMap) { return CollectionUtils.convertList(tasks, task -> { BpmTaskDonePageItemRespVO respVO = convert2(task); - BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); - copyTo(taskExtDO, respVO); + respVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + // 流程实例 HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId()); if (processInstance != null) { AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); @@ -89,12 +91,12 @@ public interface BpmTaskConvert { BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); default List convertList3(List tasks, - Map bpmTaskExtDOMap, HistoricProcessInstance processInstance, + HistoricProcessInstance processInstance, Map userMap, Map deptMap) { return CollectionUtils.convertList(tasks, task -> { BpmTaskRespVO respVO = convert3(task); - BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); - copyTo(taskExtDO, respVO); + respVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + // 流程实例 if (processInstance != null) { AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); respVO.setProcessInstance(convert(processInstance, startUser)); @@ -116,9 +118,6 @@ public interface BpmTaskConvert { BpmTaskRespVO.User convert3(AdminUserRespDTO bean); - @Mapping(target = "id", ignore = true) - void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to); - @Mappings({@Mapping(source = "processInstance.id", target = "id"), @Mapping(source = "processInstance.name", target = "name"), @Mapping(source = "processInstance.startUserId", target = "startUserId"), @@ -127,14 +126,6 @@ public interface BpmTaskConvert { BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser); - default BpmTaskExtDO convert2TaskExt(Task task) { - BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId()) - .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName()) - .setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId()); - taskExtDO.setCreateTime(LocalDateTimeUtil.of(task.getCreateTime())); - return taskExtDO; - } - default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) { BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); @@ -161,6 +152,7 @@ public interface BpmTaskConvert { task.setParentTaskId(parentTask.getId()); task.setProcessDefinitionId(parentTask.getProcessDefinitionId()); task.setProcessInstanceId(parentTask.getProcessInstanceId()); +// task.setExecutionId(parentTask.getExecutionId()); // TODO 芋艿:新加的,不太确定;尴尬,不加时,子任务不通过会失败(报错);加了,子任务审批通过会失败(报错) task.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); task.setTaskDefinitionId(parentTask.getTaskDefinitionId()); task.setPriority(parentTask.getPriority()); @@ -168,15 +160,14 @@ public interface BpmTaskConvert { return task; } - default List convertList(List bpmTaskExtDOList, - Map userMap, - Map idTaskMap){ + default List convertList(List bpmTaskExtDOList, + Map userMap){ return CollectionUtils.convertList(bpmTaskExtDOList, task -> { BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO() - .setId(task.getTaskId()).setName(task.getName()); + .setId(task.getId()).setName(task.getName()); // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner - Task sourceTask = idTaskMap.get(task.getTaskId()); - String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee()); +// Task sourceTask = idTaskMap.get(task.getTaskId()); + String assignee = ObjectUtil.defaultIfBlank(task.getOwner(), task.getAssignee()); MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee), assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser))); return bpmTaskSubSignRespVO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java index a79fce412..7ebe25e01 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java @@ -20,6 +20,7 @@ import java.time.LocalDateTime; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) +@Deprecated public class BpmTaskExtDO extends BaseDO { /** @@ -61,6 +62,7 @@ public class BpmTaskExtDO extends BaseDO { /** * 审批建议 */ + @Deprecated private String reason; /** * 任务的结束时间 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java index 8108e613d..0d91545c2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java @@ -1,39 +1,33 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.task; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; -import java.util.Collection; -import java.util.List; - @Mapper public interface BpmTaskExtMapper extends BaseMapperX { - default void updateByTaskId(BpmTaskExtDO entity) { - update(entity, new LambdaQueryWrapper().eq(BpmTaskExtDO::getTaskId, entity.getTaskId())); - } +// default void updateByTaskId(BpmTaskExtDO entity) { +// update(entity, new LambdaQueryWrapper().eq(BpmTaskExtDO::getTaskId, entity.getTaskId())); +// } - default List selectListByTaskIds(Collection taskIds) { - return selectList(BpmTaskExtDO::getTaskId, taskIds); - } +// default List selectListByTaskIds(Collection taskIds) { +// return selectList(BpmTaskExtDO::getTaskId, taskIds); +// } // TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务 - default List selectProcessListByTaskIds(Collection taskIds) { - return selectList(new LambdaQueryWrapperX() - .in(BpmTaskExtDO::getTaskId, taskIds) - .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST)); - } +// default List selectProcessListByTaskIds(Collection taskIds) { +// return selectList(new LambdaQueryWrapperX() +// .in(BpmTaskExtDO::getTaskId, taskIds) +// .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST)); +// } - default BpmTaskExtDO selectByTaskId(String taskId) { - return selectOne(BpmTaskExtDO::getTaskId, taskId); - } +// default BpmTaskExtDO selectByTaskId(String taskId) { +// return selectOne(BpmTaskExtDO::getTaskId, taskId); +// } - default void updateBatchByTaskIdList(List taskIdList, BpmTaskExtDO updateObj) { - update(updateObj, new LambdaQueryWrapper().in(BpmTaskExtDO::getTaskId, taskIdList)); - } +// default void updateBatchByTaskIdList(List taskIdList, BpmTaskExtDO updateObj) { +// update(updateObj, new LambdaQueryWrapper().in(BpmTaskExtDO::getTaskId, taskIdList)); +// } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java index b2bd419e6..7649b0fbc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java @@ -16,4 +16,11 @@ public class BpmConstants { */ public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS"; + /** + * 任务的变量 - 状态 + * + * @see org.flowable.task.api.Task#getTaskLocalVariables() + */ + public static final String TASK_VARIABLE_STATUS = "TASK_STATUS"; + } 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 08638a9d3..7a647c205 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 @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import com.google.common.collect.ImmutableSet; @@ -21,7 +20,7 @@ import java.util.List; import java.util.Set; /** - * 监听 {@link org.flowable.task.api.Task} 的开始与完成,创建与更新对应的 {@link BpmTaskExtDO} 记录 + * 监听 {@link org.flowable.task.api.Task} 的开始与完成 * * @author jason */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java index 76fe21669..3c786d805 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -48,7 +48,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { // 插入 OA 请假单 long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays(); BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day) - .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + .setResult(BpmProcessInstanceResultEnum.RUNNING.getResult()); leaveMapper.insert(leave); // 发起 BPM 流程 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index ca312df81..bb94dd2e2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import jakarta.validation.Valid; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; @@ -13,6 +15,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * 流程实例 Service 接口 * @@ -43,7 +47,7 @@ public interface BpmProcessInstanceService { * @return 流程实例列表 Map */ default Map getProcessInstanceMap(Set ids) { - return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); + return convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); } /** @@ -53,7 +57,7 @@ public interface BpmProcessInstanceService { * @return 对应的映射关系 */ default Map getProcessInstanceNameMap(Set ids) { - return CollectionUtils.convertMap(getProcessInstances(ids), + return convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId, ProcessInstance::getName); } @@ -80,7 +84,7 @@ public interface BpmProcessInstanceService { * @return 历史的流程实例列表 Map */ default Map getHistoricProcessInstanceMap(Set ids) { - return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); + return convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); } /** 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 97018451d..08a07bdb5 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 @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import jakarta.validation.Valid; import org.flowable.task.api.Task; @@ -64,15 +63,6 @@ public interface BpmTaskService { */ List getTaskListByProcessInstanceId(String processInstanceId); - - /** - * 通过任务 ID 集合,获取任务扩展表信息集合 - * - * @param taskIdList 任务 ID 集合 - * @return 任务列表 - */ - List getTaskListByTaskIdList(List taskIdList); - /** * 通过任务 * @@ -151,7 +141,6 @@ public interface BpmTaskService { */ void returnTask(Long userId, BpmTaskReturnReqVO reqVO); - /** * 将指定任务委派给其他人处理,等接收人处理后再回到原审批人手中审批 * 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 6e9929d37..199662519 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 @@ -13,12 +13,11 @@ import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 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.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -39,7 +38,6 @@ import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.DelegationState; import org.flowable.task.api.Task; -import org.flowable.task.api.TaskInfo; import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; @@ -51,7 +49,6 @@ import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; -import java.time.LocalDateTime; import java.util.*; import java.util.stream.Stream; @@ -115,8 +112,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 获得 ProcessInstance Map - Map processInstanceMap = - processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId)); + Map processInstanceMap = processInstanceService.getProcessInstanceMap( + convertSet(tasks, Task::getProcessInstanceId)); // 获得 User Map Map userMap = adminUserApi.getUserMap( convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); @@ -129,11 +126,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { public PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { // 查询已办任务 HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 + .includeTaskLocalVariables() .taskAssignee(String.valueOf(userId)) // 分配给自己 .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } + // TODO @芋艿:传参风格,统一 if (pageVO.getBeginCreateTime() != null) { taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime())); } @@ -146,20 +145,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { return PageResult.empty(taskQuery.count()); } - // 获得 TaskExtDO Map - List bpmTaskExtDOs = - taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); - Map bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); // 获得 ProcessInstance Map - Map historicProcessInstanceMap = - processInstanceService.getHistoricProcessInstanceMap( - convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); + Map historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); // 获得 User Map Map userMap = adminUserApi.getUserMap( convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); // 拼接结果 return new PageResult<>( - BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap), + BpmTaskConvert.INSTANCE.convertList2(tasks, historicProcessInstanceMap, userMap), taskQuery.count()); } @@ -175,6 +169,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { public List getTaskListByProcessInstanceId(String processInstanceId) { // 获得任务列表 List tasks = historyService.createHistoricTaskInstanceQuery() + .includeTaskLocalVariables() .processInstanceId(processInstanceId) .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序 .list(); @@ -182,9 +177,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { return Collections.emptyList(); } - // 获得 TaskExtDO Map - List bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); - Map bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); // 获得 ProcessInstance Map HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); // 获得 User Map @@ -195,15 +187,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 拼接数据 - List result = BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap); + List result = BpmTaskConvert.INSTANCE.convertList3(tasks, processInstance, userMap, deptMap); return BpmTaskConvert.INSTANCE.convertChildrenList(result); } - @Override - public List getTaskListByTaskIdList(List taskIdList) { - return taskExtMapper.selectListByTaskIds(taskIdList); - } - @Override @Transactional(rollbackFor = Exception.class) public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { @@ -230,16 +217,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 情况三:自己审批的任务,调用 complete 去完成任务 // 完成任务,审批通过 + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult()); taskService.complete(task.getId(), instance.getProcessVariables()); - // 更新任务拓展表为通过 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) - .setReason(reqVO.getReason())); +// // 更新任务拓展表为通过 +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) +// .setReason(reqVO.getReason())); // 处理加签任务 - handleParentTask(task); +// handleParentTask(task); + handleParentTaskNew(task.getParentTaskId()); } - /** * 审批通过存在“后加签”的任务。 *

@@ -250,133 +238,59 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult()) - .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult()) +// .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); + // TODO @芋艿:reqVO.reason??? + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVING.getResult()); // 2. 激活子任务 List childrenTaskIdList = getChildrenTaskIdList(task.getId()); for (String childrenTaskId : childrenTaskIdList) { taskService.resolveTask(childrenTaskId); + // 更新任务扩展表中子任务为进行中 + updateTaskStatus(childrenTaskId, BpmProcessInstanceResultEnum.RUNNING.getResult()); } // 2.1 更新任务扩展表中子任务为进行中 - taskExtMapper.updateBatchByTaskIdList(childrenTaskIdList, - new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); +// taskExtMapper.updateBatchByTaskIdList(childrenTaskIdList, +// new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); } - /** - * 处理当前任务的父任务,主要处理“加签”的情况 - * - * @param task 当前任务 - */ - private void handleParentTask(Task task) { - String parentTaskId = task.getParentTaskId(); + // TODO 芋艿:名字 + private void handleParentTaskNew(String parentTaskId) { if (StrUtil.isBlank(parentTaskId)) { return; } - // 1. 判断当前任务的父任务是否还有子任务 + // 1.1 判断是否还有子任务。如果没有,就不处理 Long childrenTaskCount = getChildrenTaskCount(parentTaskId); if (childrenTaskCount > 0) { return; } - // 2. 获取父任务 + // 1.2 只处理加签的父任务 Task parentTask = validateTaskExist(parentTaskId); - - // 3. 处理加签情况 String scopeType = parentTask.getScopeType(); - if(!validateSignType(scopeType)){ + if (!validateSignType(scopeType)){ return; } - // 3.1 情况一:处理向前加签 - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { - // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批 - taskService.resolveTask(parentTaskId); - // 3.1.2 更新任务拓展表为处理中 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); - } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { - // 3.2 情况二:处理向后加签 - handleParentTaskForAfterSign(parentTask); - } - // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 - // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently - // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的 - parentTask = getTask(parentTaskId); - if (parentTask == null) { - // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据 - return; - } + // 2. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 clearTaskScopeTypeAndSave(parentTask); - } - - /** - * 处理后加签任务 - * - * @param parentTask 当前审批任务的父任务 - */ - // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下; - private void handleParentTaskForAfterSign(Task parentTask) { - String parentTaskId = parentTask.getId(); - // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己 - BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); - BpmTaskExtDO currentTaskExtUpdateObj = new BpmTaskExtDO().setTaskId(parentTask.getId()) - .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); - if (currentTaskExt.getEndTime() == null) { - // 1.1 有这个判断是因为,以前没设置过结束时间,才去设置 - currentTaskExtUpdateObj.setEndTime(LocalDateTime.now()); - } - taskExtMapper.updateByTaskId(currentTaskExtUpdateObj); - // 1.2 完成自己(因为它已经没有子任务,所以也可以完成) - taskService.complete(parentTaskId); - - // 2. 如果有父级,递归查询上级任务是否都已经完成 - if (StrUtil.isEmpty(parentTask.getParentTaskId())) { - return; - } - // 2.1 判断整条链路的任务是否完成 - // 例如从 A 任务加签了一个 B 任务,B 任务又加签了一个 C 任务,C 任务加签了 D 任务 - // 此时,D 任务完成,要一直往上找到祖先任务 A调用 complete 方法完成 A 任务 - boolean allChildrenTaskFinish = true; - while (StrUtil.isNotBlank(parentTask.getParentTaskId())) { - parentTask = validateTaskExist(parentTask.getParentTaskId()); - BpmTaskExtDO parentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); - if (parentTaskExt == null) { - break; - } - boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(parentTaskExt.getResult()); - // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false,则不会再赋值为 true,因为整个链路没有完成 - if (allChildrenTaskFinish) { - allChildrenTaskFinish = currentTaskFinish; - } - // 2.3 任务已完成则不处理 - if (currentTaskFinish) { - continue; - } - - // 3 处理非完成状态的任务 - // 3.1 判断当前任务的父任务是否还有子任务 - Long childrenTaskCount = getChildrenTaskCount(parentTaskExt.getTaskId()); - if (childrenTaskCount > 0) { - continue; - } - // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成 - if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) { - // 3.3 需要修改该任务状态为处理中 - taskService.resolveTask(parentTaskExt.getTaskId()); - parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); - taskExtMapper.updateByTaskId(parentTaskExt); - } - // 3.4 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签 - parentTask = validateTaskExist(parentTaskExt.getTaskId()); - clearTaskScopeTypeAndSave(parentTask); + // 3.1 情况一:处理向【向前】加签 + if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { + // 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批 + taskService.resolveTask(parentTaskId); + // 3.1.2 更新流程任务 status + updateTaskStatus(parentTaskId, BpmProcessInstanceResultEnum.RUNNING.getResult()); + // 3.2 情况二:处理向【向后】加签 + } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { + // 3.2.1 完成自己(因为它已经没有子任务,所以也可以完成) + updateTaskStatus(parentTaskId, BpmProcessInstanceResultEnum.APPROVE.getResult()); + taskService.complete(parentTaskId); } - // 4. 完成最后的顶级祖先任务 - if (allChildrenTaskFinish) { - taskService.complete(parentTask.getId()); - } + // 4. 递归处理父任务 + handleParentTaskNew(parentTask.getParentTaskId()); } /** @@ -422,9 +336,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee taskService.resolveTask(task.getId()); // 2.2 更新任务拓展表为【处理中】 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()) - .setReason(reqVO.getReason())); +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.RUNNING.getResult()) +// .setReason(reqVO.getReason())); + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.RUNNING.getResult()); } @Override @@ -438,12 +353,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 更新流程实例为不通过 + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason()); - // 更新任务拓展表为不通过 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult()) - .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); +// // 更新任务拓展表为不通过 +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult()) +// .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); } @Override @@ -459,6 +375,20 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.setAssignee(id, String.valueOf(userId)); } + /** + * 更新流程任务的 status 状态 + * + * @param id 任务编号 + * @param status 状态 + */ + private void updateTaskStatus(String id, Integer status) { +// try { +// } catch (FlowableObjectNotFoundException exception) { +// historyService. +// } + taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status); + } + /** * 校验任务是否存在, 并且是否是分配给自己的任务 * @@ -475,25 +405,56 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public void createTaskExt(Task task) { - BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) - .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); +// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) +// .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); +// // 向后加签生成的任务,状态不能为进行中,需要等前面父任务完成 +// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { +// taskExtDO.setResult(BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult()); +// } +// taskExtMapper.insert(taskExtDO); +// Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); +// if (status != null) { +// return; +// } +// +// status = BpmProcessInstanceResultEnum.RUNNING.getResult(); // 向后加签生成的任务,状态不能为进行中,需要等前面父任务完成 - if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { - taskExtDO.setResult(BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult()); - } - taskExtMapper.insert(taskExtDO); +// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { +// status = BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult(); +// } + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.RUNNING.getResult()); } @Override public void updateTaskExtComplete(Task task) { - BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) - .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置 - .setEndTime(LocalDateTime.now()); - taskExtMapper.updateByTaskId(taskExtDO); +// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) +// .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置 +// .setEndTime(LocalDateTime.now()); +// taskExtMapper.updateByTaskId(taskExtDO); + + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult()); } @Override public void updateTaskExtCancel(String taskId) { + Task task = getTask(taskId); + // 可能只是活动,不是任务,所以查询不到 + if (task == null) { + log.error("[updateTaskExtCancel][taskId({}) 任务不存在]", taskId); + return; + } + + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (BpmProcessInstanceResultEnum.isEndResult(status)) { + log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); + return; + } + updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult()); + + if (true) { + return; + } + // 需要在事务提交后,才进行查询。不然查询不到历史的原因 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @@ -505,21 +466,27 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } - // 如果任务拓展表已经是完成的状态,则跳过 - BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId); - if (taskExt == null) { - log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录,可能存在问题]", taskId); - return; - } - // 如果已经是最终的结果,则跳过 - if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) { - log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, taskExt.getResult()); +// // 如果任务拓展表已经是完成的状态,则跳过 +// BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId); +// if (taskExt == null) { +// log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录,可能存在问题]", taskId); +// return; +// } +// // 如果已经是最终的结果,则跳过 +// if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) { +// log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, taskExt.getResult()); +// return; +// } + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (BpmProcessInstanceResultEnum.isEndResult(status)) { + log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } // 更新任务 - taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) - .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason()))); +// taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) +// .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason()))); + updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult()); } }); @@ -527,9 +494,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public void updateTaskExtAssign(Task task) { - BpmTaskExtDO taskExtDO = - new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId()); - taskExtMapper.updateByTaskId(taskExtDO); +// BpmTaskExtDO taskExtDO = +// new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId()); +// taskExtMapper.updateByTaskId(taskExtDO); + // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override @@ -555,11 +523,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public Task getTask(String id) { - return taskService.createTaskQuery().taskId(id).singleResult(); + return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult(); } private HistoricTaskInstance getHistoricTask(String id) { - return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult(); + return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult(); } @Override @@ -594,13 +562,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 1.2 校验源头和目标节点的关系,并返回目标元素 FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetDefinitionKey(), task.getProcessDefinitionId()); + // 3. 更新任务扩展表 TODO 芋艿:需要提前搞 + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); + // 2. 调用 flowable 框架的回退逻辑 returnTask0(task, targetElement, reqVO); // 3. 更新任务扩展表 - taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId()) - .setResult(BpmProcessInstanceResultEnum.BACK.getResult()) - .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); +// updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); +// taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId()) +// .setResult(BpmProcessInstanceResultEnum.BACK.getResult()) +// .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); } /** @@ -654,6 +626,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { } taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.BACK.getType().toString(), reqVO.getReason()); + + // TODO 芋艿:这里加下驳回的 + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); }); // 3. 执行驳回 @@ -688,9 +663,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3.2 执行委派,将任务委派给 receiveId taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString()); // 3.3 更新任务拓展表为【委派】 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult()) - .setReason(reqVO.getReason())); +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult()) +// .setReason(reqVO.getReason())); + updateTaskStatus(taskId, BpmProcessInstanceResultEnum.DELEGATE.getResult()); } /** @@ -729,15 +705,20 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskEntity.setOwner(taskEntity.getAssignee()); taskEntity.setAssignee(null); // 2.3 更新扩展表状态 - taskExtMapper.updateByTaskId( - new BpmTaskExtDO().setTaskId(taskEntity.getId()) - .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()) - .setReason(reqVO.getReason())); +// taskExtMapper.updateByTaskId( +// new BpmTaskExtDO().setTaskId(taskEntity.getId()) +// .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()) +// .setReason(reqVO.getReason())); +// taskEntity.setTransientVariableLocal(BpmConstants.TASK_VARIABLE_STATUS, BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()); +// updateTaskStatus(taskEntity.getId(), BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()); // TODO 芋艿:貌似会有实物并发的问题;所以不能用这个调用,只能 set } // 2.4 记录加签方式,完成任务时需要用到判断 taskEntity.setScopeType(reqVO.getType()); // 2.5 保存当前任务修改后的值 taskService.saveTask(taskEntity); + if (reqVO.getType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) { + updateTaskStatus(taskEntity.getId(), BpmProcessInstanceResultEnum.WAIT.getResult()); // TODO 芋艿:貌似只能放在这个地方,不然会有并发修改的报错 + } // 3. 创建加签任务 createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); @@ -764,12 +745,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { private TaskEntityImpl validateAddSign(Long userId, BpmTaskAddSignReqVO reqVO) { TaskEntityImpl taskEntity = (TaskEntityImpl) validateTask(userId, reqVO.getId()); // 向前加签和向后加签不能同时存在 - if (StrUtil.isNotBlank(taskEntity.getScopeType()) - && ObjectUtil.notEqual(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType(), taskEntity.getScopeType()) + if (taskEntity.getScopeType() != null && ObjectUtil.notEqual(taskEntity.getScopeType(), reqVO.getType())) { throw exception(TASK_ADD_SIGN_TYPE_ERROR, BpmTaskAddSignTypeEnum.formatDesc(taskEntity.getScopeType()), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType())); } + // 同一个 key 的任务,审批人不重复 List taskList = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()) .taskDefinitionKey(taskEntity.getTaskDefinitionKey()).list(); @@ -819,17 +800,23 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 task.setOwner(assignee); // 2.2.2 设置向后加签任务的 scopeType 为 afterChildrenTask,用于设置任务扩展表的状态 - task.setScopeType(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType()); +// task.setScopeType(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType()); +// task.setVariableLocal(BpmConstants.TASK_VARIABLE_STATUS, BpmProcessInstanceResultEnum.WAIT.getResult()); } // 2. 保存子任务 taskService.saveTask(task); + // 3. TODO + if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { + updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.WAIT.getResult()); + } } @Override @Transactional(rollbackFor = Exception.class) public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { // 1.1 校验 task 可以被减签 - Task task = validateSubSign(reqVO.getId()); +// Task task = validateSubSign(reqVO.getId()); // TODO 芋艿:这个判断,暂时有点问题!在前置加签的时候 + Task task = validateTaskExist(reqVO.getId()); // 1.2 校验取消人存在 AdminUserRespDTO cancelUser = null; if (StrUtil.isNotBlank(task.getAssignee())) { @@ -846,17 +833,18 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.2 删除任务和所有子任务 taskService.deleteTasks(allTaskIdList); // 2.3 修改扩展表状态为取消 - AdminUserRespDTO user = adminUserApi.getUser(userId); - taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) - .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); +// taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) +// .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); +// allTaskIdList.forEach(taskId -> updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult())); // TODO @芋艿:交给取消;考虑到理由,可能不能直接给; // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 + AdminUserRespDTO user = adminUserApi.getUser(userId); String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname()); taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); // 4. 处理当前任务的父任务 - handleParentTask(task); + handleParentTaskNew(task.getParentTaskId()); } /** @@ -954,17 +942,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isEmpty(taskList)) { return Collections.emptyList(); } - List childrenTaskIdList = convertList(taskList, Task::getId); // 2.1 将 owner 和 assignee 统一到一个集合中 List userIds = convertListByFlatMap(taskList, control -> Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner())) - .filter(Objects::nonNull)); + .filter(Objects::nonNull)); // TODO 芋艿:这里可能可以优化下 // 2.2 组装数据 Map userMap = adminUserApi.getUserMap(userIds); - List taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); - Map idTaskMap = convertMap(taskList, TaskInfo::getId); - return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap); +// List taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); +// Map idTaskMap = convertMap(taskList, TaskInfo::getId); + return BpmTaskConvert.INSTANCE.convertList(taskList, userMap); } @Override From 3fce482716d475d9161c071e90ba6607135654f2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 17 Mar 2024 17:24:40 +0800 Subject: [PATCH 07/26] =?UTF-8?q?BPM=EF=BC=9A=E7=AE=80=E5=8C=96=20task=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=20VO=EF=BC=8C=E5=81=9A=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E5=90=88=E5=B9=B6=E3=80=82=E8=99=BD=E7=84=B6=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=B8=8A=E6=9C=89=E5=86=97=E4=BD=99=EF=BC=8C=E4=BD=86?= =?UTF-8?q?=E6=98=AF=E8=AF=BB=E4=BB=A3=E7=A0=81=E9=9A=BE=E5=BA=A6=E9=99=8D?= =?UTF-8?q?=E4=BD=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceStatusOldEnum.java | 28 ---- .../admin/task/BpmTaskController.java | 142 ++++++++++++++++-- .../vo/task/BpmTaskDonePageItemRespVO.java | 27 ---- .../task/vo/task/BpmTaskDonePageReqVO.java | 31 ---- ...doPageReqVO.java => BpmTaskPageReqVO.java} | 6 +- .../admin/task/vo/task/BpmTaskRespVO.java | 79 +++++++--- .../task/vo/task/BpmTaskReturnReqVO.java | 2 +- .../task/vo/task/BpmTaskSimpleRespVO.java | 16 -- .../task/vo/task/BpmTaskSubSignRespVO.java | 19 --- .../vo/task/BpmTaskTodoPageItemRespVO.java | 53 ------- .../bpm/convert/task/BpmTaskConvert.java | 139 ----------------- .../bpm/dal/dataobject/task/BpmTaskExtDO.java | 87 ----------- .../bpm/dal/mysql/task/BpmTaskExtMapper.java | 33 ---- .../bpm/service/task/BpmTaskService.java | 24 +-- .../bpm/service/task/BpmTaskServiceImpl.java | 133 ++++------------ 15 files changed, 231 insertions(+), 588 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/{BpmTaskTodoPageReqVO.java => BpmTaskPageReqVO.java} (74%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSimpleRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java deleted file mode 100644 index 1db19cf64..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.task; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 流程实例的状态 - * - * @author 芋道源码 - */ -@Deprecated -@Getter -@AllArgsConstructor -public enum BpmProcessInstanceStatusOldEnum { - - RUNNING(1, "进行中"), - FINISH(2, "已完成"); - - /** - * 状态 - */ - private final Integer status; - /** - * 描述 - */ - private final String desc; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index ba14b61f1..78429ea21 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -1,21 +1,43 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +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; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 流程任务实例") @@ -26,28 +48,103 @@ public class BpmTaskController { @Resource private BpmTaskService taskService; + @Resource + private BpmProcessInstanceService processInstanceService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; @GetMapping("todo-page") @Operation(summary = "获取 Todo 待办任务分页") @PreAuthorize("@ss.hasPermission('bpm:task:query')") - public CommonResult> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) { - return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO)); + public CommonResult> getTodoTaskPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTodoTaskPage(getLoginUserId(), pageVO); + // 拼接数据 + Map processInstanceMap = processInstanceService.getProcessInstanceMap( + convertSet(pageResult.getList(), Task::getProcessInstanceId)); + Map userMap = adminUserApi.getUserMap( + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { + ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance == null) { + return; + } + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + })); } @GetMapping("done-page") @Operation(summary = "获取 Done 已办任务分页") @PreAuthorize("@ss.hasPermission('bpm:task:query')") - public CommonResult> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) { - return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO)); + public CommonResult> getDoneTaskPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getDoneTaskPage(getLoginUserId(), pageVO); + // 拼接数据 + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); + Map userMap = adminUserApi.getUserMap( + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { + HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance == null) { + return; + } + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + })); } + // TODO @芋艿:怎么优化下 @GetMapping("/list-by-process-instance-id") @Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的") @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) @PreAuthorize("@ss.hasPermission('bpm:task:query')") public CommonResult> getTaskListByProcessInstanceId( @RequestParam("processInstanceId") String processInstanceId) { - return success(taskService.getTaskListByProcessInstanceId(processInstanceId)); + List taskList = taskService.getTaskListByProcessInstanceId(processInstanceId); + if (CollUtil.isEmpty(taskList)) { + return success(Collections.emptyList()); + } + + // 拼接数据 + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); + // 获得 User 和 Dept Map + Set userIds = convertSet(taskList, task -> NumberUtils.parseLong(task.getAssignee())); + userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + List taskVOList = CollectionUtils.convertList(taskList, task -> { + BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); + taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + // 流程实例 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + // 用户信息 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); + if (dept != null) { + taskVO.getAssigneeUser().setDeptName(dept.getName()); + } + } + return taskVO; + }); + + // 拼接父子关系 + Map> childrenTaskMap = convertMultiMap( + filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())), + BpmTaskRespVO::getParentTaskId); + for (BpmTaskRespVO taskVO : taskVOList) { + taskVO.setChildren(childrenTaskMap.get(taskVO.getId())); + } + return success(filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId()))); } @PutMapping("/approve") @@ -74,12 +171,14 @@ public class BpmTaskController { return success(true); } - @GetMapping("/return-list") + @GetMapping("/list-by-return") @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") @Parameter(name = "taskId", description = "当前任务ID", required = true) @PreAuthorize("@ss.hasPermission('bpm:task:update')") - public CommonResult> getReturnList(@RequestParam("taskId") String taskId) { - return success(taskService.getReturnTaskList(taskId)); + public CommonResult> getTaskListByReturn(@RequestParam("id") String id) { + List userTaskList = taskService.getUserTaskListByReturn(id); + return success(convertList(userTaskList, userTask -> // 只返回 id 和 name + new BpmTaskRespVO().setName(userTask.getName()).setTaskDefinitionKey(userTask.getId()))); } @PutMapping("/return") @@ -114,12 +213,23 @@ public class BpmTaskController { return success(true); } - @GetMapping("children-list") - @Operation(summary = "获取能被减签的任务") - @Parameter(name = "parentId", description = "父级任务 ID", required = true) - @PreAuthorize("@ss.hasPermission('bpm:task:update')") - public CommonResult> getChildrenTaskList(@RequestParam("parentId") String parentId) { - return success(taskService.getChildrenTaskList(parentId)); + // TODO 芋艿:待测试 + @GetMapping("list-by-parent-task-id") + @Operation(summary = "获得指定父级任务的子任务列表") // 目前用于,减签的时候,获得子任务列表 + @Parameter(name = "parentTaskId", description = "父级任务编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskListByParentTaskId(@RequestParam("parentTaskId") String parentTaskId) { + List taskList = taskService.getTaskListByParentTaskId(parentTaskId); + if (CollUtil.isEmpty(taskList)) { + return success(Collections.emptyList()); + } + // 拼接数据 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(taskList, user -> Stream.of(Long.valueOf(user.getAssignee()), Long.valueOf(user.getOwner())))); + return success(convertList(taskList, task -> BeanUtils.toBean(task, BpmTaskRespVO.class, taskVO -> { + taskVO.setAssigneeUser(BeanUtils.toBean(userMap.get(NumberUtils.parseLong(task.getAssignee())), BpmProcessInstanceRespVO.User.class)); + taskVO.setOwnerUser(BeanUtils.toBean(userMap.get(NumberUtils.parseLong(task.getOwner())), BpmProcessInstanceRespVO.User.class)); + }))); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java deleted file mode 100644 index c7fd78cac..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 流程任务的 Done 已完成的分页项 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO { - - @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime endTime; - @Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private Long durationInMillis; - - @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 - - @Schema(description = "审批建议", requiredMode = Schema.RequiredMode.REQUIRED, example = "不请假了!") - private String reason; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java deleted file mode 100644 index 52daea445..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 流程任务的 Done 已办的分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskDonePageReqVO extends PageParam { - - @Schema(description = "流程任务名", example = "芋道") - private String name; - - @Schema(description = "开始的创建收间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime beginCreateTime; - - @Schema(description = "结束的创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime endCreateTime; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java similarity index 74% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java index 605007ef5..fe115fdf0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java @@ -10,13 +10,11 @@ import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 流程任务的 TODO 待办的分页 Request VO") +@Schema(description = "管理后台 - 流程任务的的分页 Request VO") // 待办、已办,都使用该分页 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class BpmTaskTodoPageReqVO extends PageParam { +public class BpmTaskPageReqVO extends PageParam { @Schema(description = "流程任务名", example = "芋道") private String name; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 1af839e26..1e1bebf04 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -1,47 +1,84 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import java.time.LocalDateTime; import java.util.List; -@Schema(description = "管理后台 - 流程任务的 Response VO") +@Schema(description = "管理后台 - 流程任务 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO { +public class BpmTaskRespVO { - @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "user-001") - private String definitionKey; + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + @Schema(description = "任务名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Long durationInMillis; + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 + + /** + * 负责人的用户信息 + */ + private BpmProcessInstanceRespVO.User ownerUser; /** * 审核的用户信息 */ - private User assigneeUser; + private BpmProcessInstanceRespVO.User assigneeUser; + + // TODO @芋艿:这个 key 有点问题,应该是 taskDefinitionId + @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "user-001") + private String definitionKey; + @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one") + private String taskDefinitionKey; + + @Schema(description = "所属流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8888") + private String processInstanceId; /** - * 父任务ID + * 所属流程实例 */ + private ProcessInstance processInstance; + + @Schema(description = "父任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String parentTaskId; - @Schema(description = "子任务(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask") + @Schema(description = "子任务列表(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask") private List children; - @Schema(description = "用户信息") @Data - public static class User { + @Schema(description = "流程实例") + public static class ProcessInstance { - @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Long id; - @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - private String nickname; + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; - @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Long deptId; - @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") - private String deptName; + @Schema(description = "流程实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String processDefinitionId; + + /** + * 发起人的用户信息 + */ + private BpmProcessInstanceRespVO.User startUser; } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java index ca27ff6d5..a5c3edac2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskReturnReqVO.java @@ -15,7 +15,7 @@ public class BpmTaskReturnReqVO { @Schema(description = "回退到的任务 Key", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotEmpty(message = "回退到的任务 Key 不能为空") - private String targetDefinitionKey; + private String targetTaskDefinitionKey; @Schema(description = "回退意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "我就是想驳回") @NotEmpty(message = "回退意见不能为空") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSimpleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSimpleRespVO.java deleted file mode 100644 index b98a25a22..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSimpleRespVO.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - 流程任务的精简 Response VO") -@Data -public class BpmTaskSimpleRespVO { - - @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one") - private String definitionKey; - - @Schema(description = "任务名词", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批") - private String name; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java deleted file mode 100644 index c78d8a432..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignRespVO.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - 减签流程任务的 Response VO") -@Data -public class BpmTaskSubSignRespVO { - - @Schema(description = "审核的用户信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "小李") - private BpmTaskRespVO.User assigneeUser; - - @Schema(description = "任务 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12312") - private String id; - - @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批") - private String name; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java deleted file mode 100644 index 4b57f4777..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 流程任务的 Running 进行中的分页项 Response VO") -@Data -public class BpmTaskTodoPageItemRespVO { - - @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "任务名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - - @Schema(description = "接收时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime claimTime; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - @Schema(description = "激活状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer suspensionState; - - /** - * 所属流程实例 - */ - private ProcessInstance processInstance; - - @Data - @Schema(description = "流程实例") - public static class ProcessInstance { - - @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "流程实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - - @Schema(description = "发起人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long startUserId; - - @Schema(description = "发起人的用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - private String startUserNickname; - - @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") - private String processDefinitionId; - - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 2f9421983..dcc34f0de 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -1,35 +1,16 @@ package cn.iocoder.yudao.module.bpm.convert.task; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -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.module.bpm.controller.admin.task.vo.task.*; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.common.engine.impl.db.SuspensionState; -import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; -import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.Date; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; /** * Bpm 任务 Convert @@ -41,91 +22,6 @@ public interface BpmTaskConvert { BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); - default List convertList1(List tasks, - Map processInstanceMap, - Map userMap) { - return CollectionUtils.convertList(tasks, task -> { - BpmTaskTodoPageItemRespVO respVO = convert1(task); - ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId()); - if (processInstance != null) { - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - respVO.setProcessInstance(convert(processInstance, startUser)); - } - return respVO; - }); - } - - @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState") - BpmTaskTodoPageItemRespVO convert1(Task bean); - - @Named("convertSuspendedToSuspensionState") - default Integer convertSuspendedToSuspensionState(boolean suspended) { - return suspended ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode(); - } - - default List convertList2(List tasks, - Map historicProcessInstanceMap, - Map userMap) { - return CollectionUtils.convertList(tasks, task -> { - BpmTaskDonePageItemRespVO respVO = convert2(task); - respVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); - // 流程实例 - HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId()); - if (processInstance != null) { - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - respVO.setProcessInstance(convert(processInstance, startUser)); - } - return respVO; - }); - } - - BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean); - - @Mappings({ - @Mapping(source = "processInstance.id", target = "id"), - @Mapping(source = "processInstance.name", target = "name"), - @Mapping(source = "processInstance.startUserId", target = "startUserId"), - @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"), - @Mapping(source = "startUser.nickname", target = "startUserNickname") - }) - BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); - - default List convertList3(List tasks, - HistoricProcessInstance processInstance, - Map userMap, Map deptMap) { - return CollectionUtils.convertList(tasks, task -> { - BpmTaskRespVO respVO = convert3(task); - respVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); - // 流程实例 - if (processInstance != null) { - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - respVO.setProcessInstance(convert(processInstance, startUser)); - } - AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); - if (assignUser != null) { - respVO.setAssigneeUser(convert3(assignUser)); - DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); - if (dept != null) { - respVO.getAssigneeUser().setDeptName(dept.getName()); - } - } - return respVO; - }); - } - - @Mapping(source = "taskDefinitionKey", target = "definitionKey") - BpmTaskRespVO convert3(HistoricTaskInstance bean); - - BpmTaskRespVO.User convert3(AdminUserRespDTO bean); - - @Mappings({@Mapping(source = "processInstance.id", target = "id"), - @Mapping(source = "processInstance.name", target = "name"), - @Mapping(source = "processInstance.startUserId", target = "startUserId"), - @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"), - @Mapping(source = "startUser.nickname", target = "startUserNickname")}) - BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, - AdminUserRespDTO startUser); - default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) { BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); @@ -136,12 +32,6 @@ public interface BpmTaskConvert { return reqDTO; } - default List convertList(List elementList) { - return CollectionUtils.convertList(elementList, element -> new BpmTaskSimpleRespVO() - .setName(element.getName()) - .setDefinitionKey(element.getId())); - } - //此处不用 mapstruct 映射,因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的 //使用 mapstruct 会将里面嵌套的各个属性值都设置进去,会出现意想不到的问题 default TaskEntityImpl convert(TaskEntityImpl task,TaskEntityImpl parentTask){ @@ -160,33 +50,4 @@ public interface BpmTaskConvert { return task; } - default List convertList(List bpmTaskExtDOList, - Map userMap){ - return CollectionUtils.convertList(bpmTaskExtDOList, task -> { - BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO() - .setId(task.getId()).setName(task.getName()); - // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner -// Task sourceTask = idTaskMap.get(task.getTaskId()); - String assignee = ObjectUtil.defaultIfBlank(task.getOwner(), task.getAssignee()); - MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee), - assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser))); - return bpmTaskSubSignRespVO; - }); - } - - /** - * 转换任务为父子级 - * - * @param sourceList 原始数据 - * @return 转换后的父子级数组 - */ - default List convertChildrenList(List sourceList) { - List childrenTaskList = filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId())); - Map> parentChildrenTaskListMap = convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId); - for (BpmTaskRespVO bpmTaskRespVO : sourceList) { - bpmTaskRespVO.setChildren(parentChildrenTaskListMap.get(bpmTaskRespVO.getId())); - } - return filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId())); - } - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java deleted file mode 100644 index 7ebe25e01..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java +++ /dev/null @@ -1,87 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.dataobject.task; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; - -/** - * Bpm 流程任务的拓展表 - * 主要解决 Flowable Task 和 HistoricTaskInstance 不支持拓展字段,所以新建拓展表 - * - * @author 芋道源码 - */ -@TableName(value = "bpm_task_ext", autoResultMap = true) -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Deprecated -public class BpmTaskExtDO extends BaseDO { - - /** - * 编号,自增 - */ - @TableId - private Long id; - - /** - * 任务的审批人 - * - * 冗余 Task 的 assignee 属性 - */ - private Long assigneeUserId; - /** - * 任务的名字 - * - * 冗余 Task 的 name 属性,为了筛选 - */ - private String name; - /** - * 任务的编号 - * - * 关联 Task 的 id 属性 - */ - private String taskId; -// /** -// * 任务的标识 -// * -// * 关联 {@link Task#getTaskDefinitionKey()} -// */ -// private String definitionKey; - /** - * 任务的结果 - * - * 枚举 {@link BpmProcessInstanceResultEnum} - */ - private Integer result; - /** - * 审批建议 - */ - @Deprecated - private String reason; - /** - * 任务的结束时间 - * - * 冗余 HistoricTaskInstance 的 endTime 属性 - */ - private LocalDateTime endTime; - - /** - * 流程实例的编号 - * - * 关联 ProcessInstance 的 id 属性 - */ - private String processInstanceId; - /** - * 流程定义的编号 - * - * 关联 ProcessDefinition 的 id 属性 - */ - private String processDefinitionId; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java deleted file mode 100644 index 0d91545c2..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.mysql.task; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; -import org.apache.ibatis.annotations.Mapper; - -@Mapper -public interface BpmTaskExtMapper extends BaseMapperX { - -// default void updateByTaskId(BpmTaskExtDO entity) { -// update(entity, new LambdaQueryWrapper().eq(BpmTaskExtDO::getTaskId, entity.getTaskId())); -// } - -// default List selectListByTaskIds(Collection taskIds) { -// return selectList(BpmTaskExtDO::getTaskId, taskIds); -// } - - // TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务 -// default List selectProcessListByTaskIds(Collection taskIds) { -// return selectList(new LambdaQueryWrapperX() -// .in(BpmTaskExtDO::getTaskId, taskIds) -// .in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST)); -// } - -// default BpmTaskExtDO selectByTaskId(String taskId) { -// return selectOne(BpmTaskExtDO::getTaskId, taskId); -// } - -// default void updateBatchByTaskIdList(List taskIdList, BpmTaskExtDO updateObj) { -// update(updateObj, new LambdaQueryWrapper().in(BpmTaskExtDO::getTaskId, taskIdList)); -// } - -} 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 08a07bdb5..6114a612b 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 @@ -4,7 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import jakarta.validation.Valid; +import org.flowable.bpmn.model.UserTask; import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; import java.util.Collection; import java.util.List; @@ -25,7 +27,7 @@ public interface BpmTaskService { * @param pageReqVO 分页请求 * @return 流程任务分页 */ - PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); + PageResult getTodoTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); /** * 获得已办的流程任务分页 @@ -34,7 +36,7 @@ public interface BpmTaskService { * @param pageReqVO 分页请求 * @return 流程任务分页 */ - PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO); + PageResult getDoneTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); /** * 获得流程任务 Map @@ -56,12 +58,12 @@ public interface BpmTaskService { List getTasksByProcessInstanceIds(List processInstanceIds); /** - * 获得指令流程实例的流程任务列表,包括所有状态的 + * 获得指定流程实例的流程任务列表,包括所有状态的 * * @param processInstanceId 流程实例的编号 * @return 流程任务列表 */ - List getTaskListByProcessInstanceId(String processInstanceId); + List getTaskListByProcessInstanceId(String processInstanceId); /** * 通过任务 @@ -126,12 +128,12 @@ public interface BpmTaskService { Task getTask(String id); /** - * 获取当前任务的可回退的流程集合 + * 获取当前任务的可回退的 UserTask 集合 * - * @param taskId 当前的任务 ID + * @param id 当前的任务 ID * @return 可以回退的节点列表 */ - List getReturnTaskList(String taskId); + List getUserTaskListByReturn(String id); /** * 将任务回退到指定的 targetDefinitionKey 位置 @@ -158,7 +160,7 @@ public interface BpmTaskService { void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO); /** - * 任务减签名 + * 任务减签 * * @param userId 当前用户ID * @param reqVO 被减签的任务 ID,理由 @@ -166,12 +168,12 @@ public interface BpmTaskService { void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO); /** - * 获取指定任务的子任务和审批人信息 + * 获取指定任务的子任务列表 * - * @param parentId 指定任务ID + * @param parentTaskId 父任务ID * @return 子任务列表 */ - List getChildrenTaskList(String parentId); + List getTaskListByParentTaskId(String parentTaskId); /** * 通过任务 ID,查询任务名 Map 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 199662519..9587de823 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 @@ -13,15 +13,12 @@ import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 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.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; -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 jakarta.annotation.Resource; @@ -34,7 +31,6 @@ import org.flowable.engine.HistoryService; import org.flowable.engine.ManagementService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; -import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.DelegationState; import org.flowable.task.api.Task; @@ -50,10 +46,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.util.Assert; import java.util.*; -import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** @@ -82,49 +78,31 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Resource private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @Resource - private BpmTaskExtMapper taskExtMapper; @Resource private ManagementService managementService; @Override - public PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { - // 查询待办任务 + public PageResult getTodoTaskPage(Long userId, BpmTaskPageReqVO pageVO) { TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己 .orderByTaskCreateTime().desc(); // 创建时间倒序 if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } - if (ArrayUtil.get(pageVO.getCreateTime(), 0) != null) { + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); } - if (ArrayUtil.get(pageVO.getCreateTime(), 1) != null) { - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); } - // 执行查询 List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); - if (CollUtil.isEmpty(tasks)) { - return PageResult.empty(taskQuery.count()); - } - - // 获得 ProcessInstance Map - Map processInstanceMap = processInstanceService.getProcessInstanceMap( - convertSet(tasks, Task::getProcessInstanceId)); - // 获得 User Map - Map userMap = adminUserApi.getUserMap( - convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); - // 拼接结果 - return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap), - taskQuery.count()); + return new PageResult<>(tasks, count); } @Override - public PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { - // 查询已办任务 + public PageResult getDoneTaskPage(Long userId, BpmTaskPageReqVO pageVO) { HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 .includeTaskLocalVariables() .taskAssignee(String.valueOf(userId)) // 分配给自己 @@ -132,29 +110,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); } - // TODO @芋艿:传参风格,统一 - if (pageVO.getBeginCreateTime() != null) { - taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime())); - } - if (pageVO.getEndCreateTime() != null) { - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime())); + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); } // 执行查询 - List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); - if (CollUtil.isEmpty(tasks)) { - return PageResult.empty(taskQuery.count()); + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); } - - // 获得 ProcessInstance Map - Map historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap( - convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); - // 获得 User Map - Map userMap = adminUserApi.getUserMap( - convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); - // 拼接结果 - return new PageResult<>( - BpmTaskConvert.INSTANCE.convertList2(tasks, historicProcessInstanceMap, userMap), - taskQuery.count()); + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(tasks, count); } @Override @@ -166,8 +132,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } @Override - public List getTaskListByProcessInstanceId(String processInstanceId) { - // 获得任务列表 + public List getTaskListByProcessInstanceId(String processInstanceId) { List tasks = historyService.createHistoricTaskInstanceQuery() .includeTaskLocalVariables() .processInstanceId(processInstanceId) @@ -176,19 +141,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (CollUtil.isEmpty(tasks)) { return Collections.emptyList(); } - - // 获得 ProcessInstance Map - HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); - // 获得 User Map - Set userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee())); - userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); - Map userMap = adminUserApi.getUserMap(userIds); - // 获得 Dept Map - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - - // 拼接数据 - List result = BpmTaskConvert.INSTANCE.convertList3(tasks, processInstance, userMap, deptMap); - return BpmTaskConvert.INSTANCE.convertChildrenList(result); + return tasks; } @Override @@ -531,10 +484,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { } @Override - public List getReturnTaskList(String taskId) { - // 1. 校验当前任务 task 存在 - Task task = validateTaskExist(taskId); - // 根据流程定义获取流程模型信息 + public List getUserTaskListByReturn(String id) { + // 1.1 校验当前任务 task 存在 + Task task = validateTaskExist(id); + // 1.2 根据流程定义获取流程模型信息 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); if (source == null) { @@ -548,7 +501,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回 previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null)); - return BpmTaskConvert.INSTANCE.convertList(previousUserList); + return previousUserList; } @Override @@ -560,7 +513,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(TASK_IS_PENDING); } // 1.2 校验源头和目标节点的关系,并返回目标元素 - FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetDefinitionKey(), task.getProcessDefinitionId()); + FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId()); // 3. 更新任务扩展表 TODO 芋艿:需要提前搞 updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); @@ -635,7 +588,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { runtimeService.createChangeActivityStateBuilder() .processInstanceId(currentTask.getProcessInstanceId()) .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多) - reqVO.getTargetDefinitionKey()) // targetKey 跳转到的节点(1) + reqVO.getTargetTaskDefinitionKey()) // targetKey 跳转到的节点(1) .changeState(); } @@ -877,6 +830,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType()); } +// TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务 /** * 获取所有要被取消的删除的任务 ID 集合 * @@ -918,42 +872,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @return 所有子任务的 ID 集合 */ private List getChildrenTaskIdList(String parentTaskId) { - return convertList(getChildrenTaskList0(parentTaskId), Task::getId); + return convertList(getTaskListByParentTaskId(parentTaskId), Task::getId); } - /** - * 获取指定父级任务的所有子任务 ID 集合 - * - * @param parentTaskId 父任务 ID - * @return 所有子任务的 ID 集合 - */ - private List getChildrenTaskList0(String parentTaskId) { + @Override + public List getTaskListByParentTaskId(String parentTaskId) { String tableName = managementService.getTableName(TaskEntity.class); // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询 String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); } - - @Override - public List getChildrenTaskList(String parentId) { - // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner - List taskList = getChildrenTaskList0(parentId); - if (CollUtil.isEmpty(taskList)) { - return Collections.emptyList(); - } - - // 2.1 将 owner 和 assignee 统一到一个集合中 - List userIds = convertListByFlatMap(taskList, control -> - Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner())) - .filter(Objects::nonNull)); // TODO 芋艿:这里可能可以优化下 - // 2.2 组装数据 - Map userMap = adminUserApi.getUserMap(userIds); -// List taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); -// Map idTaskMap = convertMap(taskList, TaskInfo::getId); - return BpmTaskConvert.INSTANCE.convertList(taskList, userMap); - } - @Override public Map getTaskNameByTaskIds(Collection taskIds) { if (CollUtil.isEmpty(taskIds)) { From ba502fc5282b7f00a731abd7f352561f7409dfcd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 17 Mar 2024 22:14:36 +0800 Subject: [PATCH 08/26] =?UTF-8?q?BPM=EF=BC=9A=E8=B0=83=E6=95=B4=E6=8A=84?= =?UTF-8?q?=E9=80=81=E9=80=BB=E8=BE=91=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E6=88=90=E5=AE=A1=E6=89=B9=E9=80=9A=E8=BF=87=E3=80=81?= =?UTF-8?q?=E4=B8=8D=E9=80=9A=E8=BF=87=E6=97=B6=EF=BC=8C=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=8A=84=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/enums/task/BpmCommentTypeEnum.java | 22 +- .../BpmProcessInstanceCopyController.java | 52 ++- .../admin/task/BpmTaskController.java | 53 +-- .../vo/cc/BpmProcessInstanceCopyRespVO.java | 40 ++ .../BpmProcessInstanceCopyCreateReqVO.java | 20 - .../BpmProcessInstanceCopyPageItemRespVO.java | 45 -- ...a => BpmProcessInstanceCopyPageReqVO.java} | 5 +- .../task/vo/task/BpmTaskApproveReqVO.java | 6 +- .../cc/BpmProcessInstanceCopyConvert.java | 40 -- .../bpm/convert/task/BpmTaskConvert.java | 80 ++++ .../cc/BpmProcessInstanceCopyDO.java | 23 +- .../cc/BpmProcessInstanceCopyMapper.java | 6 +- .../BpmProcessInstanceCopyService.java | 21 +- .../BpmProcessInstanceCopyServiceImpl.java | 83 ++++ .../bpm/service/task/BpmTaskServiceImpl.java | 71 +-- .../cc/BpmProcessInstanceCopyServiceImpl.java | 71 --- .../task/cc/dto/BpmDelegateExecutionDTO.java | 439 ------------------ 17 files changed, 315 insertions(+), 762 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/{BpmProcessInstanceCopyMyPageReqVO.java => BpmProcessInstanceCopyPageReqVO.java} (83%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/{cc => }/BpmProcessInstanceCopyService.java (51%) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index 89d56b3c0..06269a31e 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -4,25 +4,29 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 流程任务 -- comment类型枚举 + * 流程任务的 Comment 评论类型枚举 + * + * @author kehaiyou */ @Getter @AllArgsConstructor public enum BpmCommentTypeEnum { - APPROVE(1, "通过", ""), - REJECT(2, "不通过", ""), - CANCEL(3, "已取消", ""), - BACK(4, "退回", ""), - DELEGATE(5, "委派", ""), - ADD_SIGN(6, "加签", "[{}]{}给了[{}],理由为:{}"), - SUB_SIGN(7, "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), + APPROVE("1", "审批通过", ""), // 理由:直接使用用户的评论 + REJECT("2", "不通过", ""), + CANCEL("3", "已取消", ""), + BACK("4", "退回", ""), + DELEGATE("5", "委派", ""), + ADD_SIGN("6", "加签", "[{}]{}给了[{}],理由为:{}"), + SUB_SIGN("7", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), ; /** * 操作类型 + * + * 由于 BPM Comment 类型为 String,所以这里就不使用 Integer */ - private final Integer type; + private final String type; /** * 操作名字 */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java index e1ad107ab..e86f01315 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java @@ -3,23 +3,27 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageItemRespVO; -import cn.iocoder.yudao.module.bpm.convert.cc.BpmProcessInstanceCopyConvert; +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.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; -import cn.iocoder.yudao.module.bpm.service.task.cc.BpmProcessInstanceCopyService; 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; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.flowable.engine.history.HistoricProcessInstance; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.Map; import java.util.stream.Stream; @@ -31,35 +35,27 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @Tag(name = "管理后台 - 流程实例抄送") @RestController -@RequestMapping("/bpm/process-instance/cc") +@RequestMapping("/bpm/process-instance/copy") @Validated public class BpmProcessInstanceCopyController { @Resource private BpmProcessInstanceCopyService processInstanceCopyService; @Resource - private BpmProcessInstanceService bpmProcessInstanceService; + private BpmProcessInstanceService processInstanceService; + @Resource + private BpmTaskService bpmTaskService; @Resource private AdminUserApi adminUserApi; - @Resource - private BpmTaskService bpmTaskService; - - @PostMapping("/create") - @Operation(summary = "抄送流程") - @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')") - public CommonResult createProcessInstanceCopy(@Valid @RequestBody BpmProcessInstanceCopyCreateReqVO createReqVO) { - processInstanceCopyService.createProcessInstanceCopy(getLoginUserId(), createReqVO); - return success(true); - } - - @GetMapping("/my-page") + @GetMapping("/page") @Operation(summary = "获得抄送流程分页列表") @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')") - public CommonResult> getProcessInstanceCopyPage( - @Valid BpmProcessInstanceCopyMyPageReqVO pageReqVO) { - PageResult pageResult = processInstanceCopyService.getMyProcessInstanceCopyPage(getLoginUserId(), pageReqVO); + public CommonResult> getProcessInstanceCopyPage( + @Valid BpmProcessInstanceCopyPageReqVO pageReqVO) { + PageResult pageResult = processInstanceCopyService.getProcessInstanceCopyPage( + getLoginUserId(), pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return success(new PageResult<>(pageResult.getTotal())); } @@ -67,11 +63,17 @@ public class BpmProcessInstanceCopyController { // 拼接返回 Map taskNameMap = bpmTaskService.getTaskNameByTaskIds( convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getTaskId)); - Map processNameMap = bpmProcessInstanceService.getProcessInstanceNameMap( + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId)); Map userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), copy -> Stream.of(copy.getStartUserId(), Long.parseLong(copy.getCreator())))); - return success(BpmProcessInstanceCopyConvert.INSTANCE.convertPage(pageResult, taskNameMap, processNameMap, userMap)); + return success(BeanUtils.toBean(pageResult, BpmProcessInstanceCopyRespVO.class, copyVO -> { + MapUtils.findAndThen(userMap, Long.valueOf(copyVO.getCreator()), user -> copyVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, copyVO.getStartUserId(), user -> copyVO.setStartUserName(user.getNickname())); + MapUtils.findAndThen(taskNameMap, copyVO.getTaskId(), copyVO::setTaskName); + MapUtils.findAndThen(processInstanceMap, copyVO.getProcessInstanceId(), + processInstance -> copyVO.setProcessInstanceStartTime(DateUtils.of(processInstance.getStartTime()))); + })); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index 78429ea21..f18926582 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -1,15 +1,13 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; +import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -66,15 +64,7 @@ public class BpmTaskController { convertSet(pageResult.getList(), Task::getProcessInstanceId)); Map userMap = adminUserApi.getUserMap( convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); - return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { - ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); - if (processInstance == null) { - return; - } - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); - })); + return success(BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap)); } @GetMapping("done-page") @@ -87,18 +77,9 @@ public class BpmTaskController { convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); Map userMap = adminUserApi.getUserMap( convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); - return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { - HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); - if (processInstance == null) { - return; - } - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); - })); + return success(BpmTaskConvert.INSTANCE.buildDoneTaskPage(pageResult, processInstanceMap, userMap)); } - // TODO @芋艿:怎么优化下 @GetMapping("/list-by-process-instance-id") @Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的") @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) @@ -118,33 +99,7 @@ public class BpmTaskController { Map userMap = adminUserApi.getUserMap(userIds); Map deptMap = deptApi.getDeptMap( convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - List taskVOList = CollectionUtils.convertList(taskList, task -> { - BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); - taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); - // 流程实例 - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); - // 用户信息 - AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); - if (assignUser != null) { - taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); - DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); - if (dept != null) { - taskVO.getAssigneeUser().setDeptName(dept.getName()); - } - } - return taskVO; - }); - - // 拼接父子关系 - Map> childrenTaskMap = convertMultiMap( - filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())), - BpmTaskRespVO::getParentTaskId); - for (BpmTaskRespVO taskVO : taskVOList) { - taskVO.setChildren(childrenTaskMap.get(taskVO.getId())); - } - return success(filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId()))); + return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, userMap, deptMap)); } @PutMapping("/approve") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java new file mode 100644 index 000000000..4b397fc1c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO") +@Data +public class BpmProcessInstanceCopyRespVO { + + @Schema(description = "抄送主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "发起人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long startUserId; + @Schema(description = "发起人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String startUserName; + + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "A233") + private String processInstanceId; + @Schema(description = "流程实例的名称") + private String processInstanceName; + @Schema(description = "流程实例的发起时间") + private LocalDateTime processInstanceStartTime; + + @Schema(description = "发起抄送的任务编号") + private String taskId; + @Schema(description = "发起抄送的任务名称") + private String taskName; + + @Schema(description = "抄送人") + private String creator; + @Schema(description = "抄送人昵称") + private String creatorName; + + @Schema(description = "抄送时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java deleted file mode 100644 index 3a1b1d45c..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -@Schema(description = "管理后台 - 流程实例抄送的创建 Request VO") -@Data -public class BpmProcessInstanceCopyCreateReqVO { - - @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotEmpty(message = "任务编号不能为空") - private String taskId; - - @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!") - @NotBlank(message = "抄送原因不能为空") - private String reason; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java deleted file mode 100644 index 4b149a65e..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO") -@Data -public class BpmProcessInstanceCopyPageItemRespVO { - - @Schema(description = "抄送主键") - private Long id; - - @Schema(description = "发起人 ID") - private Long startUserId; - - @Schema(description = "发起人别名") - private String startUserNickname; - - @Schema(description = "流程实例的主键") - private String processInstanceId; - - @Schema(description = "流程实例的名称") - private String processInstanceName; - - @Schema(description = "发起抄送的任务编号") - private String taskId; - - @Schema(description = "发起抄送的任务名称") - private String taskName; - - @Schema(description = "抄送原因") - private String reason; - - @Schema(description = "抄送人") - private String creator; - - @Schema(description = "抄送人别名") - private String creatorNickname; - - @Schema(description = "抄送时间") - private LocalDateTime createTime; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyMyPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java similarity index 83% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyMyPageReqVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java index 7b4effadd..a0c431814 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyMyPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java @@ -15,14 +15,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class BpmProcessInstanceCopyMyPageReqVO extends PageParam { +public class BpmProcessInstanceCopyPageReqVO extends PageParam { @Schema(description = "流程名称", example = "芋道") private String processInstanceName; - @Schema(description = "流程编号", example = "123456768") - private String processInstanceId; - @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index 14dca13ea..c5ca09b37 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -1,9 +1,10 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Data; -import jakarta.validation.constraints.NotEmpty; +import java.util.Collection; @Schema(description = "管理后台 - 通过流程任务的 Request VO") @Data @@ -17,4 +18,7 @@ public class BpmTaskApproveReqVO { @NotEmpty(message = "审批意见不能为空") private String reason; + @Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2") + private Collection copyUserIds; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java deleted file mode 100644 index f482c71e6..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.cc; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageItemRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; - -/** - * 流程抄送 Convert - * - * @author 芋艿 - */ -@Mapper -public interface BpmProcessInstanceCopyConvert { - - BpmProcessInstanceCopyConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceCopyConvert.class); - - default PageResult convertPage(PageResult page, - Map taskNameMap, - Map processInstaneNameMap, - Map userMap) { - List list = BeanUtils.toBean(page.getList(), - BpmProcessInstanceCopyPageItemRespVO.class, - copy -> { - MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), user -> user.setNickname(user.getNickname())); - MapUtils.findAndThen(userMap, copy.getStartUserId(), user -> copy.setStartUserNickname(user.getNickname())); - MapUtils.findAndThen(taskNameMap, copy.getTaskId(), copy::setTaskName); - MapUtils.findAndThen(processInstaneNameMap, copy.getProcessInstanceId(), copy::setProcessInstanceName); - }); - return new PageResult<>(list, page.getTotal()); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index dcc34f0de..8bbe10f8b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -1,16 +1,31 @@ package cn.iocoder.yudao.module.bpm.convert.task; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.util.Date; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; /** * Bpm 任务 Convert @@ -22,6 +37,71 @@ public interface BpmTaskConvert { BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); + default PageResult buildTodoTaskPage(PageResult pageResult, + Map processInstanceMap, + Map userMap) { + return BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> { + ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance == null) { + return; + } + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + }); + } + + default PageResult buildDoneTaskPage(PageResult pageResult, + Map processInstanceMap, + Map userMap) { + List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { + BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); + taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + // 流程实例 + HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); + if (processInstance != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + } + return taskVO; + }); + return new PageResult<>(taskVOList, pageResult.getTotal()); + } + + default List buildTaskListByProcessInstanceId(List taskList, + HistoricProcessInstance processInstance, + Map userMap, + Map deptMap) { + List taskVOList = CollectionUtils.convertList(taskList, task -> { + BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); + taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + // 流程实例 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, + processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + // 用户信息 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); + if (dept != null) { + taskVO.getAssigneeUser().setDeptName(dept.getName()); + } + } + return taskVO; + }); + + // 拼接父子关系 + Map> childrenTaskMap = convertMultiMap( + filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())), + BpmTaskRespVO::getParentTaskId); + for (BpmTaskRespVO taskVO : taskVOList) { + taskVO.setChildren(childrenTaskMap.get(taskVO.getId())); + } + return filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId())); + } + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) { BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java index 7ca65f3db..99bca609d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java @@ -29,7 +29,7 @@ public class BpmProcessInstanceCopyDO extends BaseDO { /** * 发起人 Id * - * 关联 system_users 的 id 属性 + * 冗余 ProcessInstance 的 startUserId 字段 */ private Long startUserId; /** @@ -44,6 +44,12 @@ public class BpmProcessInstanceCopyDO extends BaseDO { * 关联 ProcessInstance 的 id 属性 */ private String processInstanceId; + /** + * 流程分类 + * + * 冗余 ProcessInstance 的 category 字段 + */ + private String category; /** * 任务主键 @@ -51,7 +57,6 @@ public class BpmProcessInstanceCopyDO extends BaseDO { * 关联 Task 的 id 属性 */ private String taskId; - /** * 任务名称 * @@ -60,22 +65,10 @@ public class BpmProcessInstanceCopyDO extends BaseDO { private String taskName; /** - * 用户编号 + * 用户编号(被抄送的用户编号) * * 关联 system_users 的 id 属性 */ private Long userId; - /** - * 抄送原因 - */ - private String reason; - - /** - * 流程分类 - * - * 冗余 ProcessInstance 的 category 字段 - */ - private String category; - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java index de6fa14f5..2179525e0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java @@ -3,19 +3,19 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.cc; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; import org.apache.ibatis.annotations.Mapper; @Mapper public interface BpmProcessInstanceCopyMapper extends BaseMapperX { - default PageResult selectPage(Long loginUserId, BpmProcessInstanceCopyMyPageReqVO reqVO) { + default PageResult selectPage(Long loginUserId, BpmProcessInstanceCopyPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(BpmProcessInstanceCopyDO::getUserId, loginUserId) - .eqIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceId, reqVO.getProcessInstanceId()) .likeIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceName, reqVO.getProcessInstanceName()) .betweenIfPresent(BpmProcessInstanceCopyDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(BpmProcessInstanceCopyDO::getId)); } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java similarity index 51% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java index 4d1db2958..67135167a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -1,10 +1,11 @@ -package cn.iocoder.yudao.module.bpm.service.task.cc; +package cn.iocoder.yudao.module.bpm.service.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import java.util.Collection; + /** * 流程抄送 Service 接口 * @@ -15,17 +16,19 @@ public interface BpmProcessInstanceCopyService { /** * 流程实例的抄送 * - * @param userId 当前登录用户 - * @param createReqVO 创建的抄送请求 + * @param userIds 抄送的用户编号 + * @param taskId 流程任务编号 */ - void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO createReqVO); + void createProcessInstanceCopy(Collection userIds, String taskId); /** - * 抄送的流程的分页 + * 获得抄送的流程的分页 + * * @param userId 当前登录用户 * @param pageReqVO 分页请求 * @return 抄送的分页结果 */ - PageResult getMyProcessInstanceCopyPage(Long userId, - BpmProcessInstanceCopyMyPageReqVO pageReqVO); + PageResult getProcessInstanceCopyPage(Long userId, + BpmProcessInstanceCopyPageReqVO pageReqVO); + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java new file mode 100644 index 000000000..e45ce881c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * 流程抄送 Service 实现类 + * + * @author kyle + */ +@Service +@Validated +@Slf4j +public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService { + + @Resource + private BpmProcessInstanceCopyMapper processInstanceCopyMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmTaskService taskService; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessInstanceService processInstanceService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessDefinitionService processDefinitionService; + + @Override + public void createProcessInstanceCopy(Collection userIds, String taskId) { + // 1.1 校验任务存在 + Task task = taskService.getTask(taskId); + if (ObjectUtil.isNull(task)) { + throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); + } + // 1.2 校验流程实例存在 + String processInstanceId = task.getProcessInstanceId(); + ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId); + if (processInstance == null) { + throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); + } + // 1.3 校验流程定义存在 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + processInstance.getProcessDefinitionId()); + if (processDefinition == null) { + throw exception(ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS); + } + + // 2. 创建抄送流程 + List copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO() + .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId())) + .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName()) + .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName())); + processInstanceCopyMapper.insertBatch(copyList); + } + + @Override + public PageResult getProcessInstanceCopyPage(Long userId, + BpmProcessInstanceCopyPageReqVO pageReqVO) { + return processInstanceCopyMapper.selectPage(userId, pageReqVO); + } + +} 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 9587de823..a2211e640 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 @@ -68,10 +68,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { private HistoryService historyService; @Resource private RuntimeService runtimeService; + @Resource + private ManagementService managementService; @Resource private BpmProcessInstanceService processInstanceService; @Resource + private BpmProcessInstanceCopyService processInstanceCopyService; + @Resource private BpmModelService bpmModelService; @Resource private BpmMessageService messageService; @@ -79,12 +83,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Resource private AdminUserApi adminUserApi; - @Resource - private ManagementService managementService; - @Override public PageResult getTodoTaskPage(Long userId, BpmTaskPageReqVO pageVO) { - TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己 + TaskQuery taskQuery = taskService.createTaskQuery() + .taskAssignee(String.valueOf(userId)) // 分配给自己 + .active() + .includeProcessVariables() .orderByTaskCreateTime().desc(); // 创建时间倒序 if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); @@ -103,9 +107,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public PageResult getDoneTaskPage(Long userId, BpmTaskPageReqVO pageVO) { - HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 - .includeTaskLocalVariables() + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery() + .finished() // 已完成 .taskAssignee(String.valueOf(userId)) // 分配给自己 + .includeTaskLocalVariables() .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 if (StrUtil.isNotBlank(pageVO.getName())) { taskQuery.taskNameLike("%" + pageVO.getName() + "%"); @@ -155,30 +160,34 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(PROCESS_INSTANCE_NOT_EXISTS); } + // 2. 抄送用户 + if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) { + processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId()); + } + // 情况一:被委派的任务,不调用 complete 去完成任务 if (DelegationState.PENDING.equals(task.getDelegationState())) { approveDelegateTask(reqVO, task); return; } - // 情况二:后加签的任务 + // 情况二:审批有【后】加签的任务 if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(task.getScopeType())) { - // 后加签处理 approveAfterSignTask(task, reqVO); return; } - // 情况三:自己审批的任务,调用 complete 去完成任务 - // 完成任务,审批通过 + // 情况三:审批普通的任务。大多数情况下,都是这样 + // 更新流程任务 status 为审批通过 updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult()); + // 添加评论 + taskService.addComment(task.getId(), task.getProcessInstanceId(), + BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason()); + // 调用 BPM complete 去完成任务 taskService.complete(task.getId(), instance.getProcessVariables()); -// // 更新任务拓展表为通过 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) -// .setReason(reqVO.getReason())); + // 处理加签任务 -// handleParentTask(task); - handleParentTaskNew(task.getParentTaskId()); + handleParentTaskIfSign(task.getParentTaskId()); } /** @@ -209,8 +218,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { // new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); } - // TODO 芋艿:名字 - private void handleParentTaskNew(String parentTaskId) { + /** + * 如果父任务是有前后【加签】的任务,如果它【加签】出来的子任务都被处理,需要处理父任务: + * + * 1. 如果是【向前】加签,则需要重新激活父任务,让它可以被审批 + * 2. 如果是【向后】加签,则需要完成父任务,让它完成审批 + * + * @param parentTaskId 父任务编号 + */ + private void handleParentTaskIfSign(String parentTaskId) { if (StrUtil.isBlank(parentTaskId)) { return; } @@ -227,7 +243,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 2. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 - clearTaskScopeTypeAndSave(parentTask); + TaskEntityImpl parentTaskImpl = (TaskEntityImpl) parentTask; + parentTaskImpl.setScopeType(null); + taskService.saveTask(parentTaskImpl); // 3.1 情况一:处理向【向前】加签 if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { @@ -243,18 +261,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 4. 递归处理父任务 - handleParentTaskNew(parentTask.getParentTaskId()); - } - - /** - * 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签 - * - * @param task 需要被清空的任务 - */ - private void clearTaskScopeTypeAndSave(Task task) { - TaskEntityImpl taskImpl = (TaskEntityImpl) task; - taskImpl.setScopeType(null); - taskService.saveTask(task); + handleParentTaskIfSign(parentTask.getParentTaskId()); } /** @@ -797,7 +804,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); // 4. 处理当前任务的父任务 - handleParentTaskNew(task.getParentTaskId()); + handleParentTaskIfSign(task.getParentTaskId()); } /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java deleted file mode 100644 index d800d1932..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.task.cc; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; -import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; -import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; -import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.task.api.Task; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; - -/** - * 流程抄送 Service 实现类 - * - * @author kyle - */ -@Service -@Validated -@Slf4j -public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService { - - @Resource - private BpmProcessInstanceCopyMapper processInstanceCopyMapper; - - @Resource - @Lazy - private BpmTaskService bpmTaskService; - @Resource - @Lazy - private BpmProcessInstanceService bpmProcessInstanceService; - - @Override - public void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO reqVO) { - // 1.1 校验任务存在 - Task task = bpmTaskService.getTask(reqVO.getTaskId()); - if (ObjectUtil.isNull(task)) { - throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); - } - // 1.2 校验流程存在 - String processInstanceId = task.getProcessInstanceId(); - ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(processInstanceId); - if (processInstance == null) { - log.warn("[createProcessInstanceCopy][任务({}) 对应的流程不存在]", reqVO.getTaskId()); - throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); - } - - // 2. 创建抄送流程 - BpmProcessInstanceCopyDO copy = new BpmProcessInstanceCopyDO() - .setTaskId(reqVO.getTaskId()).setTaskName(task.getName()) - .setProcessInstanceId(processInstanceId).setStartUserId(Long.valueOf(processInstance.getStartUserId())) - .setProcessInstanceName(processInstance.getName()).setCategory(processInstance.getProcessDefinitionCategory()) - .setReason(reqVO.getReason()); - processInstanceCopyMapper.insert(copy); - } - - @Override - public PageResult getMyProcessInstanceCopyPage(Long userId, BpmProcessInstanceCopyMyPageReqVO pageReqVO) { - return processInstanceCopyMapper.selectPage(userId, pageReqVO); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java deleted file mode 100644 index d010d8969..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java +++ /dev/null @@ -1,439 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.task.cc.dto; - -import org.flowable.bpmn.model.FlowElement; -import org.flowable.bpmn.model.FlowableListener; -import org.flowable.engine.delegate.DelegateExecution; -import org.flowable.engine.delegate.ReadOnlyDelegateExecution; -import org.flowable.variable.api.persistence.entity.VariableInstance; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * 仅为了传输processInstanceId - */ -public class BpmDelegateExecutionDTO implements DelegateExecution { - - public BpmDelegateExecutionDTO(String getProcessInstanceId) { - this.getProcessInstanceId = getProcessInstanceId; - } - - private final String getProcessInstanceId; - - @Override - public String getId() { - return null; - } - - @Override - public String getProcessInstanceId() { - return null; - } - - @Override - public String getRootProcessInstanceId() { - return null; - } - - @Override - public String getEventName() { - return null; - } - - @Override - public void setEventName(String eventName) { - - } - - @Override - public String getProcessInstanceBusinessKey() { - return null; - } - - @Override - public String getProcessInstanceBusinessStatus() { - return null; - } - - @Override - public String getProcessDefinitionId() { - return null; - } - - @Override - public String getPropagatedStageInstanceId() { - return null; - } - - @Override - public String getParentId() { - return null; - } - - @Override - public String getSuperExecutionId() { - return null; - } - - @Override - public String getCurrentActivityId() { - return null; - } - - @Override - public String getTenantId() { - return null; - } - - @Override - public FlowElement getCurrentFlowElement() { - return null; - } - - @Override - public void setCurrentFlowElement(FlowElement flowElement) { - - } - - @Override - public FlowableListener getCurrentFlowableListener() { - return null; - } - - @Override - public void setCurrentFlowableListener(FlowableListener currentListener) { - - } - - @Override - public ReadOnlyDelegateExecution snapshotReadOnly() { - return null; - } - - @Override - public DelegateExecution getParent() { - return null; - } - - @Override - public List getExecutions() { - return null; - } - - @Override - public void setActive(boolean isActive) { - - } - - @Override - public boolean isActive() { - return false; - } - - @Override - public boolean isEnded() { - return false; - } - - @Override - public void setConcurrent(boolean isConcurrent) { - - } - - @Override - public boolean isConcurrent() { - return false; - } - - @Override - public boolean isProcessInstanceType() { - return false; - } - - @Override - public void inactivate() { - - } - - @Override - public boolean isScope() { - return false; - } - - @Override - public void setScope(boolean isScope) { - - } - - @Override - public boolean isMultiInstanceRoot() { - return false; - } - - @Override - public void setMultiInstanceRoot(boolean isMultiInstanceRoot) { - - } - - @Override - public Map getVariables() { - return null; - } - - @Override - public Map getVariableInstances() { - return null; - } - - @Override - public Map getVariables(Collection collection) { - return null; - } - - @Override - public Map getVariableInstances(Collection collection) { - return null; - } - - @Override - public Map getVariables(Collection collection, boolean b) { - return null; - } - - @Override - public Map getVariableInstances(Collection collection, boolean b) { - return null; - } - - @Override - public Map getVariablesLocal() { - return null; - } - - @Override - public Map getVariableInstancesLocal() { - return null; - } - - @Override - public Map getVariablesLocal(Collection collection) { - return null; - } - - @Override - public Map getVariableInstancesLocal(Collection collection) { - return null; - } - - @Override - public Map getVariablesLocal(Collection collection, boolean b) { - return null; - } - - @Override - public Map getVariableInstancesLocal(Collection collection, boolean b) { - return null; - } - - @Override - public Object getVariable(String s) { - return null; - } - - @Override - public VariableInstance getVariableInstance(String s) { - return null; - } - - @Override - public Object getVariable(String s, boolean b) { - return null; - } - - @Override - public VariableInstance getVariableInstance(String s, boolean b) { - return null; - } - - @Override - public Object getVariableLocal(String s) { - return null; - } - - @Override - public VariableInstance getVariableInstanceLocal(String s) { - return null; - } - - @Override - public Object getVariableLocal(String s, boolean b) { - return null; - } - - @Override - public VariableInstance getVariableInstanceLocal(String s, boolean b) { - return null; - } - - @Override - public T getVariable(String s, Class aClass) { - return null; - } - - @Override - public T getVariableLocal(String s, Class aClass) { - return null; - } - - @Override - public Set getVariableNames() { - return null; - } - - @Override - public Set getVariableNamesLocal() { - return null; - } - - @Override - public void setVariable(String s, Object o) { - - } - - @Override - public void setVariable(String s, Object o, boolean b) { - - } - - @Override - public Object setVariableLocal(String s, Object o) { - return null; - } - - @Override - public Object setVariableLocal(String s, Object o, boolean b) { - return null; - } - - @Override - public void setVariables(Map map) { - - } - - @Override - public void setVariablesLocal(Map map) { - - } - - @Override - public boolean hasVariables() { - return false; - } - - @Override - public boolean hasVariablesLocal() { - return false; - } - - @Override - public boolean hasVariable(String s) { - return false; - } - - @Override - public boolean hasVariableLocal(String s) { - return false; - } - - @Override - public void removeVariable(String s) { - - } - - @Override - public void removeVariableLocal(String s) { - - } - - @Override - public void removeVariables(Collection collection) { - - } - - @Override - public void removeVariablesLocal(Collection collection) { - - } - - @Override - public void removeVariables() { - - } - - @Override - public void removeVariablesLocal() { - - } - - @Override - public void setTransientVariable(String s, Object o) { - - } - - @Override - public void setTransientVariableLocal(String s, Object o) { - - } - - @Override - public void setTransientVariables(Map map) { - - } - - @Override - public Object getTransientVariable(String s) { - return null; - } - - @Override - public Map getTransientVariables() { - return null; - } - - @Override - public void setTransientVariablesLocal(Map map) { - - } - - @Override - public Object getTransientVariableLocal(String s) { - return null; - } - - @Override - public Map getTransientVariablesLocal() { - return null; - } - - @Override - public void removeTransientVariableLocal(String s) { - - } - - @Override - public void removeTransientVariable(String s) { - - } - - @Override - public void removeTransientVariables() { - - } - - @Override - public void removeTransientVariablesLocal() { - - } -} From c4688d887ca4c10a8a2fbb6b5c4acde59b026c32 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 18 Mar 2024 18:41:04 +0800 Subject: [PATCH 09/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=20task=20?= =?UTF-8?q?=E7=9A=84=E5=AE=A1=E6=89=B9=E5=BB=BA=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/enums/task/BpmCommentTypeEnum.java | 2 +- ...esultEnum.java => BpmTaskStatustEnum.java} | 28 +++---- .../admin/task/vo/task/BpmTaskRespVO.java | 5 +- .../bpm/convert/task/BpmTaskConvert.java | 2 + .../module/bpm/convert/task/package-info.java | 1 - .../bpm/dal/dataobject/oa/BpmOALeaveDO.java | 4 +- .../flowable/core/enums/BpmConstants.java | 8 ++ .../bpm/service/oa/BpmOALeaveServiceImpl.java | 4 +- .../bpm/service/task/BpmTaskServiceImpl.java | 84 +++++++++---------- .../flowable/core/util/BpmnModelUtils.java | 2 +- .../module/crm/util/CrmAuditStatusUtils.java | 8 +- 11 files changed, 80 insertions(+), 68 deletions(-) rename yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/{BpmProcessInstanceResultEnum.java => BpmTaskStatustEnum.java} (71%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index 06269a31e..f2c2ded53 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -15,7 +15,7 @@ public enum BpmCommentTypeEnum { APPROVE("1", "审批通过", ""), // 理由:直接使用用户的评论 REJECT("2", "不通过", ""), CANCEL("3", "已取消", ""), - BACK("4", "退回", ""), + BACK("4", "退回", ""), // 理由:直接使用用户的评论 DELEGATE("5", "委派", ""), ADD_SIGN("6", "加签", "[{}]{}给了[{}],理由为:{}"), SUB_SIGN("7", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java similarity index 71% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java index bd4f361d5..ee06b0847 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java @@ -5,13 +5,13 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 流程实例的结果 + * 流程任务 Task 的状态枚举 * * @author jason */ @Getter @AllArgsConstructor -public enum BpmProcessInstanceResultEnum { +public enum BpmTaskStatustEnum { RUNNING(1, "审批中"), APPROVE(2, "审批通过"), @@ -43,28 +43,28 @@ public enum BpmProcessInstanceResultEnum { // WAIT_BEFORE_TASK(9, "处理中【待前置任务完成】"); /** - * 结果 + * 状态 *

- * 如果新增时,注意 {@link #isEndResult(Integer)} 是否需要变更 + * 如果新增时,注意 {@link #isEndStatus(Integer)} 是否需要变更 */ - private final Integer result; + private final Integer status; /** - * 描述 + * 名字 */ - private final String desc; + private final String name; /** - * 判断该结果是否已经处于 End 最终结果 + * 判断该状态是否已经处于 End 最终状态 *

- * 主要用于一些结果更新的逻辑,如果已经是最终结果,就不再进行更新 + * 主要用于一些状态更新的逻辑,如果已经是最终状态,就不再进行更新 * - * @param result 结果 + * @param status 状态 * @return 是否 */ - public static boolean isEndResult(Integer result) { - return ObjectUtils.equalsAny(result, - APPROVE.getResult(), REJECT.getResult(), CANCEL.getResult(), - BACK.getResult(), APPROVING.getResult()); + public static boolean isEndStatus(Integer status) { + return ObjectUtils.equalsAny(status, + APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus(), + BACK.getStatus(), APPROVING.getStatus()); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 1e1bebf04..46ac3f36d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -27,7 +27,10 @@ public class BpmTaskRespVO { private Long durationInMillis; @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 + private Integer status; // 参见 BpmTaskStatusEnum 枚举 + + @Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String reason; /** * 负责人的用户信息 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 8bbe10f8b..ee7b5245c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -57,6 +57,7 @@ public interface BpmTaskConvert { List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); // 流程实例 HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); if (processInstance != null) { @@ -76,6 +77,7 @@ public interface BpmTaskConvert { List taskVOList = CollectionUtils.convertList(taskList, task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); + taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); // 流程实例 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java deleted file mode 100644 index 6a53114a8..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.task; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java index 4e4e68d6f..e24ce02ad 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -59,7 +59,7 @@ public class BpmOALeaveDO extends BaseDO { /** * 请假的结果 * - * 枚举 {@link BpmProcessInstanceResultEnum} + * 枚举 {@link BpmTaskStatustEnum} * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 */ private Integer result; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java index 7649b0fbc..6dd5e79c7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java @@ -22,5 +22,13 @@ public class BpmConstants { * @see org.flowable.task.api.Task#getTaskLocalVariables() */ public static final String TASK_VARIABLE_STATUS = "TASK_STATUS"; + /** + * 任务的变量 - 理由 + * + * 例如说:审批通过、不通过的理由 + * + * @see org.flowable.task.api.Task#getTaskLocalVariables() + */ + public static final String TASK_VARIABLE_REASON = "TASK_REASON"; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java index 3c786d805..9477e667d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -48,7 +48,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { // 插入 OA 请假单 long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays(); BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day) - .setResult(BpmProcessInstanceResultEnum.RUNNING.getResult()); + .setResult(BpmTaskStatustEnum.RUNNING.getStatus()); leaveMapper.insert(leave); // 发起 BPM 流程 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 a2211e640..b0bc45e3f 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 @@ -14,7 +14,7 @@ import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 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.enums.task.BpmCommentTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; @@ -178,15 +178,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 情况三:审批普通的任务。大多数情况下,都是这样 - // 更新流程任务 status 为审批通过 - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult()); - // 添加评论 + // 3.1 更新 task 状态、原因 + updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus()); + // 3.2 添加评论 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason()); - // 调用 BPM complete 去完成任务 + // 3.3 调用 BPM complete 去完成任务 taskService.complete(task.getId(), instance.getProcessVariables()); - // 处理加签任务 + // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); } @@ -204,14 +204,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { // new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult()) // .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); // TODO @芋艿:reqVO.reason??? - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVING.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVING.getStatus()); // 2. 激活子任务 List childrenTaskIdList = getChildrenTaskIdList(task.getId()); for (String childrenTaskId : childrenTaskIdList) { taskService.resolveTask(childrenTaskId); // 更新任务扩展表中子任务为进行中 - updateTaskStatus(childrenTaskId, BpmProcessInstanceResultEnum.RUNNING.getResult()); + updateTaskStatus(childrenTaskId, BpmTaskStatustEnum.RUNNING.getStatus()); } // 2.1 更新任务扩展表中子任务为进行中 // taskExtMapper.updateBatchByTaskIdList(childrenTaskIdList, @@ -252,11 +252,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批 taskService.resolveTask(parentTaskId); // 3.1.2 更新流程任务 status - updateTaskStatus(parentTaskId, BpmProcessInstanceResultEnum.RUNNING.getResult()); + updateTaskStatus(parentTaskId, BpmTaskStatustEnum.RUNNING.getStatus()); // 3.2 情况二:处理向【向后】加签 } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { // 3.2.1 完成自己(因为它已经没有子任务,所以也可以完成) - updateTaskStatus(parentTaskId, BpmProcessInstanceResultEnum.APPROVE.getResult()); + updateTaskStatus(parentTaskId, BpmTaskStatustEnum.APPROVE.getStatus()); taskService.complete(parentTaskId); } @@ -299,7 +299,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // taskExtMapper.updateByTaskId( // new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.RUNNING.getResult()) // .setReason(reqVO.getReason())); - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.RUNNING.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); } @Override @@ -313,7 +313,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 更新流程实例为不通过 - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.REJECT.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.REJECT.getStatus()); processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason()); // // 更新任务拓展表为不通过 @@ -342,13 +342,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param status 状态 */ private void updateTaskStatus(String id, Integer status) { -// try { -// } catch (FlowableObjectNotFoundException exception) { -// historyService. -// } taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status); } + /** + * 更新流程任务的 status 状态、reason 理由 + * + * @param id 任务编号 + * @param status 状态 + * @param reason 理由(审批通过、审批不通过的理由) + */ + private void updateTaskStatus(String id, Integer status, String reason) { + taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status); + taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_REASON, reason); + } + /** * 校验任务是否存在, 并且是否是分配给自己的任务 * @@ -382,7 +390,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { // status = BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult(); // } - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.RUNNING.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); } @Override @@ -392,7 +400,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // .setEndTime(LocalDateTime.now()); // taskExtMapper.updateByTaskId(taskExtDO); - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus()); } @Override @@ -405,11 +413,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { } Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); - if (BpmProcessInstanceResultEnum.isEndResult(status)) { + if (BpmTaskStatustEnum.isEndStatus(status)) { log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } - updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult()); + updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus()); if (true) { return; @@ -438,7 +446,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // return; // } Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); - if (BpmProcessInstanceResultEnum.isEndResult(status)) { + if (BpmTaskStatustEnum.isEndStatus(status)) { log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } @@ -446,7 +454,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 更新任务 // taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) // .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason()))); - updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult()); + updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus()); } }); @@ -520,19 +528,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(TASK_IS_PENDING); } // 1.2 校验源头和目标节点的关系,并返回目标元素 - FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId()); + FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), + reqVO.getTargetTaskDefinitionKey(), task.getProcessDefinitionId()); - // 3. 更新任务扩展表 TODO 芋艿:需要提前搞 - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); - - // 2. 调用 flowable 框架的回退逻辑 - returnTask0(task, targetElement, reqVO); - - // 3. 更新任务扩展表 -// updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); -// taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId()) -// .setResult(BpmProcessInstanceResultEnum.BACK.getResult()) -// .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); + // 2. 调用 Flowable 框架的回退逻辑 + returnTask(task, targetElement, reqVO); } /** @@ -568,7 +568,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param targetElement 需要回退到的目标任务 * @param reqVO 前端参数封装 */ - public void returnTask0(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) { + public void returnTask(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) { // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤 // 1.1 获取所有正常进行的任务节点 Key List taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list(); @@ -584,11 +584,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { return; } + // 2.1 添加评论 taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), - BpmCommentTypeEnum.BACK.getType().toString(), reqVO.getReason()); - - // TODO 芋艿:这里加下驳回的 - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.BACK.getResult()); + BpmCommentTypeEnum.BACK.getType(), reqVO.getReason()); + // 2.2 更新 task 状态 + 原因 + updateTaskStatus(task.getId(), BpmTaskStatustEnum.BACK.getStatus(), reqVO.getReason()); }); // 3. 执行驳回 @@ -626,7 +626,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // taskExtMapper.updateByTaskId( // new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult()) // .setReason(reqVO.getReason())); - updateTaskStatus(taskId, BpmProcessInstanceResultEnum.DELEGATE.getResult()); + updateTaskStatus(taskId, BpmTaskStatustEnum.DELEGATE.getStatus()); } /** @@ -677,7 +677,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.5 保存当前任务修改后的值 taskService.saveTask(taskEntity); if (reqVO.getType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) { - updateTaskStatus(taskEntity.getId(), BpmProcessInstanceResultEnum.WAIT.getResult()); // TODO 芋艿:貌似只能放在这个地方,不然会有并发修改的报错 + updateTaskStatus(taskEntity.getId(), BpmTaskStatustEnum.WAIT.getStatus()); // TODO 芋艿:貌似只能放在这个地方,不然会有并发修改的报错 } // 3. 创建加签任务 @@ -767,7 +767,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.saveTask(task); // 3. TODO if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { - updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.WAIT.getResult()); + updateTaskStatus(task.getId(), BpmTaskStatustEnum.WAIT.getStatus()); } } diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java index 6de30aa94..264dd7ec6 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java @@ -55,7 +55,7 @@ public class BpmnModelUtils { /** * 获得 BPMN 流程中,指定的元素们 * - * @param model + * @param model 模型 * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等 * @return 元素们 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java index 665e98fbe..43e681c5e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.util; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; /** @@ -17,9 +17,9 @@ public class CrmAuditStatusUtils { * @param bpmResult BPM 审批结果 */ public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { - Integer auditStatus = BpmProcessInstanceResultEnum.APPROVE.getResult().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() - : BpmProcessInstanceResultEnum.REJECT.getResult().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() - : BpmProcessInstanceResultEnum.CANCEL.getResult().equals(bpmResult) ? BpmProcessInstanceResultEnum.CANCEL.getResult() : null; + Integer auditStatus = BpmTaskStatustEnum.APPROVE.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() + : BpmTaskStatustEnum.REJECT.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() + : BpmTaskStatustEnum.CANCEL.getStatus().equals(bpmResult) ? BpmTaskStatustEnum.CANCEL.getStatus() : null; Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); return auditStatus; } From b2b2b497b1ab7a87163e851b33df8384dc1a7259 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 18 Mar 2024 19:24:07 +0800 Subject: [PATCH 10/26] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=20task=20?= =?UTF-8?q?=E5=A7=94=E6=89=98=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/enums/task/BpmCommentTypeEnum.java | 14 +++++-- .../bpm/enums/task/BpmTaskStatustEnum.java | 6 +-- .../task/vo/task/BpmTaskDelegateReqVO.java | 3 +- .../bpm/service/task/BpmTaskServiceImpl.java | 42 +++++++------------ 4 files changed, 29 insertions(+), 36 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index f2c2ded53..c48b4f439 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.enums.task; +import cn.hutool.core.util.StrUtil; import lombok.AllArgsConstructor; import lombok.Getter; @@ -15,10 +16,11 @@ public enum BpmCommentTypeEnum { APPROVE("1", "审批通过", ""), // 理由:直接使用用户的评论 REJECT("2", "不通过", ""), CANCEL("3", "已取消", ""), - BACK("4", "退回", ""), // 理由:直接使用用户的评论 - DELEGATE("5", "委派", ""), - ADD_SIGN("6", "加签", "[{}]{}给了[{}],理由为:{}"), - SUB_SIGN("7", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), + BACK("4", "退回", "{}"), // 直接使用用户填写的原因 + DELEGATE_START("5", "委派发起", "[{}]将任务委派给[{}],委派理由为:{}"), + DELEGATE_END("6", "委派完成", "[{}]将任务委派给[{}],委派理由为:{}"), + ADD_SIGN("7", "加签", "[{}]{}给了[{}],理由为:{}"), + SUB_SIGN("8", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), ; /** @@ -36,4 +38,8 @@ public enum BpmCommentTypeEnum { */ private final String comment; + public String formatComment(Object... params) { + return StrUtil.format(comment, params); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java index ee06b0847..020ed3daf 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java @@ -18,9 +18,7 @@ public enum BpmTaskStatustEnum { REJECT(3, "审批不通过"), CANCEL(4, "已取消"), - // ========== 流程任务独有的状态 ========== - - BACK(5, "已驳回"), // 退回 + RETURN(5, "已退回"), DELEGATE(6, "委派中"), /** @@ -64,7 +62,7 @@ public enum BpmTaskStatustEnum { public static boolean isEndStatus(Integer status) { return ObjectUtils.equalsAny(status, APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus(), - BACK.getStatus(), APPROVING.getStatus()); + RETURN.getStatus(), APPROVING.getStatus()); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java index 2d1620661..cd1fce441 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDelegateReqVO.java @@ -1,10 +1,9 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; @Schema(description = "管理后台 - 委派流程任务的 Request VO") @Data 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 b0bc45e3f..915bc6162 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 @@ -285,21 +285,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) { // 1. 添加审批意见 AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()); - AdminUserRespDTO sourceApproveUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); - Assert.notNull(sourceApproveUser, "委派任务找不到原审批人,需要检查数据"); - String comment = StrUtil.format("[{}]完成委派任务,任务重新回到[{}]手中,审批意见为:{}", currentUser.getNickname(), - sourceApproveUser.getNickname(), reqVO.getReason()); - taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), - BpmCommentTypeEnum.DELEGATE.getType().toString(), comment); + AdminUserRespDTO ownerUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); // 发起委托的用户 + Assert.notNull(ownerUser, "委派任务找不到原审批人,需要检查数据"); + taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_END.getType(), + BpmCommentTypeEnum.DELEGATE_END.formatComment(currentUser.getNickname(), ownerUser.getNickname(), reqVO.getReason())); // 2.1 调用 resolveTask 完成任务。 // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee taskService.resolveTask(task.getId()); - // 2.2 更新任务拓展表为【处理中】 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.RUNNING.getResult()) -// .setReason(reqVO.getReason())); - updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); + // 2.2 更新 task 状态 + 原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus(), reqVO.getReason()); } @Override @@ -352,8 +347,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param status 状态 * @param reason 理由(审批通过、审批不通过的理由) */ - private void updateTaskStatus(String id, Integer status, String reason) { - taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_STATUS, status); + private void updateTaskStatusAndReason(String id, Integer status, String reason) { + updateTaskStatus(id, status); taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_REASON, reason); } @@ -585,10 +580,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } // 2.1 添加评论 - taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), - BpmCommentTypeEnum.BACK.getType(), reqVO.getReason()); + taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.BACK.getType(), + BpmCommentTypeEnum.BACK.formatComment(reqVO.getReason())); // 2.2 更新 task 状态 + 原因 - updateTaskStatus(task.getId(), BpmTaskStatustEnum.BACK.getStatus(), reqVO.getReason()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.RETURN.getStatus(), reqVO.getReason()); }); // 3. 执行驳回 @@ -602,6 +597,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override @Transactional(rollbackFor = Exception.class) public void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO) { + String taskId = reqVO.getId(); // 1.1 校验任务 Task task = validateTaskCanDelegate(userId, reqVO); // 1.2 校验目标用户存在 @@ -612,21 +608,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 添加审批意见 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); - String comment = StrUtil.format("[{}]将任务委派给[{}],委派理由为:{}", currentUser.getNickname(), - delegateUser.getNickname(), reqVO.getReason()); - String taskId = reqVO.getId(); - taskService.addComment(taskId, task.getProcessInstanceId(), - BpmCommentTypeEnum.DELEGATE.getType().toString(), comment); + taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START.getType(), + BpmCommentTypeEnum.DELEGATE_START.formatComment(currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason())); // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) taskService.setOwner(taskId, task.getAssignee()); // 3.2 执行委派,将任务委派给 receiveId taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString()); - // 3.3 更新任务拓展表为【委派】 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult()) -// .setReason(reqVO.getReason())); - updateTaskStatus(taskId, BpmTaskStatustEnum.DELEGATE.getStatus()); + // 3.3 更新 task 状态 + 原因 + updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.DELEGATE.getStatus(), reqVO.getReason()); } /** From bc4427aca54755bc2661bf0254acd46e2c351482 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 18 Mar 2024 20:44:44 +0800 Subject: [PATCH 11/26] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=20task=20?= =?UTF-8?q?=E8=BD=AC=E6=B4=BE=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 4 +- .../bpm/enums/task/BpmCommentTypeEnum.java | 7 +- .../admin/task/BpmTaskController.java | 18 +++--- ...eeReqVO.java => BpmTaskTransferReqVO.java} | 8 ++- .../bpm/service/task/BpmTaskService.java | 10 +-- .../bpm/service/task/BpmTaskServiceImpl.java | 64 +++++++++---------- 6 files changed, 55 insertions(+), 56 deletions(-) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/{BpmTaskUpdateAssigneeReqVO.java => BpmTaskTransferReqVO.java} (66%) 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 e88e27b1f..cb22e70fc 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 @@ -53,7 +53,9 @@ public interface ErrorCodeConstants { ErrorCode TASK_ADD_SIGN_USER_NOT_EXIST = new ErrorCode(1_009_005_009, "任务加签:选择的用户不存在"); ErrorCode TASK_ADD_SIGN_TYPE_ERROR = new ErrorCode(1_009_005_010, "任务加签:当前任务已经{},不能{}"); ErrorCode TASK_ADD_SIGN_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); - ErrorCode TASK_SUB_SIGN_NO_PARENT = new ErrorCode(1_009_005_011, "任务减签失败,被减签的任务必须是通过加签生成的任务"); + ErrorCode TASK_SUB_SIGN_NO_PARENT = new ErrorCode(1_009_005_012, "任务减签失败,被减签的任务必须是通过加签生成的任务"); + ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); + ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); // ========== 流程任务分配规则 1-009-006-000 TODO 芋艿:这里要改下 ========== ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index c48b4f439..8a7757cca 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -18,9 +18,10 @@ public enum BpmCommentTypeEnum { CANCEL("3", "已取消", ""), BACK("4", "退回", "{}"), // 直接使用用户填写的原因 DELEGATE_START("5", "委派发起", "[{}]将任务委派给[{}],委派理由为:{}"), - DELEGATE_END("6", "委派完成", "[{}]将任务委派给[{}],委派理由为:{}"), - ADD_SIGN("7", "加签", "[{}]{}给了[{}],理由为:{}"), - SUB_SIGN("8", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), + DELEGATE_END("6", "委派完成", "[{}]完成委派任务,任务重新回到[{}]手中,审批建议为:{}"), + TRANSFER("7", "转派", "[{}]将任务转派给[{}],转派理由为:{}"), + ADD_SIGN("8", "加签", "[{}]{}给了[{}],理由为:{}"), + SUB_SIGN("9", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"), ; /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index f18926582..151610e2b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -118,14 +118,6 @@ public class BpmTaskController { return success(true); } - @PutMapping("/update-assignee") - @Operation(summary = "更新任务的负责人", description = "用于【流程详情】的【转派】按钮") - @PreAuthorize("@ss.hasPermission('bpm:task:update')") - public CommonResult updateTaskAssignee(@Valid @RequestBody BpmTaskUpdateAssigneeReqVO reqVO) { - taskService.updateTaskAssignee(getLoginUserId(), reqVO); - return success(true); - } - @GetMapping("/list-by-return") @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") @Parameter(name = "taskId", description = "当前任务ID", required = true) @@ -145,13 +137,21 @@ public class BpmTaskController { } @PutMapping("/delegate") - @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮。和向前【加签】有点像,唯一区别是【委托】没有单独创立任务") + @Operation(summary = "委派任务", description = "用于【流程详情】的【委派】按钮") @PreAuthorize("@ss.hasPermission('bpm:task:update')") public CommonResult delegateTask(@Valid @RequestBody BpmTaskDelegateReqVO reqVO) { taskService.delegateTask(getLoginUserId(), reqVO); return success(true); } + @PutMapping("/transfer") + @Operation(summary = "转派任务", description = "用于【流程详情】的【转派】按钮") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult transferTask(@Valid @RequestBody BpmTaskTransferReqVO reqVO) { + taskService.transferTask(getLoginUserId(), reqVO); + return success(true); + } + @PutMapping("/create-sign") @Operation(summary = "加签", description = "before 前加签,after 后加签") @PreAuthorize("@ss.hasPermission('bpm:task:update')") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java similarity index 66% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java index 51c10bfc5..b388705ce 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTransferReqVO.java @@ -6,9 +6,9 @@ import lombok.Data; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -@Schema(description = "管理后台 - 流程任务的更新负责人的 Request VO") +@Schema(description = "管理后台 - 流程任务的转办 Request VO") @Data -public class BpmTaskUpdateAssigneeReqVO { +public class BpmTaskTransferReqVO { @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotEmpty(message = "任务编号不能为空") @@ -18,4 +18,8 @@ public class BpmTaskUpdateAssigneeReqVO { @NotNull(message = "新审批人的用户编号不能为空") private Long assigneeUserId; + @Schema(description = "转办原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "做不了决定,需要你先帮忙瞅瞅") + @NotEmpty(message = "转办原因不能为空") + private String reason; + } 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 6114a612b..1e60ce04f 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 @@ -87,15 +87,7 @@ public interface BpmTaskService { * @param userId 用户编号 * @param reqVO 分配请求 */ - void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO); - - /** - * 将流程任务分配给指定用户 - * - * @param id 流程任务编号 - * @param userId 用户编号 - */ - void updateTaskAssignee(String id, Long userId); + void transferTask(Long userId, BpmTaskTransferReqVO reqVO); /** * 创建 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 915bc6162..2044d9899 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 @@ -179,7 +179,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 情况三:审批普通的任务。大多数情况下,都是这样 // 3.1 更新 task 状态、原因 - updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus(), reqVO.getReason()); // 3.2 添加评论 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason()); @@ -317,19 +317,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { // .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); } - @Override - public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) { - // 校验任务存在 - Task task = validateTask(userId, reqVO.getId()); - // 更新负责人 - updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId()); - } - - @Override - public void updateTaskAssignee(String id, Long userId) { - taskService.setAssignee(id, String.valueOf(userId)); - } - /** * 更新流程任务的 status 状态 * @@ -599,41 +586,54 @@ public class BpmTaskServiceImpl implements BpmTaskService { public void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO) { String taskId = reqVO.getId(); // 1.1 校验任务 - Task task = validateTaskCanDelegate(userId, reqVO); + Task task = validateTask(userId, reqVO.getId()); + if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) { // 校验当前审批人和被委派人不是同一人 + throw exception(TASK_DELEGATE_FAIL_USER_REPEAT); + } // 1.2 校验目标用户存在 AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId()); if (delegateUser == null) { throw exception(TASK_DELEGATE_FAIL_USER_NOT_EXISTS); } - // 2. 添加审批意见 + // 2. 添加委托意见 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START.getType(), BpmCommentTypeEnum.DELEGATE_START.formatComment(currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason())); // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) taskService.setOwner(taskId, task.getAssignee()); - // 3.2 执行委派,将任务委派给 receiveId + // 3.2 执行委派,将任务委派给 delegateUser taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString()); - // 3.3 更新 task 状态 + 原因 - updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.DELEGATE.getStatus(), reqVO.getReason()); + // 3.3 更新 task 状态。 + // 为什么不更新原因?因为原因目前主要给审批通过、不通过时使用 + updateTaskStatus(taskId, BpmTaskStatustEnum.DELEGATE.getStatus()); } - /** - * 校验任务委派参数 - * - * @param userId 用户编号 - * @param reqVO 任务编号,接收人ID - * @return 当前任务信息 - */ - private Task validateTaskCanDelegate(Long userId, BpmTaskDelegateReqVO reqVO) { - // 校验任务 + @Override + public void transferTask(Long userId, BpmTaskTransferReqVO reqVO) { + String taskId = reqVO.getId(); + // 1.1 校验任务 Task task = validateTask(userId, reqVO.getId()); - // 校验当前审批人和被委派人不是同一人 - if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) { - throw exception(TASK_DELEGATE_FAIL_USER_REPEAT); + if (task.getAssignee().equals(reqVO.getAssigneeUserId().toString())) { // 校验当前审批人和被转派人不是同一人 + throw exception(TASK_TRANSFER_FAIL_USER_REPEAT); } - return task; + // 1.2 校验目标用户存在 + AdminUserRespDTO assigneeUser = adminUserApi.getUser(reqVO.getAssigneeUserId()); + if (assigneeUser == null) { + throw exception(TASK_TRANSFER_FAIL_USER_NOT_EXISTS); + } + + // 2. 添加委托意见 + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); + taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.TRANSFER.getType(), + BpmCommentTypeEnum.TRANSFER.formatComment(currentUser.getNickname(), assigneeUser.getNickname(), reqVO.getReason())); + + // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) + taskService.setOwner(taskId, task.getAssignee()); + // 3.2 执行转派(审批人),将任务转派给 assigneeUser + // 委托( delegate)和转派(transfer)的差别,就在这块的调用!!!! + taskService.setAssignee(taskId, reqVO.getAssigneeUserId().toString()); } @Override From 0a7f94dd5fe94b72fd14d362efa8fd7e3441dc20 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 18 Mar 2024 22:43:58 +0800 Subject: [PATCH 12/26] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=20task=20?= =?UTF-8?q?=E5=9C=A8=E9=80=9A=E8=BF=87=E3=80=81=E4=B8=8D=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E3=80=81=E5=8F=96=E6=B6=88=E7=AD=89=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=20reason=20=E5=92=8C=20comment=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/enums/task/BpmCommentTypeEnum.java | 8 +- .../bpm/enums/task/BpmDeleteReasonEnum.java | 44 ++++++ .../BpmProcessInstanceDeleteReasonEnum.java | 58 -------- .../BpmProcessInstanceEventListener.java | 4 +- .../core/listener/BpmTaskEventListener.java | 12 +- .../task/BpmProcessInstanceService.java | 6 +- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskService.java | 21 ++- .../bpm/service/task/BpmTaskServiceImpl.java | 130 +++++------------- 9 files changed, 100 insertions(+), 185 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index 8a7757cca..8b7b7ce11 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -13,10 +13,10 @@ import lombok.Getter; @AllArgsConstructor public enum BpmCommentTypeEnum { - APPROVE("1", "审批通过", ""), // 理由:直接使用用户的评论 - REJECT("2", "不通过", ""), - CANCEL("3", "已取消", ""), - BACK("4", "退回", "{}"), // 直接使用用户填写的原因 + APPROVE("1", "审批通过", "审批通过,原因是:{}"), + REJECT("2", "不通过", "审批不通过:原因是:{}"), + CANCEL("3", "已取消", "系统自动取消,原因是:{}"), + RETURN("4", "退回", "任务被退回,原因是:{}"), DELEGATE_START("5", "委派发起", "[{}]将任务委派给[{}],委派理由为:{}"), DELEGATE_END("6", "委派完成", "[{}]完成委派任务,任务重新回到[{}]手中,审批建议为:{}"), TRANSFER("7", "转派", "[{}]将任务转派给[{}],转派理由为:{}"), diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java new file mode 100644 index 000000000..ed07b330a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例/任务的删除原因枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmDeleteReasonEnum { + + // ========== 流程实例的独有原因 ========== + + REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法 + CANCEL_PROCESS_INSTANCE("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 + + // ========== 流程任务的独有原因 ========== + + CANCEL_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等 + ; + + private final String reason; + + /** + * 格式化理由 + * + * @param args 参数 + * @return 理由 + */ + public String format(Object... args) { + return StrUtil.format(reason, args); + } + + // ========== 逻辑 ========== + + public static boolean isRejectReason(String reason) { + return StrUtil.startWith(reason, "审批不通过任务,原因:"); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java deleted file mode 100644 index 4f99d0a3d..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.task; - -import cn.hutool.core.util.StrUtil; -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 流程实例的删除原因 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum BpmProcessInstanceDeleteReasonEnum { - - REJECT_TASK("不通过任务,原因:{}"), // 修改文案时,需要注意 isRejectReason 方法 - CANCEL_TASK("主动取消任务,原因:{}"), - - // ========== 流程任务的独有原因 ========== - MULTI_TASK_END("系统自动取消,原因:多任务审批已经满足条件,无需审批该任务"), // 多实例满足 condition 而结束时,其它任务实例任务会被取消,对应的删除原因是 MI_END - - ; - - private final String reason; - - /** - * 格式化理由 - * - * @param args 参数 - * @return 理由 - */ - public String format(Object... args) { - return StrUtil.format(reason, args); - } - - // ========== 逻辑 ========== - - public static boolean isRejectReason(String reason) { - return StrUtil.startWith(reason, "不通过任务,原因:"); - } - - /** - * 将 Flowable 的删除原因,翻译成对应的中文原因 - * - * @param reason 原始原因 - * @return 原因 - */ - public static String translateReason(String reason) { - if (StrUtil.isEmpty(reason)) { - return reason; - } - switch (reason) { - case "MI_END": return MULTI_TASK_END.getReason(); - default: return reason; - } - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java index f8e5920f1..cf1506e8d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java @@ -36,12 +36,12 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent @Override protected void processCancelled(FlowableCancelledEvent event) { - processInstanceService.updateProcessInstanceExtCancel(event); + processInstanceService.updateProcessInstanceWhenCancel(event); } @Override protected void processCompleted(FlowableEngineEntityEvent event) { - processInstanceService.updateProcessInstanceExtComplete((ProcessInstance)event.getEntity()); + processInstanceService.updateProcessInstanceWhenApprove((ProcessInstance)event.getEntity()); } } 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 7a647c205..a8f1788f3 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 @@ -31,7 +31,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; - @Resource @Lazy // 解决循环依赖 private BpmActivityService activityService; @@ -39,7 +38,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) +// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时,已经记录了 task 的 status 为通过,所以不需要监听了。 .add(FlowableEngineEventType.ACTIVITY_CANCELLED) .build(); @@ -49,12 +48,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { @Override protected void taskCreated(FlowableEngineEntityEvent event) { - taskService.createTaskExt((Task) event.getEntity()); - } - - @Override - protected void taskCompleted(FlowableEngineEntityEvent event) { - taskService.updateTaskExtComplete((Task)event.getEntity()); + taskService.updateTaskStatusWhenCreated((Task) event.getEntity()); } @Override @@ -74,7 +68,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { if (StrUtil.isEmpty(activity.getTaskId())) { return; } - taskService.updateTaskExtCancel(activity.getTaskId()); + taskService.updateTaskStatusWhenCanceled(activity.getTaskId()); }); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index bb94dd2e2..1e78c271e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -136,14 +136,14 @@ public interface BpmProcessInstanceService { * * @param event 流程取消事件 */ - void updateProcessInstanceExtCancel(FlowableCancelledEvent event); + void updateProcessInstanceWhenCancel(FlowableCancelledEvent event); /** * 更新 ProcessInstance 拓展记录为完成 * * @param instance 流程任务 */ - void updateProcessInstanceExtComplete(ProcessInstance instance); + void updateProcessInstanceWhenApprove(ProcessInstance instance); /** * 更新 ProcessInstance 拓展记录为不通过 @@ -151,7 +151,7 @@ public interface BpmProcessInstanceService { * @param id 流程编号 * @param reason 理由。例如说,审批不通过时,需要传递该值 */ - void updateProcessInstanceExtReject(String id, String reason); + void updateProcessInstanceReject(String id, String reason); // TODO @hai:改成 getProcessInstanceAssigneesByTaskDefinitionKey(String id, String taskDefinitionKey) /** 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 fa92e7e6e..6b81092ac 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 更新拓展表 runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file 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 1e60ce04f..4ec8272a5 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 @@ -90,25 +90,18 @@ public interface BpmTaskService { void transferTask(Long userId, BpmTaskTransferReqVO reqVO); /** - * 创建 Task 拓展记录 + * 更新 Task 状态,在创建时 * * @param task 任务实体 */ - void createTaskExt(Task task); + void updateTaskStatusWhenCreated(Task task); /** - * 更新 Task 拓展记录为完成 - * - * @param task 任务实体 - */ - void updateTaskExtComplete(Task task); - - /** - * 更新 Task 拓展记录为已取消 + * 更新 Task 状态,在取消时 * * @param taskId 任务的编号 */ - void updateTaskExtCancel(String taskId); + void updateTaskStatusWhenCanceled(String taskId); /** * 更新 Task 拓展记录,并发送通知 @@ -117,6 +110,12 @@ public interface BpmTaskService { */ void updateTaskExtAssign(Task task); + /** + * 获取任务 + * + * @param id 任务编号 + * @return 任务 + */ Task getTask(String id); /** 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 2044d9899..5c1de8a56 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 @@ -13,9 +13,7 @@ import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 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.enums.task.BpmCommentTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; -import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.task.*; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; @@ -181,8 +179,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3.1 更新 task 状态、原因 updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus(), reqVO.getReason()); // 3.2 添加评论 - taskService.addComment(task.getId(), task.getProcessInstanceId(), - BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason()); + taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), + BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 3.3 调用 BPM complete 去完成任务 taskService.complete(task.getId(), instance.getProcessVariables()); @@ -300,21 +298,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override @Transactional(rollbackFor = Exception.class) public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { + // 1.1 校验任务存在 Task task = validateTask(userId, reqVO.getId()); - // 校验流程实例存在 + // 1.2 校验流程实例存在 ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); if (instance == null) { throw exception(PROCESS_INSTANCE_NOT_EXISTS); } - // 更新流程实例为不通过 - updateTaskStatus(task.getId(), BpmTaskStatustEnum.REJECT.getStatus()); - processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason()); + // 2.1 更新流程实例为不通过 + updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.REJECT.getStatus(), reqVO.getReason()); + // 2.2 添加评论 + taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), + BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); -// // 更新任务拓展表为不通过 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult()) -// .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason())); + // 3. 更新流程实例,审批不通过! + processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); } /** @@ -354,112 +353,49 @@ public class BpmTaskServiceImpl implements BpmTaskService { } @Override - public void createTaskExt(Task task) { -// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) -// .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); -// // 向后加签生成的任务,状态不能为进行中,需要等前面父任务完成 -// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { -// taskExtDO.setResult(BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult()); -// } -// taskExtMapper.insert(taskExtDO); -// Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); -// if (status != null) { -// return; -// } -// -// status = BpmProcessInstanceResultEnum.RUNNING.getResult(); - // 向后加签生成的任务,状态不能为进行中,需要等前面父任务完成 -// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) { -// status = BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult(); -// } + public void updateTaskStatusWhenCreated(Task task) { + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (status != null) { + log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status); + return; + } updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); } @Override - public void updateTaskExtComplete(Task task) { -// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) -// .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置 -// .setEndTime(LocalDateTime.now()); -// taskExtMapper.updateByTaskId(taskExtDO); - - updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus()); - } - - @Override - public void updateTaskExtCancel(String taskId) { + public void updateTaskStatusWhenCanceled(String taskId) { Task task = getTask(taskId); - // 可能只是活动,不是任务,所以查询不到 + // 1. 可能只是活动,不是任务,所以查询不到 if (task == null) { - log.error("[updateTaskExtCancel][taskId({}) 任务不存在]", taskId); + log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", taskId); return; } + // 2. 更新 task 状态 + 原因 Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); if (BpmTaskStatustEnum.isEndStatus(status)) { - log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); + log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } - updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus()); - - if (true) { - return; - } - - // 需要在事务提交后,才进行查询。不然查询不到历史的原因 - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - - @Override - public void afterCommit() { - // 可能只是活动,不是任务,所以查询不到 - HistoricTaskInstance task = getHistoricTask(taskId); - if (task == null) { - return; - } - -// // 如果任务拓展表已经是完成的状态,则跳过 -// BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId); -// if (taskExt == null) { -// log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录,可能存在问题]", taskId); -// return; -// } -// // 如果已经是最终的结果,则跳过 -// if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) { -// log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, taskExt.getResult()); -// return; -// } - Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); - if (BpmTaskStatustEnum.isEndStatus(status)) { - log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status); - return; - } - - // 更新任务 -// taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) -// .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason()))); - updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus()); - } - - }); + updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_SYSTEM.getReason()); + // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 } @Override public void updateTaskExtAssign(Task task) { -// BpmTaskExtDO taskExtDO = -// new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId()); -// taskExtMapper.updateByTaskId(taskExtDO); - // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override public void afterCommit() { if (StrUtil.isNotEmpty(task.getAssignee())) { - ProcessInstance processInstance = - processInstanceService.getProcessInstance(task.getProcessInstanceId()); - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); - messageService.sendMessageWhenTaskAssigned( - BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); + return; } + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); } + }); } @@ -567,8 +503,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } // 2.1 添加评论 - taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.BACK.getType(), - BpmCommentTypeEnum.BACK.formatComment(reqVO.getReason())); + taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(), + BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason())); // 2.2 更新 task 状态 + 原因 updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.RETURN.getStatus(), reqVO.getReason()); }); From 8c32eb24ec7c649660271a0cc0f6f2544c4d9978 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 19 Mar 2024 01:31:37 +0800 Subject: [PATCH 13/26] =?UTF-8?q?BPM=EF=BC=9A=E4=BC=98=E5=8C=96=20task=20?= =?UTF-8?q?=E5=8A=A0=E5=87=8F=E7=AD=BE=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 8 +- ...TypeEnum.java => BpmTaskSignTypeEnum.java} | 26 +- .../bpm/enums/task/BpmTaskStatustEnum.java | 17 +- .../admin/task/BpmTaskController.java | 23 +- .../task/vo/task/BpmTaskAddSignReqVO.java | 30 -- .../task/vo/task/BpmTaskSignCreateReqVO.java | 29 ++ ...ReqVO.java => BpmTaskSignDeleteReqVO.java} | 10 +- .../bpm/convert/task/BpmTaskConvert.java | 72 +++-- .../bpm/service/task/BpmTaskService.java | 4 +- .../bpm/service/task/BpmTaskServiceImpl.java | 277 ++++++++---------- 10 files changed, 249 insertions(+), 247 deletions(-) rename yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/{BpmTaskAddSignTypeEnum.java => BpmTaskSignTypeEnum.java} (51%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/{BpmTaskSubSignReqVO.java => BpmTaskSignDeleteReqVO.java} (50%) 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 cb22e70fc..a689ad3e6 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 @@ -50,10 +50,10 @@ public interface ErrorCodeConstants { ErrorCode TASK_RETURN_FAIL_SOURCE_TARGET_ERROR = new ErrorCode(1_009_005_006, "回退任务失败,目标节点是在并行网关上或非同一路线上,不可跳转"); ErrorCode TASK_DELEGATE_FAIL_USER_REPEAT = new ErrorCode(1_009_005_007, "任务委派失败,委派人和当前审批人为同一人"); ErrorCode TASK_DELEGATE_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_008, "任务委派失败,被委派人不存在"); - ErrorCode TASK_ADD_SIGN_USER_NOT_EXIST = new ErrorCode(1_009_005_009, "任务加签:选择的用户不存在"); - ErrorCode TASK_ADD_SIGN_TYPE_ERROR = new ErrorCode(1_009_005_010, "任务加签:当前任务已经{},不能{}"); - ErrorCode TASK_ADD_SIGN_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); - ErrorCode TASK_SUB_SIGN_NO_PARENT = new ErrorCode(1_009_005_012, "任务减签失败,被减签的任务必须是通过加签生成的任务"); + ErrorCode TASK_SIGN_CREATE_USER_NOT_EXIST = new ErrorCode(1_009_005_009, "任务加签:选择的用户不存在"); + ErrorCode TASK_SIGN_CREATE_TYPE_ERROR = new ErrorCode(1_009_005_010, "任务加签:当前任务已经{},不能{}"); + ErrorCode TASK_SIGN_CREATE_USER_REPEAT = new ErrorCode(1_009_005_011, "任务加签失败,加签人与现有审批人[{}]重复"); + ErrorCode TASK_SIGN_DELETE_NO_PARENT = new ErrorCode(1_009_005_012, "任务减签失败,被减签的任务必须是通过加签生成的任务"); ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java similarity index 51% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java index 47e06bf6f..b01153d79 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskSignTypeEnum.java @@ -1,14 +1,17 @@ package cn.iocoder.yudao.module.bpm.enums.task; +import cn.hutool.core.util.ArrayUtil; import lombok.AllArgsConstructor; import lombok.Getter; /** - * 流程任务 -- 加签类型枚举类型 + * 流程任务的加签类型枚举 + * + * @author kehaiyou */ @Getter @AllArgsConstructor -public enum BpmTaskAddSignTypeEnum { +public enum BpmTaskSignTypeEnum { /** * 向前加签,需要前置任务审批完成,才回到原审批人 @@ -19,17 +22,26 @@ public enum BpmTaskAddSignTypeEnum { */ AFTER("after", "向后加签"); + /** + * 类型 + */ private final String type; + /** + * 名字 + */ + private final String name; - private final String desc; // TODO 芋艿:desc - - public static String formatDesc(String type) { - for (BpmTaskAddSignTypeEnum value : values()) { + public static String nameOfType(String type) { + for (BpmTaskSignTypeEnum value : values()) { if (value.type.equals(type)) { - return value.desc; + return value.name; } } return null; } + public static BpmTaskSignTypeEnum of(String type) { + return ArrayUtil.firstMatch(value -> value.getType().equals(type), values()); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java index 020ed3daf..eb4af0f62 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java @@ -22,23 +22,16 @@ public enum BpmTaskStatustEnum { DELEGATE(6, "委派中"), /** - * 【加签】源任务已经审批完成,但是它使用了后加签,后加签的任务未完成,源任务就会是这个状态 - * 相当于是 通过 APPROVE 的特殊状态 - * 例如:A 审批,A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” + * 使用场景: + * 1. 任务被向后【加签】时,它在审批通过后,会变成 APPROVING 这个状态,然后等到【加签】出来的任务都被审批后,才会变成 APPROVE 审批通过 */ APPROVING(7, "审批通过中"), /** - * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” - * 相当于是 处理中 PROCESS 的特殊状态 - * 例如:A 审批,A 前加签了 B,B 还未审核 + * 使用场景: + * 1. 任务被向前【加签】时,它会变成 WAIT 状态,需要等待【加签】出来的任务被审批后,它才能继续变为 RUNNING 继续审批 + * 2. 任务被向后【加签】时,【加签】出来的任务处于 WAIT 状态,它们需要等待该任务被审批后,它们才能继续变为 RUNNING 继续审批 */ WAIT(0, "待审批"); -// /** -// * 【加签】后加签任务被创建时的初始状态 -// * 相当于是 处理中 PROCESS 的特殊状态 -// * 因为需要源任务先完成,才能到后加签的人来审批,所以加了一个状态区分 -// */ -// WAIT_BEFORE_TASK(9, "处理中【待前置任务完成】"); /** * 状态 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index 151610e2b..6e17a0901 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -4,8 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; 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.service.task.BpmProcessInstanceService; @@ -94,7 +92,8 @@ public class BpmTaskController { // 拼接数据 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); // 获得 User 和 Dept Map - Set userIds = convertSet(taskList, task -> NumberUtils.parseLong(task.getAssignee())); + Set userIds = convertSetByFlatMap(taskList, task -> + Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); Map userMap = adminUserApi.getUserMap(userIds); Map deptMap = deptApi.getDeptMap( @@ -155,7 +154,7 @@ public class BpmTaskController { @PutMapping("/create-sign") @Operation(summary = "加签", description = "before 前加签,after 后加签") @PreAuthorize("@ss.hasPermission('bpm:task:update')") - public CommonResult createSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) { + public CommonResult createSignTask(@Valid @RequestBody BpmTaskSignCreateReqVO reqVO) { taskService.createSignTask(getLoginUserId(), reqVO); return success(true); } @@ -163,13 +162,12 @@ public class BpmTaskController { @DeleteMapping("/delete-sign") @Operation(summary = "减签") @PreAuthorize("@ss.hasPermission('bpm:task:update')") - public CommonResult deleteSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) { + public CommonResult deleteSignTask(@Valid @RequestBody BpmTaskSignDeleteReqVO reqVO) { taskService.deleteSignTask(getLoginUserId(), reqVO); return success(true); } - // TODO 芋艿:待测试 - @GetMapping("list-by-parent-task-id") + @GetMapping("/list-by-parent-task-id") @Operation(summary = "获得指定父级任务的子任务列表") // 目前用于,减签的时候,获得子任务列表 @Parameter(name = "parentTaskId", description = "父级任务编号", required = true) @PreAuthorize("@ss.hasPermission('bpm:task:query')") @@ -179,12 +177,11 @@ public class BpmTaskController { return success(Collections.emptyList()); } // 拼接数据 - Map userMap = adminUserApi.getUserMap( - convertSetByFlatMap(taskList, user -> Stream.of(Long.valueOf(user.getAssignee()), Long.valueOf(user.getOwner())))); - return success(convertList(taskList, task -> BeanUtils.toBean(task, BpmTaskRespVO.class, taskVO -> { - taskVO.setAssigneeUser(BeanUtils.toBean(userMap.get(NumberUtils.parseLong(task.getAssignee())), BpmProcessInstanceRespVO.User.class)); - taskVO.setOwnerUser(BeanUtils.toBean(userMap.get(NumberUtils.parseLong(task.getOwner())), BpmProcessInstanceRespVO.User.class)); - }))); + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(taskList, + user -> Stream.of(NumberUtils.parseLong(user.getAssignee()), NumberUtils.parseLong(user.getOwner())))); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmTaskConvert.INSTANCE.buildTaskListByParentTaskId(taskList, userMap, deptMap)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java deleted file mode 100644 index 68369696b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import jakarta.validation.constraints.NotEmpty; -import java.util.Set; - -// TODO @海洋:类名,应该是 create 哈 -@Schema(description = "管理后台 - 加签流程任务的 Request VO") -@Data -public class BpmTaskAddSignReqVO { - - @Schema(description = "需要加签的任务 ID") - @NotEmpty(message = "任务编号不能为空") - private String id; - - @Schema(description = "加签的用户 ID") - @NotEmpty(message = "加签用户 ID 不能为空") - private Set userIdList; - - @Schema(description = "加签类型,before 向前加签,after 向后加签") - @NotEmpty(message = "加签类型不能为空") - private String type; - - @Schema(description = "加签原因") - @NotEmpty(message = "加签原因不能为空") - private String reason; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java new file mode 100644 index 000000000..71278b37f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignCreateReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; +import java.util.Set; + +@Schema(description = "管理后台 - 加签任务的创建(加签) Request VO") +@Data +public class BpmTaskSignCreateReqVO { + + @Schema(description = "需要加签的任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @Schema(description = "加签的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotEmpty(message = "加签用户不能为空") + private Set userIds; + + @Schema(description = "加签类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "before") + @NotEmpty(message = "加签类型不能为空") + private String type; // 参见 BpmTaskSignTypeEnum 枚举 + + @Schema(description = "加签原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "需要加签") + @NotEmpty(message = "加签原因不能为空") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java similarity index 50% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java index a2966a399..9ea8a105b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSignDeleteReqVO.java @@ -5,16 +5,16 @@ import lombok.Data; import jakarta.validation.constraints.NotEmpty; -// TODO @海洋:类名,应该是 delete 哈 -@Schema(description = "管理后台 - 减签流程任务的 Request VO") +@Schema(description = "管理后台 - 加签任务的删除(减签) Request VO") @Data -public class BpmTaskSubSignReqVO { +public class BpmTaskSignDeleteReqVO { - @Schema(description = "被减签的任务 ID") + @Schema(description = "被减签的任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotEmpty(message = "任务编号不能为空") private String id; - @Schema(description = "加签原因") + @Schema(description = "加签原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "需要减签") @NotEmpty(message = "加签原因不能为空") private String reason; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index ee7b5245c..e9f04f498 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -24,8 +24,7 @@ import java.util.Date; import java.util.List; import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; /** * Bpm 任务 Convert @@ -91,6 +90,14 @@ public interface BpmTaskConvert { taskVO.getAssigneeUser().setDeptName(dept.getName()); } } + AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); + if (ownerUser != null) { + taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); + if (dept != null) { + taskVO.getOwnerUser().setDeptName(dept.getName()); + } + } return taskVO; }); @@ -104,6 +111,29 @@ public interface BpmTaskConvert { return filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId())); } + default List buildTaskListByParentTaskId(List taskList, + Map userMap, + Map deptMap) { + return convertList(taskList, task -> BeanUtils.toBean(task, BpmTaskRespVO.class, taskVO -> { + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); + if (dept != null) { + taskVO.getAssigneeUser().setDeptName(dept.getName()); + } + } + AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); + if (ownerUser != null) { + taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); + DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); + if (dept != null) { + taskVO.getOwnerUser().setDeptName(dept.getName()); + } + } + })); + } + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) { BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); @@ -114,22 +144,28 @@ public interface BpmTaskConvert { return reqDTO; } - //此处不用 mapstruct 映射,因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的 - //使用 mapstruct 会将里面嵌套的各个属性值都设置进去,会出现意想不到的问题 - default TaskEntityImpl convert(TaskEntityImpl task,TaskEntityImpl parentTask){ - task.setCategory(parentTask.getCategory()); - task.setDescription(parentTask.getDescription()); - task.setTenantId(parentTask.getTenantId()); - task.setName(parentTask.getName()); - task.setParentTaskId(parentTask.getId()); - task.setProcessDefinitionId(parentTask.getProcessDefinitionId()); - task.setProcessInstanceId(parentTask.getProcessInstanceId()); -// task.setExecutionId(parentTask.getExecutionId()); // TODO 芋艿:新加的,不太确定;尴尬,不加时,子任务不通过会失败(报错);加了,子任务审批通过会失败(报错) - task.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); - task.setTaskDefinitionId(parentTask.getTaskDefinitionId()); - task.setPriority(parentTask.getPriority()); - task.setCreateTime(new Date()); - return task; + /** + * 将父任务的属性,拷贝到子任务(加签任务) + * + * 为什么不使用 mapstruct 映射?因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的。 + * 使用 mapstruct 会将里面嵌套的各个属性值都设置进去,会出现意想不到的问题。 + * + * @param parentTask 父任务 + * @param childTask 加签任务 + */ + default void copyTo(TaskEntityImpl parentTask, TaskEntityImpl childTask) { + childTask.setName(parentTask.getName()); + childTask.setDescription(parentTask.getDescription()); + childTask.setCategory(parentTask.getCategory()); + childTask.setParentTaskId(parentTask.getId()); + childTask.setProcessDefinitionId(parentTask.getProcessDefinitionId()); + childTask.setProcessInstanceId(parentTask.getProcessInstanceId()); +// childTask.setExecutionId(parentTask.getExecutionId()); // TODO 芋艿:新加的,不太确定;尴尬,不加时,子任务不通过会失败(报错);加了,子任务审批通过会失败(报错) + childTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); + childTask.setTaskDefinitionId(parentTask.getTaskDefinitionId()); + childTask.setPriority(parentTask.getPriority()); + childTask.setCreateTime(new Date()); + childTask.setTenantId(parentTask.getTenantId()); } } 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 4ec8272a5..83bb3eb0a 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 @@ -148,7 +148,7 @@ public interface BpmTaskService { * @param userId 被加签的用户和任务 ID,加签类型 * @param reqVO 当前用户 ID */ - void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO); + void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO); /** * 任务减签 @@ -156,7 +156,7 @@ public interface BpmTaskService { * @param userId 当前用户ID * @param reqVO 被减签的任务 ID,理由 */ - void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO); + void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO); /** * 获取指定任务的子任务列表 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 5c1de8a56..aa1fc6345 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 @@ -13,7 +13,10 @@ import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 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.enums.task.*; +import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; @@ -44,10 +47,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.util.Assert; import java.util.*; +import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** @@ -170,7 +173,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 情况二:审批有【后】加签的任务 - if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(task.getScopeType())) { + if (BpmTaskSignTypeEnum.AFTER.getType().equals(task.getScopeType())) { approveAfterSignTask(task, reqVO); return; } @@ -191,29 +194,23 @@ public class BpmTaskServiceImpl implements BpmTaskService { /** * 审批通过存在“后加签”的任务。 *

- * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理 + * 注意:该任务不能马上完成,需要一个中间状态(APPROVING),并激活剩余所有子任务(PROCESS)为可审批处理 + * 如果马上完成,则会触发下一个任务,甚至如果没有下一个任务则流程实例就直接结束了! * * @param task 当前任务 * @param reqVO 前端请求参数 */ private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { - // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult()) -// .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); - // TODO @芋艿:reqVO.reason??? - updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVING.getStatus()); + // 更新父 task 状态 + 原因 + updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVING.getStatus(), reqVO.getReason()); // 2. 激活子任务 - List childrenTaskIdList = getChildrenTaskIdList(task.getId()); - for (String childrenTaskId : childrenTaskIdList) { - taskService.resolveTask(childrenTaskId); - // 更新任务扩展表中子任务为进行中 - updateTaskStatus(childrenTaskId, BpmTaskStatustEnum.RUNNING.getStatus()); + List childrenTaskList = getTaskListByParentTaskId(task.getId()); + for (Task childrenTask : childrenTaskList) { + taskService.resolveTask(childrenTask.getId()); + // 更新子 task 状态 + updateTaskStatus(childrenTask.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); } - // 2.1 更新任务扩展表中子任务为进行中 -// taskExtMapper.updateBatchByTaskIdList(childrenTaskIdList, -// new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); } /** @@ -229,14 +226,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } // 1.1 判断是否还有子任务。如果没有,就不处理 - Long childrenTaskCount = getChildrenTaskCount(parentTaskId); + Long childrenTaskCount = getTaskCountByParentTaskId(parentTaskId); if (childrenTaskCount > 0) { return; } // 1.2 只处理加签的父任务 Task parentTask = validateTaskExist(parentTaskId); String scopeType = parentTask.getScopeType(); - if (!validateSignType(scopeType)){ + if (BpmTaskSignTypeEnum.of(scopeType) == null){ return; } @@ -246,14 +243,20 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.saveTask(parentTaskImpl); // 3.1 情况一:处理向【向前】加签 - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { + if (BpmTaskSignTypeEnum.BEFORE.getType().equals(scopeType)) { // 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批 taskService.resolveTask(parentTaskId); // 3.1.2 更新流程任务 status updateTaskStatus(parentTaskId, BpmTaskStatustEnum.RUNNING.getStatus()); // 3.2 情况二:处理向【向后】加签 - } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { - // 3.2.1 完成自己(因为它已经没有子任务,所以也可以完成) + } else if (BpmTaskSignTypeEnum.AFTER.getType().equals(scopeType)) { + // 只有 parentTask 处于 APPROVING 的情况下,才可以继续 complete 完成 + // 否则,一个未审批的 parentTask 任务,在加签出来的任务都被减签的情况下,就直接完成审批,这样会存在问题 + Integer status = (Integer) parentTask.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); + if (ObjectUtil.notEqual(status, BpmTaskStatustEnum.APPROVING.getStatus())) { + return; + } + // 3.2.2 完成自己(因为它已经没有子任务,所以也可以完成) updateTaskStatus(parentTaskId, BpmTaskStatustEnum.APPROVE.getStatus()); taskService.complete(parentTaskId); } @@ -262,18 +265,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { handleParentTaskIfSign(parentTask.getParentTaskId()); } - /** - * 获取子任务个数 - * - * @param parentTaskId 父任务 ID - * @return 剩余子任务个数 - */ - private Long getChildrenTaskCount(String parentTaskId) { - String tableName = managementService.getTableName(TaskEntity.class); - String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}"; - return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count(); - } - /** * 审批被委派的任务 * @@ -339,7 +330,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } /** - * 校验任务是否存在, 并且是否是分配给自己的任务 + * 校验任务是否存在,并且是否是分配给自己的任务 * * @param userId 用户 id * @param taskId task id @@ -388,7 +379,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public void afterCommit() { - if (StrUtil.isNotEmpty(task.getAssignee())) { + if (StrUtil.isEmpty(task.getAssignee())) { return; } ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); @@ -574,52 +565,45 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override @Transactional(rollbackFor = Exception.class) - public void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO) { + public void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO) { // 1. 获取和校验任务 - TaskEntityImpl taskEntity = validateAddSign(userId, reqVO); - List userList = adminUserApi.getUserList(reqVO.getUserIdList()); + TaskEntityImpl taskEntity = validateTaskCanCreateSign(userId, reqVO); + List userList = adminUserApi.getUserList(reqVO.getUserIds()); if (CollUtil.isEmpty(userList)) { - throw exception(TASK_ADD_SIGN_USER_NOT_EXIST); + throw exception(TASK_SIGN_CREATE_USER_NOT_EXIST); } // 2. 处理当前任务 // 2.1 开启计数功能,主要用于为了让表 ACT_RU_TASK 中的 SUB_TASK_COUNT_ 字段记录下总共有多少子任务,后续可能有用 taskEntity.setCountEnabled(true); - if (reqVO.getType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) { - // 2.2 向前加签,设置 owner,置空 assign。等子任务都完成后,再调用 resolveTask 重新将 owner 设置为 assign - // 原因是:不能和向前加签的子任务一起审批,需要等前面的子任务都完成才能审批 + // 2.2 向前加签,设置 owner,置空 assign。等子任务都完成后,再调用 resolveTask 重新将 owner 设置为 assign + // 原因是:不能和向前加签的子任务一起审批,需要等前面的子任务都完成才能审批 + if (reqVO.getType().equals(BpmTaskSignTypeEnum.BEFORE.getType())) { taskEntity.setOwner(taskEntity.getAssignee()); taskEntity.setAssignee(null); - // 2.3 更新扩展表状态 -// taskExtMapper.updateByTaskId( -// new BpmTaskExtDO().setTaskId(taskEntity.getId()) -// .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()) -// .setReason(reqVO.getReason())); -// taskEntity.setTransientVariableLocal(BpmConstants.TASK_VARIABLE_STATUS, BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()); -// updateTaskStatus(taskEntity.getId(), BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()); // TODO 芋艿:貌似会有实物并发的问题;所以不能用这个调用,只能 set } // 2.4 记录加签方式,完成任务时需要用到判断 taskEntity.setScopeType(reqVO.getType()); // 2.5 保存当前任务修改后的值 taskService.saveTask(taskEntity); - if (reqVO.getType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) { - updateTaskStatus(taskEntity.getId(), BpmTaskStatustEnum.WAIT.getStatus()); // TODO 芋艿:貌似只能放在这个地方,不然会有并发修改的报错 + // 2.6 更新 task 状态为 WAIT,只有在向前加签的时候 + if (reqVO.getType().equals(BpmTaskSignTypeEnum.BEFORE.getType())) { + updateTaskStatus(taskEntity.getId(), BpmTaskStatustEnum.WAIT.getStatus()); } // 3. 创建加签任务 - createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); + createSignTaskList(convertList(reqVO.getUserIds(), String::valueOf), taskEntity); - // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason + // 4. 记录加签的评论到 task 任务 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); - String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(), - BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); - taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), - BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment); + String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), + currentUser.getNickname(), BpmTaskSignTypeEnum.nameOfType(reqVO.getType()), + String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); + taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), BpmCommentTypeEnum.ADD_SIGN.getType(), comment); } - /** - * 校验任务的加签是否一致 + * 校验任务是否可以加签,主要校验加签类型是否一致: *

* 1. 如果存在“向前加签”的任务,则不能“向后加签” * 2. 如果存在“向后加签”的任务,则不能“向前加签” @@ -628,24 +612,23 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param reqVO 请求参数,包含任务 ID 和加签类型 * @return 当前任务 */ - private TaskEntityImpl validateAddSign(Long userId, BpmTaskAddSignReqVO reqVO) { + private TaskEntityImpl validateTaskCanCreateSign(Long userId, BpmTaskSignCreateReqVO reqVO) { TaskEntityImpl taskEntity = (TaskEntityImpl) validateTask(userId, reqVO.getId()); // 向前加签和向后加签不能同时存在 if (taskEntity.getScopeType() != null && ObjectUtil.notEqual(taskEntity.getScopeType(), reqVO.getType())) { - throw exception(TASK_ADD_SIGN_TYPE_ERROR, - BpmTaskAddSignTypeEnum.formatDesc(taskEntity.getScopeType()), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType())); + throw exception(TASK_SIGN_CREATE_TYPE_ERROR, + BpmTaskSignTypeEnum.nameOfType(taskEntity.getScopeType()), BpmTaskSignTypeEnum.nameOfType(reqVO.getType())); } // 同一个 key 的任务,审批人不重复 List taskList = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()) .taskDefinitionKey(taskEntity.getTaskDefinitionKey()).list(); - List currentAssigneeList = convertList(taskList, task -> NumberUtils.parseLong(task.getAssignee())); - // 保留交集在 currentAssigneeList 中 - currentAssigneeList.retainAll(reqVO.getUserIdList()); - if (CollUtil.isNotEmpty(currentAssigneeList)) { - List userList = adminUserApi.getUserList(currentAssigneeList); - throw exception(TASK_ADD_SIGN_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname))); + List currentAssigneeList = convertListByFlatMap(taskList, task -> // 需要考虑 owner 的情况,因为向后加签时,它暂时没 assignee 而是 owner + Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); + if (CollUtil.containsAny(currentAssigneeList, reqVO.getUserIds())) { + List userList = adminUserApi.getUserList( CollUtil.intersection(currentAssigneeList, reqVO.getUserIds())); + throw exception(TASK_SIGN_CREATE_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname))); } return taskEntity; } @@ -653,15 +636,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { /** * 创建加签子任务 * - * @param addSingUserIdList 被加签的用户 ID + * @param userIds 被加签的用户 ID * @param taskEntity 被加签的任务 */ - private void createSignTask(List addSingUserIdList, TaskEntityImpl taskEntity) { - if (CollUtil.isEmpty(addSingUserIdList)) { + private void createSignTaskList(List userIds, TaskEntityImpl taskEntity) { + if (CollUtil.isEmpty(userIds)) { return; } // 创建加签人的新任务,全部基于 taskEntity 为父任务来创建 - for (String addSignId : addSingUserIdList) { + for (String addSignId : userIds) { if (StrUtil.isBlank(addSignId)) { continue; } @@ -678,31 +661,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { private void createSignTask(TaskEntityImpl parentTask, String assignee) { // 1. 生成子任务 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); - task = BpmTaskConvert.INSTANCE.convert(task, parentTask); - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) { - // 2.1 前加签,设置审批人 + BpmTaskConvert.INSTANCE.copyTo(parentTask, task); + + // 2.1 向前加签,设置审批人 + if (BpmTaskSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) { task.setAssignee(assignee); + // 2.2 向后加签,设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 } else { - // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成 task.setOwner(assignee); - // 2.2.2 设置向后加签任务的 scopeType 为 afterChildrenTask,用于设置任务扩展表的状态 -// task.setScopeType(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType()); -// task.setVariableLocal(BpmConstants.TASK_VARIABLE_STATUS, BpmProcessInstanceResultEnum.WAIT.getResult()); } - // 2. 保存子任务 + // 2.3 保存子任务 taskService.saveTask(task); - // 3. TODO - if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { + + // 3. 向后前签,设置子任务的状态为 WAIT,因为需要等父任务审批完 + if (BpmTaskSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { updateTaskStatus(task.getId(), BpmTaskStatustEnum.WAIT.getStatus()); } } @Override @Transactional(rollbackFor = Exception.class) - public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { + public void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO) { // 1.1 校验 task 可以被减签 -// Task task = validateSubSign(reqVO.getId()); // TODO 芋艿:这个判断,暂时有点问题!在前置加签的时候 - Task task = validateTaskExist(reqVO.getId()); + Task task = validateTaskCanSignDelete(reqVO.getId()); // 1.2 校验取消人存在 AdminUserRespDTO cancelUser = null; if (StrUtil.isNotBlank(task.getAssignee())) { @@ -713,21 +694,19 @@ public class BpmTaskServiceImpl implements BpmTaskService { } Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); - // 2. 删除任务和对应子任务 - // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 - List allTaskIdList = getAllChildTaskIds(task.getId()); + // 2.1 获得子任务列表,包括子任务的子任务 + List childTaskList = getAllChildTaskList(task); + childTaskList.add(task); + // 2.2 更新子任务为已取消 + String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname()); + childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatustEnum.CANCEL.getStatus(), cancelReason)); // 2.2 删除任务和所有子任务 - taskService.deleteTasks(allTaskIdList); - // 2.3 修改扩展表状态为取消 -// taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) -// .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); -// allTaskIdList.forEach(taskId -> updateTaskStatus(taskId, BpmProcessInstanceResultEnum.CANCEL.getResult())); // TODO @芋艿:交给取消;考虑到理由,可能不能直接给; + taskService.deleteTasks(convertList(childTaskList, Task::getId)); // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 AdminUserRespDTO user = adminUserApi.getUser(userId); - String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname()); - taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), - BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); + taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType(), + StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname())); // 4. 处理当前任务的父任务 handleParentTaskIfSign(task.getParentTaskId()); @@ -736,86 +715,72 @@ public class BpmTaskServiceImpl implements BpmTaskService { /** * 校验任务是否能被减签 * - * @param id 任务ID + * @param id 任务编号 * @return 任务信息 */ - private Task validateSubSign(String id) { + private Task validateTaskCanSignDelete(String id) { Task task = validateTaskExist(id); - - // 必须有 scopeType - String scopeType = task.getScopeType(); - if (StrUtil.isEmpty(scopeType)) { - throw exception(TASK_SUB_SIGN_NO_PARENT); + if (task.getParentTaskId() == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); } - // 并且值为 向前和向后加签 - if (!validateSignType(scopeType)) { - throw exception(TASK_SUB_SIGN_NO_PARENT); + Task parentTask = getTask(task.getParentTaskId()); + if (parentTask == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); + } + if (BpmTaskSignTypeEnum.of(parentTask.getScopeType()) == null) { + throw exception(TASK_SIGN_DELETE_NO_PARENT); } return task; } /** - * 判断当前类型是否为加签 - * @param scopeType 任务的 scopeType - * @return 当前 scopeType 为加签则返回 true - */ - private boolean validateSignType(String scopeType){ - return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType()); - } - -// TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务 - /** - * 获取所有要被取消的删除的任务 ID 集合 + * 获得所有子任务列表 * - * @param parentTaskId 父级任务ID - * @return 所有任务ID + * @param parentTask 父任务 + * @return 所有子任务列表 */ - public List getAllChildTaskIds(String parentTaskId) { - List allChildTaskIds = new ArrayList<>(); + private List getAllChildTaskList(Task parentTask) { + List result = new ArrayList<>(); // 1. 递归获取子级 - Stack stack = new Stack<>(); - // 1.1 将根任务ID入栈 - stack.push(parentTaskId); - //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环 - int count = 0; - // TODO @海:< 的前后空格,要注意哈; - while (!stack.isEmpty() && count childrenTaskIdList = getChildrenTaskIdList(taskId); - if (CollUtil.isNotEmpty(childrenTaskIdList)) { - for (String childTaskId : childrenTaskIdList) { - // 1.5 将子任务ID入栈,以便后续处理 - stack.push(childTaskId); - } + Stack stack = new Stack<>(); + stack.push(parentTask); + // 2. 递归遍历 + for (int i = 0; i < Short.MAX_VALUE; i++) { + if (stack.isEmpty()) { + break; + } + // 2.1 获取子任务们 + Task task = stack.pop(); + List childTaskList = getTaskListByParentTaskId(task.getId()); + // 2.2 如果非空,则添加到 stack 进一步递归 + if (CollUtil.isNotEmpty(childTaskList)) { + stack.addAll(childTaskList); + result.addAll(childTaskList); } - count++; } - return allChildTaskIds; - } - - /** - * 获取指定父级任务的所有子任务 ID 集合 - * - * @param parentTaskId 父任务 ID - * @return 所有子任务的 ID 集合 - */ - private List getChildrenTaskIdList(String parentTaskId) { - return convertList(getTaskListByParentTaskId(parentTaskId), Task::getId); + return result; } @Override public List getTaskListByParentTaskId(String parentTaskId) { String tableName = managementService.getTableName(TaskEntity.class); // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询 - String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; + String sql = "select ID_,NAME_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); } + /** + * 获取子任务个数 + * + * @param parentTaskId 父任务 ID + * @return 剩余子任务个数 + */ + private Long getTaskCountByParentTaskId(String parentTaskId) { + String tableName = managementService.getTableName(TaskEntity.class); + String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}"; + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count(); + } + @Override public Map getTaskNameByTaskIds(Collection taskIds) { if (CollUtil.isEmpty(taskIds)) { From d5e28d4c57315d1dd885d3713659b1bf5ad55f62 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 19 Mar 2024 12:13:49 +0800 Subject: [PATCH 14/26] =?UTF-8?q?BPM=EF=BC=9A=E7=AE=80=E5=8C=96=20userGrou?= =?UTF-8?q?p=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmUserGroupController.java | 38 +++++++++---------- .../vo/group/BpmUserGroupCreateReqVO.java | 11 ------ .../vo/group/BpmUserGroupPageReqVO.java | 3 ++ .../vo/group/BpmUserGroupRespVO.java | 19 ++++++++-- ...BaseVO.java => BpmUserGroupSaveReqVO.java} | 20 +++++----- .../vo/group/BpmUserGroupSimpleRespVO.java | 20 ---------- .../vo/group/BpmUserGroupUpdateReqVO.java | 17 --------- .../definition/BpmUserGroupConvert.java | 38 ------------------- .../dataobject/definition/BpmUserGroupDO.java | 2 +- .../BpmTaskCandidateGroupStrategy.java | 2 +- .../definition/BpmUserGroupService.java | 7 ++-- .../definition/BpmUserGroupServiceImpl.java | 26 ++++++------- .../BpmTaskCandidateGroupStrategyTest.java | 4 +- .../definition/BpmUserGroupServiceTest.java | 4 +- 14 files changed, 65 insertions(+), 146 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/{BpmUserGroupBaseVO.java => BpmUserGroupSaveReqVO.java} (64%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java index 82404b925..64b80345c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java @@ -1,27 +1,27 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - 用户组") @RestController @@ -35,14 +35,14 @@ public class BpmUserGroupController { @PostMapping("/create") @Operation(summary = "创建用户组") @PreAuthorize("@ss.hasPermission('bpm:user-group:create')") - public CommonResult createUserGroup(@Valid @RequestBody BpmUserGroupCreateReqVO createReqVO) { + public CommonResult createUserGroup(@Valid @RequestBody BpmUserGroupSaveReqVO createReqVO) { return success(userGroupService.createUserGroup(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新用户组") @PreAuthorize("@ss.hasPermission('bpm:user-group:update')") - public CommonResult updateUserGroup(@Valid @RequestBody BpmUserGroupUpdateReqVO updateReqVO) { + public CommonResult updateUserGroup(@Valid @RequestBody BpmUserGroupSaveReqVO updateReqVO) { userGroupService.updateUserGroup(updateReqVO); return success(true); } @@ -62,7 +62,7 @@ public class BpmUserGroupController { @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") public CommonResult getUserGroup(@RequestParam("id") Long id) { BpmUserGroupDO userGroup = userGroupService.getUserGroup(id); - return success(BpmUserGroupConvert.INSTANCE.convert(userGroup)); + return success(BeanUtils.toBean(userGroup, BpmUserGroupRespVO.class)); } @GetMapping("/page") @@ -70,16 +70,14 @@ public class BpmUserGroupController { @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") public CommonResult> getUserGroupPage(@Valid BpmUserGroupPageReqVO pageVO) { PageResult pageResult = userGroupService.getUserGroupPage(pageVO); - return success(BpmUserGroupConvert.INSTANCE.convertPage(pageResult)); + return success(BeanUtils.toBean(pageResult, BpmUserGroupRespVO.class)); } - @GetMapping("/list-all-simple") + @GetMapping("/simple-list") @Operation(summary = "获取用户组精简信息列表", description = "只包含被开启的用户组,主要用于前端的下拉选项") - public CommonResult> getSimpleUserGroups() { - // 获用户门列表,只要开启状态的 + public CommonResult> getUserGroupSimpleList() { List list = userGroupService.getUserGroupListByStatus(CommonStatusEnum.ENABLE.getStatus()); - // 排序后,返回给前端 - return success(BpmUserGroupConvert.INSTANCE.convertList2(list)); + return success(convertList(list, group -> new BpmUserGroupRespVO().setId(group.getId()).setName(group.getName()))); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java deleted file mode 100644 index 416c4793a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -@Schema(description = "管理后台 - 用户组创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmUserGroupCreateReqVO extends BpmUserGroupBaseVO { - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java index 05f17788a..499e47a42 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java @@ -16,6 +16,9 @@ import java.time.LocalDateTime; @ToString(callSuper = true) public class BpmUserGroupPageReqVO extends PageParam { + @Schema(description = "编号", example = "1024") + private Long id; + @Schema(description = "组名", example = "芋道") private String name; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java index 0f89e9538..f20722a8d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java @@ -1,19 +1,30 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; import java.time.LocalDateTime; +import java.util.Set; @Schema(description = "管理后台 - 用户组 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmUserGroupRespVO extends BpmUserGroupBaseVO { +public class BpmUserGroupRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; + @Schema(description = "组名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String description; + + @Schema(description = "成员编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + private Set userIds; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java similarity index 64% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java index efe1155c3..1993cdba0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSaveReqVO.java @@ -1,29 +1,27 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; - import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - import jakarta.validation.constraints.NotNull; +import lombok.*; + import java.util.Set; -/** -* 用户组 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ +@Schema(description = "管理后台 - 用户组创建/修改 Request VO") @Data -public class BpmUserGroupBaseVO { +public class BpmUserGroupSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; @Schema(description = "组名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") @NotNull(message = "组名不能为空") private String name; - @Schema(description = "描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") - @NotNull(message = "描述不能为空") + @Schema(description = "描述", example = "芋道源码") private String description; @Schema(description = "成员编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") @NotNull(message = "成员编号数组不能为空") - private Set memberUserIds; + private Set userIds; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "状态不能为空") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java deleted file mode 100644 index e5e2060bb..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Schema(description = "管理后台 - 用户组精简信息 Response VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class BpmUserGroupSimpleRespVO { - - @Schema(description = "用户组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long id; - - @Schema(description = "用户组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java deleted file mode 100644 index 02bb2b31c..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import jakarta.validation.constraints.*; - -@Schema(description = "管理后台 - 用户组更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmUserGroupUpdateReqVO extends BpmUserGroupBaseVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "编号不能为空") - private Long id; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java deleted file mode 100644 index bbf00ba52..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.definition; - -import java.util.*; - -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import org.mapstruct.Mapper; -import org.mapstruct.Named; -import org.mapstruct.factory.Mappers; - -/** - * 用户组 Convert - * - * @author 芋道源码 - */ -@Mapper -public interface BpmUserGroupConvert { - - BpmUserGroupConvert INSTANCE = Mappers.getMapper(BpmUserGroupConvert.class); - - BpmUserGroupDO convert(BpmUserGroupCreateReqVO bean); - - BpmUserGroupDO convert(BpmUserGroupUpdateReqVO bean); - - BpmUserGroupRespVO convert(BpmUserGroupDO bean); - - List convertList(List list); - - PageResult convertPage(PageResult page); - - @Named("convertList2") - List convertList2(List list); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java index ec1168180..6e209e241 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java @@ -47,6 +47,6 @@ public class BpmUserGroupDO extends BaseDO { * 成员用户编号数组 */ @TableField(typeHandler = JsonLongSetTypeHandler.class) - private Set memberUserIds; + private Set userIds; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java index b8fa00f84..bc161886b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java @@ -41,7 +41,7 @@ public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy { public Set calculateUsers(DelegateExecution execution, String param) { Set groupIds = StrUtils.splitToLongSet(param); List groups = userGroupService.getUserGroupList(groupIds); - return convertSetByFlatMap(groups, BpmUserGroupDO::getMemberUserIds, Collection::stream); + return convertSetByFlatMap(groups, BpmUserGroupDO::getUserIds, Collection::stream); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java index 6ae6e06ca..a95dc24da 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import jakarta.validation.Valid; @@ -23,14 +22,14 @@ public interface BpmUserGroupService { * @param createReqVO 创建信息 * @return 编号 */ - Long createUserGroup(@Valid BpmUserGroupCreateReqVO createReqVO); + Long createUserGroup(@Valid BpmUserGroupSaveReqVO createReqVO); /** * 更新用户组 * * @param updateReqVO 更新信息 */ - void updateUserGroup(@Valid BpmUserGroupUpdateReqVO updateReqVO); + void updateUserGroup(@Valid BpmUserGroupSaveReqVO updateReqVO); /** * 删除用户组 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java index 269078761..3c6489104 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java @@ -2,13 +2,10 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; import jakarta.annotation.Resource; @@ -20,6 +17,7 @@ import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_IS_DISABLE; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; @@ -36,20 +34,18 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService { private BpmUserGroupMapper userGroupMapper; @Override - public Long createUserGroup(BpmUserGroupCreateReqVO createReqVO) { - // 插入 - BpmUserGroupDO userGroup = BpmUserGroupConvert.INSTANCE.convert(createReqVO); + public Long createUserGroup(BpmUserGroupSaveReqVO createReqVO) { + BpmUserGroupDO userGroup = BeanUtils.toBean(createReqVO, BpmUserGroupDO.class); userGroupMapper.insert(userGroup); - // 返回 return userGroup.getId(); } @Override - public void updateUserGroup(BpmUserGroupUpdateReqVO updateReqVO) { + public void updateUserGroup(BpmUserGroupSaveReqVO updateReqVO) { // 校验存在 - this.validateUserGroupExists(updateReqVO.getId()); + validateUserGroupExists(updateReqVO.getId()); // 更新 - BpmUserGroupDO updateObj = BpmUserGroupConvert.INSTANCE.convert(updateReqVO); + BpmUserGroupDO updateObj = BeanUtils.toBean(updateReqVO, BpmUserGroupDO.class); userGroupMapper.updateById(updateObj); } @@ -63,7 +59,7 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService { private void validateUserGroupExists(Long id) { if (userGroupMapper.selectById(id) == null) { - throw ServiceExceptionUtil.exception(USER_GROUP_NOT_EXISTS); + throw exception(USER_GROUP_NOT_EXISTS); } } @@ -95,12 +91,12 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService { } // 获得用户组信息 List userGroups = userGroupMapper.selectBatchIds(ids); - Map userGroupMap = CollectionUtils.convertMap(userGroups, BpmUserGroupDO::getId); + Map userGroupMap = convertMap(userGroups, BpmUserGroupDO::getId); // 校验 ids.forEach(id -> { BpmUserGroupDO userGroup = userGroupMap.get(id); if (userGroup == null) { - throw ServiceExceptionUtil.exception(USER_GROUP_NOT_EXISTS); + throw exception(USER_GROUP_NOT_EXISTS); } if (!CommonStatusEnum.ENABLE.getStatus().equals(userGroup.getStatus())) { throw exception(USER_GROUP_IS_DISABLE, userGroup.getName()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java index 07958a51b..8bd2c88af 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java @@ -29,8 +29,8 @@ public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest { // 准备参数 String param = "1,2"; // mock 方法 - BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); - BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(11L, 12L))); + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setUserIds(asSet(21L, 22L))); when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2)); // 调用 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java index 9aca27476..438e3193c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.util.AssertUtils; import cn.iocoder.yudao.framework.test.core.util.RandomUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; @@ -39,7 +39,7 @@ public class BpmUserGroupServiceTest extends BaseDbUnitTest { @Test public void testCreateUserGroup_success() { // 准备参数 - BpmUserGroupCreateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupCreateReqVO.class); + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class); // 调用 Long userGroupId = userGroupService.createUserGroup(reqVO); From ed83b912e40b2ce45c0c57297ec30fc02ed6eff3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 19 Mar 2024 19:49:45 +0800 Subject: [PATCH 15/26] =?UTF-8?q?BPM=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=88=86=E7=B1=BB=E8=A1=A8=EF=BC=8C=E6=9B=BF=E4=BB=A3?= =?UTF-8?q?=E7=8E=B0=E6=9C=89=E7=9A=84=20`bpm=5Fcategory`=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AD=97=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 9 +- .../task/BpmProcessInstanceStatusEnum.java | 12 +- yudao-module-bpm/yudao-module-bpm-biz/pom.xml | 4 + .../definition/BpmCategoryController.java | 86 +++++++++++ .../admin/definition/BpmModelController.java | 59 +++++++- .../BpmProcessDefinitionController.java | 66 +++++++-- .../vo/category/BpmCategoryPageReqVO.java | 36 +++++ .../vo/category/BpmCategoryRespVO.java | 33 +++++ .../vo/category/BpmCategorySaveReqVO.java | 34 +++++ .../definition/vo/model/BpmModelBaseVO.java | 40 ----- .../vo/model/BpmModelPageItemRespVO.java | 48 ------ .../vo/model/BpmModelPageReqVO.java | 6 +- .../definition/vo/model/BpmModelRespVO.java | 47 +++++- .../vo/model/BpmModelUpdateReqVO.java | 2 +- .../vo/model/BpmModelUpdateStateReqVO.java | 4 +- .../BpmProcessDefinitionListReqVO.java | 18 --- .../BpmProcessDefinitionPageItemRespVO.java | 22 --- .../process/BpmProcessDefinitionRespVO.java | 12 +- .../task/BpmProcessInstanceController.java | 8 +- .../BpmProcessInstanceCopyController.java | 6 +- .../BpmProcessInstanceMyPageReqVO.java | 10 +- .../BpmProcessInstancePageItemRespVO.java | 7 +- .../vo/instance/BpmProcessInstanceRespVO.java | 5 +- .../convert/definition/BpmModelConvert.java | 90 ++++++------ .../BpmProcessDefinitionConvert.java | 85 +++++------ .../task/BpmProcessInstanceConvert.java | 9 +- .../dataobject/definition/BpmCategoryDO.java | 53 +++++++ ...O.java => BpmProcessDefinitionInfoDO.java} | 9 +- .../BpmProcessInstanceCopyDO.java | 2 +- .../dal/mysql/category/BpmCategoryMapper.java | 46 ++++++ .../BpmProcessDefinitionExtMapper.java | 22 --- .../BpmProcessDefinitionInfoMapper.java | 21 +++ .../BpmProcessInstanceCopyMapper.java | 4 +- .../definition/BpmCategoryService.java | 85 +++++++++++ .../definition/BpmCategoryServiceImpl.java | 113 +++++++++++++++ .../service/definition/BpmFormService.java | 11 +- .../definition/BpmFormServiceImpl.java | 6 +- .../service/definition/BpmModelService.java | 21 +-- .../definition/BpmModelServiceImpl.java | 105 ++++++-------- .../BpmProcessDefinitionService.java | 40 +++-- .../BpmProcessDefinitionServiceImpl.java | 134 ++++------------- .../dto/BpmProcessDefinitionCreateReqDTO.java | 1 - .../task/BpmProcessInstanceCopyService.java | 2 +- .../BpmProcessInstanceCopyServiceImpl.java | 4 +- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../mapper/category/BpmCategoryMapper.xml | 12 ++ .../category/BpmCategoryServiceImplTest.java | 137 ++++++++++++++++++ 47 files changed, 1076 insertions(+), 512 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/{BpmProcessDefinitionExtDO.java => BpmProcessDefinitionInfoDO.java} (88%) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/{cc => task}/BpmProcessInstanceCopyDO.java (96%) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/{cc => task}/BpmProcessInstanceCopyMapper.java (88%) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java 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 a689ad3e6..494e4a1b5 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 @@ -65,7 +65,12 @@ public interface ErrorCodeConstants { ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1_009_010_001, "表单项({}) 和 ({}) 使用了相同的字段名({})"); // ========== 用户组模块 1-009-011-000 ========== - ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1_009_011_000, "用户组不存在"); - ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1_009_011_001, "名字为【{}】的用户组已被禁用"); + ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1_009_011_000, "用户分组不存在"); + ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1_009_011_001, "名字为【{}】的用户分组已被禁用"); + + // ========== 用户组模块 1-009-012-000 ========== + ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在"); + ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); + ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java index b8c05ad98..82a4119b5 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.bpm.enums.task; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Arrays; + /** * 流程实例 ProcessInstance 的状态 * @@ -10,13 +13,15 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum BpmProcessInstanceStatusEnum { +public enum BpmProcessInstanceStatusEnum implements IntArrayValuable { RUNNING(1, "审批中"), APPROVE(2, "审批通过"), REJECT(3, "审批不通过"), CANCEL(4, "已取消"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmProcessInstanceStatusEnum::getStatus).toArray(); + /** * 状态 */ @@ -26,4 +31,9 @@ public enum BpmProcessInstanceStatusEnum { */ private final String desc; + @Override + public int[] array() { + return new int[0]; + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml index f1ac4c0ee..1a4b410e8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml @@ -70,5 +70,9 @@ yudao-spring-boot-starter-flowable ${revision} + + cn.iocoder.boot + yudao-spring-boot-starter-excel + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java new file mode 100644 index 000000000..322666615 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmCategoryController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Comparator; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - BPM 流程分类") +@RestController +@RequestMapping("/bpm/category") +@Validated +public class BpmCategoryController { + + @Resource + private BpmCategoryService categoryService; + + @PostMapping("/create") + @Operation(summary = "创建流程分类") + @PreAuthorize("@ss.hasPermission('bpm:category:create')") + public CommonResult createCategory(@Valid @RequestBody BpmCategorySaveReqVO createReqVO) { + return success(categoryService.createCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程分类") + @PreAuthorize("@ss.hasPermission('bpm:category:update')") + public CommonResult updateCategory(@Valid @RequestBody BpmCategorySaveReqVO updateReqVO) { + categoryService.updateCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:category:delete')") + public CommonResult deleteCategory(@RequestParam("id") Long id) { + categoryService.deleteCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:category:query')") + public CommonResult getCategory(@RequestParam("id") Long id) { + BpmCategoryDO category = categoryService.getCategory(id); + return success(BeanUtils.toBean(category, BpmCategoryRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程分类分页") + @PreAuthorize("@ss.hasPermission('bpm:category:query')") + public CommonResult> getCategoryPage(@Valid BpmCategoryPageReqVO pageReqVO) { + PageResult pageResult = categoryService.getCategoryPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmCategoryRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取流程分类的精简信息列表", description = "只包含被开启的分类,主要用于前端的下拉选项") + public CommonResult> getCategorySimpleList() { + List list = categoryService.getCategoryListByStatus(CommonStatusEnum.ENABLE.getStatus()); + list.sort(Comparator.comparingInt(BpmCategoryDO::getSort)); + return success(convertList(list, category -> new BpmCategoryRespVO().setId(category.getId()) + .setName(category.getName()).setCode(category.getCode()))); + } + +} \ 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 4e7195ccd..4143076ff 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 @@ -1,23 +1,41 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.io.IoUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; +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.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.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - 流程模型") @RestController @@ -27,11 +45,39 @@ public class BpmModelController { @Resource private BpmModelService modelService; + @Resource + private BpmFormService formService; + @Resource + private BpmCategoryService categoryService; + @Resource + private BpmProcessDefinitionService processDefinitionService; @GetMapping("/page") @Operation(summary = "获得模型分页") - public CommonResult> getModelPage(BpmModelPageReqVO pageVO) { - return success(modelService.getModelPage(pageVO)); + public CommonResult> getModelPage(BpmModelPageReqVO pageVO) { + PageResult pageResult = modelService.getModelPage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接数据 + // 获得 Form 表单 + Set formIds = convertSet(pageResult.getList(), model -> { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + return metaInfo != null ? metaInfo.getFormId() : null; + }); + Map formMap = formService.getFormMap(formIds); + // 获得 Category Map + Map categoryMap = categoryService.getCategoryMap( + convertSet(pageResult.getList(), Model::getCategory)); + // 获得 Deployment Map + Set deploymentIds = new HashSet<>(); + pageResult.getList().forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId())); + Map deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds); + // 获得 ProcessDefinition Map + List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds); + Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); + return success(BpmModelConvert.INSTANCE.buildModelPage(pageResult, formMap, categoryMap, deploymentMap, processDefinitionMap)); } @GetMapping("/get") @@ -39,8 +85,12 @@ public class BpmModelController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('bpm:model:query')") public CommonResult getModel(@RequestParam("id") String id) { - BpmModelRespVO model = modelService.getModel(id); - return success(model); + Model model = modelService.getModel(id); + if (model == null) { + return null; + } + byte[] bpmnBytes = modelService.getModelBpmnXML(id); + return success(BpmModelConvert.INSTANCE.buildModel(model, bpmnBytes)); } @PostMapping("/create") @@ -93,4 +143,5 @@ public class BpmModelController { modelService.deleteModel(id); return success(true); } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java index 0c0fcd7d3..ff3c37b08 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java @@ -1,15 +1,23 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; +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.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +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.BpmProcessDefinitionService; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -17,11 +25,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import jakarta.annotation.Resource; - +import java.util.Collections; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - 流程定义") @RestController @@ -30,22 +39,54 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class BpmProcessDefinitionController { @Resource - private BpmProcessDefinitionService bpmDefinitionService; + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmFormService formService; + @Resource + private BpmCategoryService categoryService; @GetMapping("/page") @Operation(summary = "获得流程定义分页") @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") - public CommonResult> getProcessDefinitionPage( + public CommonResult> getProcessDefinitionPage( BpmProcessDefinitionPageReqVO pageReqVO) { - return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO)); + PageResult pageResult = processDefinitionService.getProcessDefinitionPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 获得 Category Map + Map categoryMap = categoryService.getCategoryMap( + convertSet(pageResult.getList(), ProcessDefinition::getCategory)); + // 获得 Deployment Map + Map deploymentMap = processDefinitionService.getDeploymentMap( + convertSet(pageResult.getList(), ProcessDefinition::getDeploymentId)); + // 获得 BpmProcessDefinitionInfoDO Map + Map processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap( + convertSet(pageResult.getList(), ProcessDefinition::getId)); + // 获得 Form Map + Map formMap = formService.getFormMap( + convertSet(processDefinitionMap.values(), BpmProcessDefinitionInfoDO::getFormId)); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionPage( + pageResult, deploymentMap, processDefinitionMap, formMap, categoryMap)); } @GetMapping ("/list") @Operation(summary = "获得流程定义列表") + @Parameter(name = "suspensionState", description = "挂起状态", required = true, example = "1") // 参见 Flowable SuspensionState 枚举 @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") public CommonResult> getProcessDefinitionList( - BpmProcessDefinitionListReqVO listReqVO) { - return success(bpmDefinitionService.getProcessDefinitionList(listReqVO)); + @RequestParam("suspensionState") Integer suspensionState) { + List list = processDefinitionService.getProcessDefinitionListBySuspensionState(suspensionState); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + // 获得 BpmProcessDefinitionInfoDO Map + Map processDefinitionMap = processDefinitionService.getProcessDefinitionInfoMap( + convertSet(list, ProcessDefinition::getId)); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinitionList( + list, null, processDefinitionMap, null, null)); } @GetMapping ("/get-bpmn-xml") @@ -53,7 +94,8 @@ public class BpmProcessDefinitionController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") public CommonResult getProcessDefinitionBpmnXML(@RequestParam("id") String id) { - String bpmnXML = bpmDefinitionService.getProcessDefinitionBpmnXML(id); + String bpmnXML = processDefinitionService.getProcessDefinitionBpmnXML(id); return success(bpmnXML); } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java new file mode 100644 index 000000000..ea3c2cb6c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM 流程分类分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmCategoryPageReqVO extends PageParam { + + @Schema(description = "分类名", example = "王五") + private String name; + + @Schema(description = "分类标志", example = "OA") + private String code; + + @Schema(description = "分类状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ 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/vo/category/BpmCategoryRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java new file mode 100644 index 000000000..7ada55a1d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程分类 Response VO") +@Data +public class BpmCategoryRespVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + private Long id; + + @Schema(description = "分类名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "分类标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "OA") + private String code; + + @Schema(description = "分类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") + private String description; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer sort; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ 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/vo/category/BpmCategorySaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java new file mode 100644 index 000000000..352cf690b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - BPM 流程分类新增/修改 Request VO") +@Data +public class BpmCategorySaveReqVO { + + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + private Long id; + + @Schema(description = "分类名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "分类名不能为空") + private String name; + + @Schema(description = "分类标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "OA") + @NotEmpty(message = "分类标志不能为空") + private String code; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "分类状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "分类排序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "分类排序不能为空") + private Integer sort; + +} \ 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/vo/model/BpmModelBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java deleted file mode 100644 index c0b1443cb..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import jakarta.validation.constraints.NotEmpty; - -/** -* 流程模型 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ -@Data -public class BpmModelBaseVO { - - @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_yudao") - @NotEmpty(message = "流程标识不能为空") - private String key; - - @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - @NotEmpty(message = "流程名称不能为空") - private String name; - - @Schema(description = "流程描述", example = "我是描述") - private String description; - - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", example = "1") - @NotEmpty(message = "流程分类不能为空") - private String category; - - @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") - private Integer formType; - @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") - private Long formId; - @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/create") - private String formCustomCreatePath; - @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/view") - private String formCustomViewPath; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java deleted file mode 100644 index 4fc5b61d4..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 流程模型的分页的每一项 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmModelPageItemRespVO extends BpmModelBaseVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "表单名字", example = "请假表单") - private String formName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - /** - * 最新部署的流程定义 - */ - private ProcessDefinition processDefinition; - - @Schema(description = "流程定义") - @Data - public static class ProcessDefinition { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer version; - - @Schema(description = "部署时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime deploymentTime; - - @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer suspensionState; - - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java index 15283208e..86766f187 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java @@ -13,13 +13,13 @@ import lombok.ToString; @ToString(callSuper = true) public class BpmModelPageReqVO extends PageParam { - @Schema(description = "标识-精准匹配", example = "process1641042089407") + @Schema(description = "标识,精准匹配", example = "process1641042089407") private String key; - @Schema(description = "名字-模糊匹配", example = "芋道") + @Schema(description = "名字,模糊匹配", example = "芋道") private String name; - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", example = "1") + @Schema(description = "流程分类", example = "1") private String category; } 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 df4abf750..c08393359 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,25 +1,56 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import java.time.LocalDateTime; -@Schema(description = "管理后台 - 流程模型的创建 Request VO") +@Schema(description = "管理后台 - 流程模型 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmModelRespVO extends BpmModelBaseVO { +public class BpmModelRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String id; - @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) - private String bpmnXml; + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "process_yudao") + private String key; + + @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "流程描述", example = "我是描述") + private String description; + + @Schema(description = "流程分类编码", example = "1") + private String category; + @Schema(description = "流程分类名字", example = "请假") + private String categoryName; + + @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + + @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") + private Long formId; + @Schema(description = "表单名字", example = "请假表单") + private String formName; + + @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/create") + private String formCustomCreatePath; + @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", + example = "/bpm/oa/leave/view") + private String formCustomViewPath; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; + @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) + private String bpmnXml; + + /** + * 最新部署的流程定义 + */ + private BpmProcessDefinitionRespVO processDefinition; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java index 9cfb7bbbe..cc2420b28 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java @@ -19,7 +19,7 @@ public class BpmModelUpdateReqVO { @Schema(description = "流程描述", example = "我是描述") private String description; - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", example = "1") + @Schema(description = "流程分类", example = "1") private String category; @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java index 4d583dac2..7c5a356a2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java @@ -13,8 +13,8 @@ public class BpmModelUpdateStateReqVO { @NotNull(message = "编号不能为空") private String id; - @Schema(description = "状态-见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "状态不能为空") - private Integer state; + private Integer state; // 参见 Flowable SuspensionState 枚举 } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java deleted file mode 100644 index 35243d2ac..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - 流程定义列表 Request VO") -@Data -@ToString(callSuper = true) -@EqualsAndHashCode(callSuper = true) -public class BpmProcessDefinitionListReqVO extends PageParam { - - @Schema(description = "中断状态-参见 SuspensionState 枚举", example = "1") - private Integer suspensionState; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java deleted file mode 100644 index 901c8aa77..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 流程定义的分页的每一项 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmProcessDefinitionPageItemRespVO extends BpmProcessDefinitionRespVO { - - @Schema(description = "表单名字", example = "请假表单") - private String formName; - - @Schema(description = "部署时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime deploymentTime; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index c649c8219..bf015920e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import jakarta.validation.constraints.NotEmpty; + +import java.time.LocalDateTime; import java.util.List; @Schema(description = "管理后台 - 流程定义 Response VO") @@ -23,14 +25,17 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "流程描述", example = "我是描述") private String description; - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", example = "1") - @NotEmpty(message = "流程分类不能为空") + @Schema(description = "流程分类", example = "1") private String category; + @Schema(description = "流程分类名字", example = "请假") + private String categoryName; @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") private Integer formType; @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") private Long formId; + @Schema(description = "表单名字", example = "请假表单") + private String formName; @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) private String formConf; @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) @@ -45,4 +50,7 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer suspensionState; + @Schema(description = "部署时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取 + } 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 c22ee3c6b..05c845827 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 @@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; @@ -40,6 +42,8 @@ public class BpmProcessInstanceController { private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmCategoryService categoryService; @GetMapping("/my-page") @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") @@ -56,7 +60,9 @@ public class BpmProcessInstanceController { convertList(pageResult.getList(), HistoricProcessInstance::getId)); Map processDefinitionMap = processDefinitionService.getProcessDefinitionMap( convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); - return success(BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, processDefinitionMap, taskMap)); + Map categoryMap = categoryService.getCategoryMap( + convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); + return success(BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, processDefinitionMap, categoryMap, taskMap)); } @PostMapping("/create") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java index e86f01315..e9f0eb444 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; @@ -44,7 +44,7 @@ public class BpmProcessInstanceCopyController { @Resource private BpmProcessInstanceService processInstanceService; @Resource - private BpmTaskService bpmTaskService; + private BpmTaskService taskService; @Resource private AdminUserApi adminUserApi; @@ -61,7 +61,7 @@ public class BpmProcessInstanceCopyController { } // 拼接返回 - Map taskNameMap = bpmTaskService.getTaskNameByTaskIds( + Map taskNameMap = taskService.getTaskNameByTaskIds( convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getTaskId)); Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId)); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java index 5b5d9fb26..4945b2b9a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -23,13 +25,11 @@ public class BpmProcessInstanceMyPageReqVO extends PageParam { @Schema(description = "流程定义的编号", example = "2048") private String processDefinitionId; - @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", example = "1") + @Schema(description = "流程实例的状态", example = "1") + @InEnum(BpmProcessInstanceStatusEnum.class) private Integer status; - @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", example = "2") - private Integer result; - - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", example = "1") + @Schema(description = "流程分类", example = "1") private String category; @Schema(description = "创建时间") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java index 4cfaf171d..f1763a27f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java @@ -6,6 +6,7 @@ import lombok.Data; import java.time.LocalDateTime; import java.util.List; +// TODO @芋艿:是不是要融合? @Schema(description = "管理后台 - 流程实例的分页 Item Response VO") @Data public class BpmProcessInstancePageItemRespVO { @@ -19,10 +20,12 @@ public class BpmProcessInstancePageItemRespVO { @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") private String processDefinitionId; - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String category; + @Schema(description = "流程分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假") + private String categoryName; - @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java index faa770c47..e0410e6be 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -17,15 +17,12 @@ public class BpmProcessInstanceRespVO { @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; - @Schema(description = "流程分类-参见 bpm_model_category 数据字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String category; @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 - @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer result; - @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; 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 9f79032f6..a0abde8c6 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 @@ -1,10 +1,17 @@ package cn.iocoder.yudao.module.bpm.convert.definition; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModeImportReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +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.service.definition.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; @@ -30,57 +37,61 @@ public interface BpmModelConvert { BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class); - default List convertList(List list, Map formMap, - Map deploymentMap, - Map processDefinitionMap) { - return CollectionUtils.convertList(list, model -> { + default PageResult buildModelPage(PageResult pageResult, + Map formMap, + Map categoryMap, Map deploymentMap, + Map processDefinitionMap) { + List list = CollectionUtils.convertList(pageResult.getList(), model -> { BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; + BpmCategoryDO category = categoryMap.get(model.getCategory()); Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null; - return convert(model, form, deployment, processDefinition); + return buildModel0(model, metaInfo, form, category, deployment, processDefinition); }); + return new PageResult<>(list, pageResult.getTotal()); } - default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) { - BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO(); - modelRespVO.setId(model.getId()); - modelRespVO.setCreateTime(DateUtils.of(model.getCreateTime())); - // 通用 copy - copyTo(model, modelRespVO); + default BpmModelRespVO buildModel(Model model, + byte[] bpmnBytes) { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); + modelVO.setBpmnXml(new String(bpmnBytes)); + return modelVO; + } + + default BpmModelRespVO buildModel0(Model model, + BpmModelMetaInfoRespDTO metaInfo, BpmFormDO form, BpmCategoryDO category, + Deployment deployment, ProcessDefinition processDefinition) { + BpmModelRespVO modelRespVO = new BpmModelRespVO().setId(model.getId()).setName(model.getName()) + .setKey(model.getKey()).setCategory(model.getCategory()) + .setCreateTime(DateUtils.of(model.getCreateTime())); // Form + if (metaInfo != null) { + modelRespVO.setFormType(metaInfo.getFormType()).setFormId(metaInfo.getFormId()) + .setFormCustomCreatePath(metaInfo.getFormCustomCreatePath()) + .setFormCustomViewPath(metaInfo.getFormCustomViewPath()); + modelRespVO.setDescription(metaInfo.getDescription()); + } if (form != null) { - modelRespVO.setFormId(form.getId()); - modelRespVO.setFormName(form.getName()); + modelRespVO.setFormId(form.getId()).setFormName(form.getName()); + } + // Category + if (category != null) { + modelRespVO.setCategoryName(category.getName()); } // ProcessDefinition - modelRespVO.setProcessDefinition(this.convert(processDefinition)); - if (modelRespVO.getProcessDefinition() != null) { + if (processDefinition != null) { + modelRespVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class)); modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); - modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime())); + if (deployment != null) { + modelRespVO.getProcessDefinition().setDeploymentTime(DateUtils.of(deployment.getDeploymentTime())); + } } return modelRespVO; } - default BpmModelRespVO convert(Model model) { - BpmModelRespVO modelRespVO = new BpmModelRespVO(); - modelRespVO.setId(model.getId()); - modelRespVO.setCreateTime(DateUtils.of(model.getCreateTime())); - // 通用 copy - copyTo(model, modelRespVO); - return modelRespVO; - } - - default void copyTo(Model model, BpmModelBaseVO to) { - to.setName(model.getName()); - to.setKey(model.getKey()); - to.setCategory(model.getCategory()); - // metaInfo - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); - copyTo(metaInfo, to); - } - BpmModelCreateReqVO convert(BpmModeImportReqVO bean); default BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDO form) { @@ -102,18 +113,14 @@ public interface BpmModelConvert { void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to); - void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to); - - BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean); - - default void copy(Model model, BpmModelCreateReqVO bean) { + default void copyToCreateModel(Model model, BpmModelCreateReqVO bean) { model.setName(bean.getName()); model.setKey(bean.getKey()); model.setMetaInfo(buildMetaInfoStr(null, bean.getDescription(), null, null, null, null)); } - default void copy(Model model, BpmModelUpdateReqVO bean) { + default void copyToUpdateModel(Model model, BpmModelUpdateReqVO bean) { model.setName(bean.getName()); model.setCategory(bean.getCategory()); model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class), @@ -138,4 +145,5 @@ public interface BpmModelConvert { } return JsonUtils.toJsonString(metaInfo); } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index b52b48ee9..f1e945178 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -1,12 +1,15 @@ package cn.iocoder.yudao.module.bpm.convert.definition; import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +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.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; @@ -14,7 +17,6 @@ import org.flowable.engine.repository.ProcessDefinition; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; -import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.List; @@ -30,55 +32,46 @@ public interface BpmProcessDefinitionConvert { BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class); - BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean); - BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean); - - default List convertList(List list, Map deploymentMap, - Map processDefinitionDOMap, Map formMap) { - return CollectionUtils.convertList(list, definition -> { - Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null; - BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId()); - BpmFormDO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null; - return convert(definition, deployment, definitionDO, form); - }); + default PageResult buildProcessDefinitionPage(PageResult page, + Map deploymentMap, + Map processDefinitionInfoMap, + Map formMap, + Map categoryMap) { + List list = buildProcessDefinitionList(page.getList(), deploymentMap, processDefinitionInfoMap, formMap, categoryMap); + return new PageResult<>(list, page.getTotal()); } - default List convertList3(List list, - Map processDefinitionDOMap) { - return CollectionUtils.convertList(list, processDefinition -> { - BpmProcessDefinitionRespVO respVO = convert3(processDefinition); - BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId()); - // 复制通用属性 - copyTo(processDefinitionExtDO, respVO); + default List buildProcessDefinitionList(List list, + Map deploymentMap, + Map processDefinitionInfoMap, + Map formMap, + Map categoryMap) { + return CollectionUtils.convertList(list, definition -> { + BpmProcessDefinitionRespVO respVO = BeanUtils.toBean(definition, BpmProcessDefinitionRespVO.class); + respVO.setSuspensionState(definition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + // Deployment + MapUtils.findAndThen(deploymentMap, definition.getDeploymentId(), + deployment -> respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime()))); + // BpmProcessDefinitionInfoDO + BpmProcessDefinitionInfoDO processDefinitionInfo = MapUtil.get(processDefinitionInfoMap, definition.getId(), BpmProcessDefinitionInfoDO.class); + if (processDefinitionInfo != null) { + copyTo(processDefinitionInfo, respVO); + // Form + BpmFormDO form = MapUtil.get(formMap, processDefinitionInfo.getFormId(), BpmFormDO.class); + if (form != null) { + respVO.setFormName(form.getName()); + } + } + // Category + MapUtils.findAndThen(categoryMap, definition.getCategory(), category -> respVO.setCategoryName(category.getName())); return respVO; }); } - @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState") - BpmProcessDefinitionRespVO convert3(ProcessDefinition bean); - - @Named("convertSuspendedToSuspensionState") - default Integer convertSuspendedToSuspensionState(boolean suspended) { - return suspended ? SuspensionState.SUSPENDED.getStateCode() : - SuspensionState.ACTIVE.getStateCode(); - } - - default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment, - BpmProcessDefinitionExtDO processDefinitionExtDO, BpmFormDO form) { - BpmProcessDefinitionPageItemRespVO respVO = convert(bean); - respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); - if (deployment != null) { - respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime())); - } - if (form != null) { - respVO.setFormName(form.getName()); - } - // 复制通用属性 - copyTo(processDefinitionExtDO, respVO); - return respVO; - } + BpmProcessDefinitionInfoDO convert2(BpmProcessDefinitionCreateReqDTO bean); @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessDefinitionRespVO to); + void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 11166c62e..a7c621590 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -7,7 +7,8 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; @@ -38,6 +39,7 @@ public interface BpmProcessInstanceConvert { default PageResult convertPage(PageResult pageResult, Map processDefinitionMap, + Map categoryMap, Map> taskMap) { PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); for (int i = 0; i < pageResult.getList().size(); i++) { @@ -45,13 +47,14 @@ public interface BpmProcessInstanceConvert { respVO.setStatus((Integer) pageResult.getList().get(i).getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), processDefinition -> respVO.setCategory(processDefinition.getCategory())); + MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstancePageItemRespVO.Task.class)); } return vpPageResult; } default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, - ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt, + ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionExt, String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { BpmProcessInstanceRespVO respVO = convert2(processInstance); respVO.setStatus((Integer) processInstance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); @@ -75,7 +78,7 @@ public interface BpmProcessInstanceConvert { BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to); + void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to); BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java new file mode 100644 index 000000000..2fe0963bb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * BPM 流程分类 DO + * + * @author 芋道源码 + */ +@TableName("bpm_category") +@KeySequence("bpm_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmCategoryDO extends BaseDO { + + /** + * 分类编号 + */ + @TableId + private Long id; + /** + * 分类名 + */ + private String name; + /** + * 分类标志 + */ + private String code; + /** + * 分类描述 + */ + private String description; + /** + * 分类状态 + * + * 枚举 {@link TODO common_status 对应的类} + */ + private Integer status; + /** + * 分类排序 + */ + private Integer sort; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java similarity index 88% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java index 57abc0b99..5f94b3b95 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -11,19 +11,19 @@ import lombok.*; import java.util.List; /** - * Bpm 流程定义的拓展表 - * 主要解决 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表 + * Bpm 流程定义的拓信息 + * 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表 * * @author 芋道源码 */ -@TableName(value = "bpm_process_definition_ext", autoResultMap = true) +@TableName(value = "bpm_process_definition_info", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class BpmProcessDefinitionExtDO extends BaseDO { +public class BpmProcessDefinitionInfoDO extends BaseDO { /** * 编号 @@ -86,5 +86,4 @@ public class BpmProcessDefinitionExtDO extends BaseDO { */ private String formCustomViewPath; - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java similarity index 96% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java index 99bca609d..fe3b28de2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.bpm.dal.dataobject.cc; +package cn.iocoder.yudao.module.bpm.dal.dataobject.task; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java new file mode 100644 index 000000000..888856a45 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.category; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * BPM 流程分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmCategoryMapper extends BaseMapperX { + + default PageResult selectPage(BpmCategoryPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmCategoryDO::getName, reqVO.getName()) + .eqIfPresent(BpmCategoryDO::getCode, reqVO.getCode()) + .eqIfPresent(BpmCategoryDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmCategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByAsc(BpmCategoryDO::getSort)); + } + + default BpmCategoryDO selectByName(String name) { + return selectOne(BpmCategoryDO::getName, name); + } + + default BpmCategoryDO selectByCode(String code) { + return selectOne(BpmCategoryDO::getCode, code); + } + + default List selectListByCode(Collection codes) { + return selectList(BpmCategoryDO::getCode, codes); + } + + default List selectListByStatus(Integer status) { + return selectList(BpmCategoryDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java deleted file mode 100644 index 3ff53f2d9..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.mysql.definition; - -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; - -@Mapper -public interface BpmProcessDefinitionExtMapper extends BaseMapperX { - - default List selectListByProcessDefinitionIds(Collection processDefinitionIds) { - return selectList("process_definition_id", processDefinitionIds); - } - - default BpmProcessDefinitionExtDO selectByProcessDefinitionId(String processDefinitionId) { - return selectOne("process_definition_id", processDefinitionId); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java new file mode 100644 index 000000000..419d638f8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionInfoMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface BpmProcessDefinitionInfoMapper extends BaseMapperX { + + default List selectListByProcessDefinitionIds(Collection processDefinitionIds) { + return selectList(BpmProcessDefinitionInfoDO::getProcessDefinitionId, processDefinitionIds); + } + + default BpmProcessDefinitionInfoDO selectByProcessDefinitionId(String processDefinitionId) { + return selectOne(BpmProcessDefinitionInfoDO::getProcessDefinitionId, processDefinitionId); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java similarity index 88% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java index 2179525e0..c5ec50f65 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.bpm.dal.mysql.cc; +package cn.iocoder.yudao.module.bpm.dal.mysql.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; import org.apache.ibatis.annotations.Mapper; @Mapper diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java new file mode 100644 index 000000000..a61b132b5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryService.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * BPM 流程分类 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmCategoryService { + + /** + * 创建流程分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createCategory(@Valid BpmCategorySaveReqVO createReqVO); + + /** + * 更新流程分类 + * + * @param updateReqVO 更新信息 + */ + void updateCategory(@Valid BpmCategorySaveReqVO updateReqVO); + + /** + * 删除流程分类 + * + * @param id 编号 + */ + void deleteCategory(Long id); + + /** + * 获得流程分类 + * + * @param id 编号 + * @return BPM 流程分类 + */ + BpmCategoryDO getCategory(Long id); + + /** + * 获得流程分类分页 + * + * @param pageReqVO 分页查询 + * @return 流程分类分页 + */ + PageResult getCategoryPage(BpmCategoryPageReqVO pageReqVO); + + /** + * 获得流程分类 Map,基于指定编码 + * + * @param codes 编号数组 + * @return 流程分类 Map + */ + default Map getCategoryMap(Collection codes) { + return convertMap(getCategoryListByCode(codes), BpmCategoryDO::getCode); + } + + /** + * 获得流程分类列表,基于指定编码 + * + * @return 流程分类列表 + */ + List getCategoryListByCode(Collection codes); + + /** + * 获得流程分类列表,基于指定状态 + * + * @param status 状态 + * @return 流程分类列表 + */ + List getCategoryListByStatus(Integer status); + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java new file mode 100644 index 000000000..8db37a46e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.bpm.dal.mysql.category.BpmCategoryMapper; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 流程分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmCategoryServiceImpl implements BpmCategoryService { + + @Resource + private BpmCategoryMapper bpmCategoryMapper; + + @Override + public Long createCategory(BpmCategorySaveReqVO createReqVO) { + // 校验唯一 + validateCategoryNameUnique(createReqVO); + validateCategoryCodeUnique(createReqVO); + // 插入 + BpmCategoryDO category = BeanUtils.toBean(createReqVO, BpmCategoryDO.class); + bpmCategoryMapper.insert(category); + return category.getId(); + } + + @Override + public void updateCategory(BpmCategorySaveReqVO updateReqVO) { + // 校验存在 + validateCategoryExists(updateReqVO.getId()); + validateCategoryNameUnique(updateReqVO); + validateCategoryCodeUnique(updateReqVO); + // 更新 + BpmCategoryDO updateObj = BeanUtils.toBean(updateReqVO, BpmCategoryDO.class); + bpmCategoryMapper.updateById(updateObj); + } + + private void validateCategoryNameUnique(BpmCategorySaveReqVO updateReqVO) { + BpmCategoryDO category = bpmCategoryMapper.selectByName(updateReqVO.getName()); + if (category == null + || ObjUtil.equal(category.getId(), updateReqVO.getId())) { + return; + } + throw exception(CATEGORY_NAME_DUPLICATE, updateReqVO.getName()); + } + + private void validateCategoryCodeUnique(BpmCategorySaveReqVO updateReqVO) { + BpmCategoryDO category = bpmCategoryMapper.selectByCode(updateReqVO.getCode()); + if (category == null + || ObjUtil.equal(category.getId(), updateReqVO.getId())) { + return; + } + throw exception(CATEGORY_CODE_DUPLICATE, updateReqVO.getCode()); + } + + @Override + public void deleteCategory(Long id) { + // 校验存在 + validateCategoryExists(id); + // 删除 + bpmCategoryMapper.deleteById(id); + } + + private void validateCategoryExists(Long id) { + if (bpmCategoryMapper.selectById(id) == null) { + throw exception(CATEGORY_NOT_EXISTS); + } + } + + @Override + public BpmCategoryDO getCategory(Long id) { + return bpmCategoryMapper.selectById(id); + } + + @Override + public PageResult getCategoryPage(BpmCategoryPageReqVO pageReqVO) { + return bpmCategoryMapper.selectPage(pageReqVO); + } + + @Override + public List getCategoryListByCode(Collection codes) { + if (CollUtil.isEmpty(codes)) { + return Collections.emptyList(); + } + return bpmCategoryMapper.selectListByCode(codes); + } + + @Override + public List getCategoryListByStatus(Integer status) { + return bpmCategoryMapper.selectListByStatus(status); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java index dd618226e..9c61ae427 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java @@ -1,16 +1,14 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; - import jakarta.validation.Valid; + import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -74,9 +72,6 @@ public interface BpmFormService { * @return 动态表单 Map */ default Map getFormMap(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyMap(); - } return CollectionUtils.convertMap(this.getFormList(ids), BpmFormDO::getId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java index 54bee9ce1..d805da6a6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.service.definition; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -80,6 +81,9 @@ public class BpmFormServiceImpl implements BpmFormService { @Override public List getFormList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } return formMapper.selectBatchIds(ids); } @@ -88,7 +92,7 @@ public class BpmFormServiceImpl implements BpmFormService { return formMapper.selectPage(pageReqVO); } - + // TODO @芋艿:这里没搞完! @Override public BpmFormDO checkFormConfig(String configStr) { BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(configStr, BpmModelMetaInfoRespDTO.class); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java index bddd79081..e1acce064 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import jakarta.validation.Valid; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Model; /** * Flowable流程模型接口 @@ -18,7 +19,7 @@ public interface BpmModelService { * @param pageVO 分页查询 * @return 流程模型分页 */ - PageResult getModelPage(BpmModelPageReqVO pageVO); + PageResult getModelPage(BpmModelPageReqVO pageVO); /** * 创建流程模型 @@ -35,7 +36,15 @@ public interface BpmModelService { * @param id 编号 * @return 流程模型 */ - BpmModelRespVO getModel(String id); + Model getModel(String id); + + /** + * 获得流程模型的 BPMN XML + * + * @param id 编号 + * @return BPMN XML + */ + byte[] getModelBpmnXML(String id); /** * 修改流程模型 @@ -66,14 +75,6 @@ public interface BpmModelService { */ void updateModelState(String id, Integer state); - /** - * 获得流程模型编号对应的 BPMN Model - * - * @param id 流程模型编号 - * @return BPMN Model - */ - BpmnModel getBpmnModel(String id); - /** * 获得流程定义编号对应的 BPMN Model * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 729e176b0..933a0b5bf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; @@ -21,7 +21,6 @@ import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.RepositoryService; -import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ModelQuery; import org.flowable.engine.repository.ProcessDefinition; @@ -30,10 +29,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import org.springframework.validation.annotation.Validated; -import java.util.*; +import java.util.List; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** @@ -60,7 +59,7 @@ public class BpmModelServiceImpl implements BpmModelService { private BpmTaskCandidateInvoker taskCandidateInvoker; @Override - public PageResult getModelPage(BpmModelPageReqVO pageVO) { + public PageResult getModelPage(BpmModelPageReqVO pageVO) { ModelQuery modelQuery = repositoryService.createModelQuery(); if (StrUtil.isNotBlank(pageVO.getKey())) { modelQuery.modelKey(pageVO.getKey()); @@ -72,34 +71,21 @@ public class BpmModelServiceImpl implements BpmModelService { modelQuery.modelCategory(pageVO.getCategory()); } // 执行查询 - List models = modelQuery.modelTenantId(TenantContextHolder.getTenantIdStr()) + long count = modelQuery.count(); + if (count == 0) { + return PageResult.empty(count); + } + List models = modelQuery + .modelTenantId(TenantContextHolder.getTenantIdStr()) .orderByCreateTime().desc() .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); - - // 获得 Form Map - Set formIds = CollectionUtils.convertSet(models, model -> { - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); - return metaInfo != null ? metaInfo.getFormId() : null; - }); - Map formMap = bpmFormService.getFormMap(formIds); - - // 获得 Deployment Map - Set deploymentIds = new HashSet<>(); - models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId())); - Map deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds); - // 获得 ProcessDefinition Map - List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds); - Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); - - // 拼接结果 - long modelCount = modelQuery.count(); - return new PageResult<>(BpmModelConvert.INSTANCE.convertList(models, formMap, deploymentMap, processDefinitionMap), modelCount); + return new PageResult<>(models, count); } @Override @Transactional(rollbackFor = Exception.class) public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { - checkKeyNCName(createReqVO.getKey()); + validateKeyNCName(createReqVO.getKey()); // 校验流程标识已经存在 Model keyModel = getModelByKey(createReqVO.getKey()); if (keyModel != null) { @@ -108,7 +94,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 创建流程定义 Model model = repositoryService.newModel(); - BpmModelConvert.INSTANCE.copy(model, createReqVO); + BpmModelConvert.INSTANCE.copyToCreateModel(model, createReqVO); model.setTenantId(TenantContextHolder.getTenantIdStr()); // 保存流程定义 repositoryService.saveModel(model); @@ -117,34 +103,17 @@ public class BpmModelServiceImpl implements BpmModelService { return model.getId(); } - private Model getModelByKey(String key) { - return repositoryService.createModelQuery().modelKey(key).singleResult(); - } - - @Override - public BpmModelRespVO getModel(String id) { - Model model = repositoryService.getModel(id); - if (model == null) { - return null; - } - BpmModelRespVO modelRespVO = BpmModelConvert.INSTANCE.convert(model); - // 拼接 bpmn XML - byte[] bpmnBytes = repositoryService.getModelEditorSource(id); - modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes)); - return modelRespVO; - } - @Override @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) { // 校验流程模型存在 - Model model = repositoryService.getModel(updateReqVO.getId()); + Model model = getModel(updateReqVO.getId()); if (model == null) { throw exception(MODEL_NOT_EXISTS); } // 修改流程定义 - BpmModelConvert.INSTANCE.copy(model, updateReqVO); + BpmModelConvert.INSTANCE.copyToUpdateModel(model, updateReqVO); // 更新模型 repositoryService.saveModel(model); // 更新 BPMN XML @@ -155,18 +124,18 @@ public class BpmModelServiceImpl implements BpmModelService { @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 public void deployModel(String id) { // 1.1 校验流程模型存在 - Model model = repositoryService.getModel(id); + Model model = getModel(id); if (ObjectUtils.isEmpty(model)) { throw exception(MODEL_NOT_EXISTS); } // 1.2 校验流程图 // TODO 芋艿:校验流程图的有效性;例如说,是否有开始的元素,是否有结束的元素; - byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId()); + byte[] bpmnBytes = getModelBpmnXML(model.getId()); if (bpmnBytes == null) { throw exception(MODEL_NOT_EXISTS); } // 1.3 校验表单已配 - BpmFormDO form = checkFormConfig(model.getMetaInfo()); + BpmFormDO form = validateFormConfig(model.getMetaInfo()); // 1.4 校验任务分配规则已配置 taskCandidateInvoker.validateBpmnConfig(bpmnBytes); @@ -194,7 +163,7 @@ public class BpmModelServiceImpl implements BpmModelService { @Transactional(rollbackFor = Exception.class) public void deleteModel(String id) { // 校验流程模型存在 - Model model = repositoryService.getModel(id); + Model model = getModel(id); if (model == null) { throw exception(MODEL_NOT_EXISTS); } @@ -206,33 +175,27 @@ public class BpmModelServiceImpl implements BpmModelService { @Override public void updateModelState(String id, Integer state) { - // 校验流程模型存在 - Model model = repositoryService.getModel(id); + // 1.1 校验流程模型存在 + Model model = getModel(id); if (model == null) { throw exception(MODEL_NOT_EXISTS); } - // 校验流程定义存在 + // 1.2 校验流程定义存在 ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } - // 更新状态 + // 2. 更新状态 processDefinitionService.updateProcessDefinitionState(definition.getId(), state); } - @Override - public BpmnModel getBpmnModel(String id) { - byte[] bpmnBytes = repositoryService.getModelEditorSource(id); - return BpmnModelUtils.getBpmnModel(bpmnBytes); - } - @Override public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) { return repositoryService.getBpmnModel(processDefinitionId); } - private void checkKeyNCName(String key) { + private void validateKeyNCName(String key) { if (!ValidationUtils.isXmlNCName(key)) { throw exception(MODEL_KEY_VALID); } @@ -244,7 +207,7 @@ public class BpmModelServiceImpl implements BpmModelService { * @param metaInfoStr 流程模型 metaInfo 字段 * @return 流程表单 */ - private BpmFormDO checkFormConfig(String metaInfoStr) { + private BpmFormDO validateFormConfig(String metaInfoStr) { BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(metaInfoStr, BpmModelMetaInfoRespDTO.class); if (metaInfo == null || metaInfo.getFormType() == null) { throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); @@ -282,4 +245,18 @@ public class BpmModelServiceImpl implements BpmModelService { processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode()); } + private Model getModelByKey(String key) { + return repositoryService.createModelQuery().modelKey(key).singleResult(); + } + + @Override + public Model getModel(String id) { + return repositoryService.getModel(id); + } + + @Override + public byte[] getModelBpmnXML(String id) { + return repositoryService.getModelEditorSource(id); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java index 5f6d5f148..163fc24aa 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -1,17 +1,14 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import jakarta.validation.Valid; -import org.flowable.bpmn.model.BpmnModel; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -33,15 +30,15 @@ public interface BpmProcessDefinitionService { * @param pageReqVO 分页入参 * @return 流程定义 Page */ - PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO); + PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO); /** * 获得流程定义列表 * - * @param listReqVO 列表入参 + * @param suspensionState 中断状态 * @return 流程定义列表 */ - List getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO); + List getProcessDefinitionListBySuspensionState(Integer suspensionState); /** * 创建流程定义 @@ -68,20 +65,24 @@ public interface BpmProcessDefinitionService { String getProcessDefinitionBpmnXML(String id); /** - * 获得需要创建的流程定义,是否和当前激活的流程定义相等 + * 获得流程定义的信息 * - * @param createReqDTO 创建信息 - * @return 是否相等 + * @param id 流程定义编号 + * @return 流程定义信息 */ - boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); + BpmProcessDefinitionInfoDO getProcessDefinitionInfo(String id); /** - * 获得编号对应的 BpmProcessDefinitionExtDO + * 获得流程定义的信息 List * - * @param id 编号 - * @return 流程定义拓展 + * @param ids 流程定义编号数组 + * @return 流程额定义信息数组 */ - BpmProcessDefinitionExtDO getProcessDefinitionExt(String id); + List getProcessDefinitionInfoList(Collection ids); + + default Map getProcessDefinitionInfoMap(Set ids) { + return convertMap(getProcessDefinitionInfoList(ids), BpmProcessDefinitionInfoDO::getProcessDefinitionId); + } /** * 获得编号对应的 ProcessDefinition @@ -153,11 +154,4 @@ public interface BpmProcessDefinitionService { */ Deployment getDeployment(String id); - /** - * 获得 Bpmn 模型 - * - * @param processDefinitionId 流程定义的编号 - * @return Bpmn 模型 - */ - BpmnModel getBpmnModel(String processDefinitionId); } 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 ef8fd6e4d..20a9ee95b 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 @@ -1,21 +1,15 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.PageUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; -import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +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.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; @@ -33,7 +27,7 @@ import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH; import static java.util.Collections.emptyList; @@ -55,10 +49,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ private RepositoryService repositoryService; @Resource - private BpmProcessDefinitionExtMapper processDefinitionMapper; - - @Resource - private BpmFormService formService; + private BpmProcessDefinitionInfoMapper processDefinitionMapper; @Override public ProcessDefinition getProcessDefinition(String id) { @@ -111,11 +102,6 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ return repositoryService.createDeploymentQuery().deploymentId(id).singleResult(); } - @Override - public BpmnModel getBpmnModel(String processDefinitionId) { - return repositoryService.getBpmnModel(processDefinitionId); - } - @Override public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { // 创建 Deployment 部署 @@ -141,7 +127,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } // 插入拓展表 - BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO) + BpmProcessDefinitionInfoDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO) .setProcessDefinitionId(definition.getId()); processDefinitionMapper.insert(definitionDO); return definition.getId(); @@ -175,101 +161,43 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } @Override - public boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { - // 校验 name、description 是否更新 - ProcessDefinition oldProcessDefinition = getActiveProcessDefinition(createReqDTO.getKey()); - if (oldProcessDefinition == null) { - return false; - } - BpmProcessDefinitionExtDO oldProcessDefinitionExt = getProcessDefinitionExt(oldProcessDefinition.getId()); - if (!StrUtil.equals(createReqDTO.getName(), oldProcessDefinition.getName()) - || !StrUtil.equals(createReqDTO.getDescription(), oldProcessDefinitionExt.getDescription()) - || !StrUtil.equals(createReqDTO.getCategory(), oldProcessDefinition.getCategory())) { - return false; - } - // 校验 form 信息是否更新 - if (!ObjectUtil.equal(createReqDTO.getFormType(), oldProcessDefinitionExt.getFormType()) - || !ObjectUtil.equal(createReqDTO.getFormId(), oldProcessDefinitionExt.getFormId()) - || !ObjectUtil.equal(createReqDTO.getFormConf(), oldProcessDefinitionExt.getFormConf()) - || !ObjectUtil.equal(createReqDTO.getFormFields(), oldProcessDefinitionExt.getFormFields()) - || !ObjectUtil.equal(createReqDTO.getFormCustomCreatePath(), oldProcessDefinitionExt.getFormCustomCreatePath()) - || !ObjectUtil.equal(createReqDTO.getFormCustomViewPath(), oldProcessDefinitionExt.getFormCustomViewPath())) { - return false; - } - // 校验 BPMN XML 信息 - BpmnModel newModel = BpmnModelUtils.getBpmnModel(createReqDTO.getBpmnBytes()); - BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); - // 对比字节变化 - if (!BpmnModelUtils.equals(oldModel, newModel)) { - return false; - } - // 最终发现都一致,则返回 true - return true; - } - - @Override - public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) { + public BpmProcessDefinitionInfoDO getProcessDefinitionInfo(String id) { return processDefinitionMapper.selectByProcessDefinitionId(id); } @Override - public List getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO) { - // 拼接查询条件 - ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery(); - if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), listReqVO.getSuspensionState())) { - definitionQuery.suspended(); - } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), listReqVO.getSuspensionState())) { - definitionQuery.active(); - } - // 执行查询 - definitionQuery.processDefinitionTenantId(TenantContextHolder.getTenantIdStr()); - List processDefinitions = definitionQuery.list(); - if (CollUtil.isEmpty(processDefinitions)) { - return Collections.emptyList(); - } - - // 获得 BpmProcessDefinitionDO Map - List processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds( - convertList(processDefinitions, ProcessDefinition::getId)); - Map processDefinitionDOMap = convertMap(processDefinitionDOs, - BpmProcessDefinitionExtDO::getProcessDefinitionId); - // 执行查询,并返回 - return BpmProcessDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap); + public List getProcessDefinitionInfoList(Collection ids) { + return processDefinitionMapper.selectListByProcessDefinitionIds(ids); } @Override - public PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) { - ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery(); + public PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) { + ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); if (StrUtil.isNotBlank(pageVO.getKey())) { - definitionQuery.processDefinitionKey(pageVO.getKey()); + query.processDefinitionKey(pageVO.getKey()); } - // 执行查询 - List processDefinitions = definitionQuery.orderByProcessDefinitionVersion().desc() - .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); - - if (CollUtil.isEmpty(processDefinitions)) { - return new PageResult<>(emptyList(), definitionQuery.count()); + long count = query.count(); + if (count == 0) { + return PageResult.empty(count); } - // 获得 Deployment Map - Set deploymentIds = new HashSet<>(); - processDefinitions.forEach(definition -> addIfNotNull(deploymentIds, definition.getDeploymentId())); - Map deploymentMap = getDeploymentMap(deploymentIds); + List list = query.orderByProcessDefinitionVersion().desc() + .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(list, count); + } - // 获得 BpmProcessDefinitionDO Map - List processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds( - convertList(processDefinitions, ProcessDefinition::getId)); - Map processDefinitionDOMap = convertMap(processDefinitionDOs, - BpmProcessDefinitionExtDO::getProcessDefinitionId); - - // 获得 Form Map - Set formIds = convertSet(processDefinitionDOs, BpmProcessDefinitionExtDO::getFormId); - Map formMap = formService.getFormMap(formIds); - - // 拼接结果 - long definitionCount = definitionQuery.count(); - return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap, - processDefinitionDOMap, formMap), definitionCount); + @Override + public List getProcessDefinitionListBySuspensionState(Integer suspensionState) { + // 拼接查询条件 + ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), suspensionState)) { + query.suspended(); + } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), suspensionState)) { + query.active(); + } + // 执行查询 + query.processDefinitionTenantId(TenantContextHolder.getTenantIdStr()); + return query.list(); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java index eb715edb4..ae3f38a96 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java @@ -40,7 +40,6 @@ public class BpmProcessDefinitionCreateReqDTO { private String description; /** * 流程分类 - * 参见 bpm_model_category 数据字典 */ @NotEmpty(message = "流程分类不能为空") private String category; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java index 67135167a..bd84490e8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; import java.util.Collection; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java index e45ce881c..aba8bd9f1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; -import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceCopyMapper; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import jakarta.annotation.Resource; 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 6b81092ac..f9a44482b 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml new file mode 100644 index 000000000..cf0954503 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java new file mode 100644 index 000000000..19f576818 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.bpm.service.category; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryServiceImpl; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.category.BpmCategoryMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link BpmCategoryServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(BpmCategoryServiceImpl.class) +public class BpmCategoryServiceImplTest extends BaseDbUnitTest { + + @Resource + private BpmCategoryServiceImpl categoryService; + + @Resource + private BpmCategoryMapper categoryMapper; + + @Test + public void testCreateCategory_success() { + // 准备参数 + BpmCategorySaveReqVO createReqVO = randomPojo(BpmCategorySaveReqVO.class).setId(null); + + // 调用 + Long categoryId = categoryService.createCategory(createReqVO); + // 断言 + assertNotNull(categoryId); + // 校验记录的属性是否正确 + BpmCategoryDO category = categoryMapper.selectById(categoryId); + assertPojoEquals(createReqVO, category, "id"); + } + + @Test + public void testUpdateCategory_success() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class, o -> { + o.setId(dbCategory.getId()); // 设置更新的 ID + }); + + // 调用 + categoryService.updateCategory(updateReqVO); + // 校验是否更新正确 + BpmCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, category); + } + + @Test + public void testUpdateCategory_notExists() { + // 准备参数 + BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS); + } + + @Test + public void testDeleteCategory_success() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class); + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbCategory.getId(); + + // 调用 + categoryService.deleteCategory(id); + // 校验数据不存在了 + assertNull(categoryMapper.selectById(id)); + } + + @Test + public void testDeleteCategory_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetCategoryPage() { + // mock 数据 + BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class, o -> { // 等会查询到 + o.setName(null); + o.setCode(null); + o.setStatus(null); + o.setCreateTime(null); + }); + categoryMapper.insert(dbCategory); + // 测试 name 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName(null))); + // 测试 code 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCode(null))); + // 测试 status 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(null))); + // 测试 createTime 不匹配 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCreateTime(null))); + // 准备参数 + BpmCategoryPageReqVO reqVO = new BpmCategoryPageReqVO(); + reqVO.setName(null); + reqVO.setCode(null); + reqVO.setStatus(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = categoryService.getCategoryPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbCategory, pageResult.getList().get(0)); + } + +} \ No newline at end of file From 29a0fbfc4339b942d4236ec25eb1ac52c1e216ed Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 20 Mar 2024 12:50:51 +0800 Subject: [PATCH 16/26] =?UTF-8?q?BPM=EF=BC=9A=E6=94=AF=E6=8C=81=E5=A4=9A?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=EF=BC=8C=E6=AF=8F=E4=B8=AA=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E9=83=BD=E5=8F=AF=E4=BB=A5=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/BpmProcessInstanceCreateReqDTO.java | 2 +- .../admin/task/BpmTaskController.java | 10 +++- .../BpmProcessInstanceCreateReqVO.java | 2 +- .../task/vo/task/BpmTaskApproveReqVO.java | 4 ++ .../admin/task/vo/task/BpmTaskRespVO.java | 14 ++++- .../convert/definition/BpmModelConvert.java | 5 +- .../task/BpmProcessInstanceConvert.java | 11 ++-- .../bpm/convert/task/BpmTaskConvert.java | 47 +++++++--------- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 5 +- .../flowable/core/util/FlowableUtils.java | 56 +++++++++++++++++++ 11 files changed, 117 insertions(+), 41 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java index b20a449df..629742bc8 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java @@ -20,7 +20,7 @@ public class BpmProcessInstanceCreateReqDTO { @NotEmpty(message = "流程定义的标识不能为空") private String processDefinitionKey; /** - * 变量实例 + * 变量实例(动态表单) */ private Map variables; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index 6e17a0901..c00f4beb4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 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; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -46,6 +48,8 @@ public class BpmTaskController { private BpmTaskService taskService; @Resource private BpmProcessInstanceService processInstanceService; + @Resource + private BpmFormService formService; @Resource private AdminUserApi adminUserApi; @@ -98,7 +102,11 @@ public class BpmTaskController { Map userMap = adminUserApi.getUserMap(userIds); Map deptMap = deptApi.getDeptMap( convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, userMap, deptMap)); + // 获得 Form Map + Map formMap = formService.getFormMap( + convertSet(taskList, task -> Long.parseLong(task.getFormKey()))); + return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, + formMap, userMap, deptMap)); } @PutMapping("/approve") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java index 93c22dddc..f47749861 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java @@ -15,7 +15,7 @@ public class BpmProcessInstanceCreateReqVO { @NotEmpty(message = "流程定义编号不能为空") private String processDefinitionId; - @Schema(description = "变量实例") + @Schema(description = "变量实例(动态表单)") private Map variables; // TODO @hai:assignees 复数 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index c5ca09b37..0be06a6c8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -5,6 +5,7 @@ import jakarta.validation.constraints.NotEmpty; import lombok.Data; import java.util.Collection; +import java.util.Map; @Schema(description = "管理后台 - 通过流程任务的 Request VO") @Data @@ -21,4 +22,7 @@ public class BpmTaskApproveReqVO { @Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2") private Collection copyUserIds; + @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) + private Map variables; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 46ac3f36d..27add6000 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -6,6 +6,7 @@ import lombok.Data; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; @Schema(description = "管理后台 - 流程任务 Response VO") @Data @@ -49,7 +50,6 @@ public class BpmTaskRespVO { @Schema(description = "所属流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8888") private String processInstanceId; - /** * 所属流程实例 */ @@ -57,10 +57,20 @@ public class BpmTaskRespVO { @Schema(description = "父任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String parentTaskId; - @Schema(description = "子任务列表(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask") private List children; + @Schema(description = "表单编号", example = "1024") + private Long formId; + @Schema(description = "表单名字", example = "请假表单") + private String formName; + @Schema(description = "表单的配置-JSON 字符串") + private String formConf; + @Schema(description = "表单项的数组") + private List formFields; + @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) + private Map formVariables; + @Data @Schema(description = "流程实例") public static class ProcessInstance { 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 a0abde8c6..7bcd82a1b 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 @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.convert.definition; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -56,7 +57,9 @@ public interface BpmModelConvert { byte[] bpmnBytes) { BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); - modelVO.setBpmnXml(new String(bpmnBytes)); + if (ArrayUtil.isNotEmpty(bpmnBytes)) { + modelVO.setBpmnXml(new String(bpmnBytes)); + } return modelVO; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index a7c621590..b1129b2d4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -2,15 +2,14 @@ package cn.iocoder.yudao.module.bpm.convert.task; 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.BeanUtils; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -19,7 +18,6 @@ import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; -import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; @@ -32,7 +30,6 @@ import java.util.Map; * * @author 芋道源码 */ -@Mapper(uses = DateUtils.class) public interface BpmProcessInstanceConvert { BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); @@ -44,7 +41,7 @@ public interface BpmProcessInstanceConvert { PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); for (int i = 0; i < pageResult.getList().size(); i++) { BpmProcessInstancePageItemRespVO respVO = vpPageResult.getList().get(i); - respVO.setStatus((Integer) pageResult.getList().get(i).getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); + respVO.setStatus(FlowableUtils.getProcessInstanceStatus(pageResult.getList().get(i))); MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), processDefinition -> respVO.setCategory(processDefinition.getCategory())); MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); @@ -57,8 +54,8 @@ public interface BpmProcessInstanceConvert { ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionExt, String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { BpmProcessInstanceRespVO respVO = convert2(processInstance); - respVO.setStatus((Integer) processInstance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); - respVO.setFormVariables(processInstance.getProcessVariables()); // TODO 芋艿:真的这么搞么???formVariable 要不要换个 key 之类的 + respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)); + respVO.setFormVariables(FlowableUtils.filterProcessInstanceFormVariable(processInstance.getProcessVariables())); // definition respVO.setProcessDefinition(convert2(processDefinition)); copyTo(processDefinitionExt, respVO.getProcessDefinition()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index e9f04f498..625282b0f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -1,14 +1,15 @@ package cn.iocoder.yudao.module.bpm.convert.task; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -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.BeanUtils; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -17,7 +18,6 @@ import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; -import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.util.Date; @@ -25,13 +25,13 @@ import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; /** * Bpm 任务 Convert * * @author 芋道源码 */ -@Mapper(uses = DateUtils.class) public interface BpmTaskConvert { BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); @@ -45,8 +45,7 @@ public interface BpmTaskConvert { return; } AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); }); } @@ -55,14 +54,13 @@ public interface BpmTaskConvert { Map userMap) { List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); - taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); - taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); + taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); // 流程实例 HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); if (processInstance != null) { AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); } return taskVO; }); @@ -71,32 +69,32 @@ public interface BpmTaskConvert { default List buildTaskListByProcessInstanceId(List taskList, HistoricProcessInstance processInstance, + Map formMap, Map userMap, Map deptMap) { List taskVOList = CollectionUtils.convertList(taskList, task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); - taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS)); - taskVO.setReason((String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON)); + taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); // 流程实例 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); - taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class, - processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)))); + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); + taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + // 表单信息 + BpmFormDO form = MapUtil.get(formMap, Long.parseLong(task.getFormKey()), BpmFormDO.class); + if (form != null) { + taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) + .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); + } // 用户信息 AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); if (assignUser != null) { taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); - DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); - if (dept != null) { - taskVO.getAssigneeUser().setDeptName(dept.getName()); - } + findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName())); } AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); if (ownerUser != null) { taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); - DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); - if (dept != null) { - taskVO.getOwnerUser().setDeptName(dept.getName()); - } + findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); } return taskVO; }); @@ -126,10 +124,7 @@ public interface BpmTaskConvert { AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner())); if (ownerUser != null) { taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); - DeptRespDTO dept = deptMap.get(ownerUser.getDeptId()); - if (dept != null) { - taskVO.getOwnerUser().setDeptName(dept.getName()); - } + findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); } })); } 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 f9a44482b..b6b9b142e 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file 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 aa1fc6345..95c5e7cf4 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 @@ -10,6 +10,7 @@ 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; @@ -185,7 +186,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 3.3 调用 BPM complete 去完成任务 - taskService.complete(task.getId(), instance.getProcessVariables()); + // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 + Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); + taskService.complete(task.getId(), variables, true); // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java index d69798995..7863bece9 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java @@ -4,8 +4,14 @@ import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.api.variable.VariableContainer; import org.flowable.common.engine.impl.el.ExpressionManager; import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.TaskInfo; + +import java.util.HashMap; +import java.util.Map; /** * Flowable 相关的工具方法 @@ -34,6 +40,56 @@ public class FlowableUtils { return activityId + "_assignee"; } + // ========== ProcessInstance 相关的工具方法 ========== + + public static Integer getProcessInstanceStatus(ProcessInstance processInstance) { + return getProcessInstanceStatus(processInstance.getProcessVariables()); + } + + public static Integer getProcessInstanceStatus(HistoricProcessInstance processInstance) { + return getProcessInstanceStatus(processInstance.getProcessVariables()); + } + + // TODO 芋艿:需要再搞搞 + private static Integer getProcessInstanceStatus(Map processVariables) { + return (Integer) processVariables.get("PROCESS_STATUS"); + } + + public static Map getProcessInstanceFormVariable(ProcessInstance processInstance) { + Map formVariables = new HashMap<>(processInstance.getProcessVariables()); + filterProcessInstanceFormVariable(formVariables); + return formVariables; + } + + public static Map filterProcessInstanceFormVariable(Map processVariables) { + processVariables.remove("PROCESS_STATUS"); + return processVariables; + } + + // ========== Task 相关的工具方法 ========== + + // TODO 芋艿:需要再搞搞 + + public static Integer getTaskStatus(TaskInfo task) { + return (Integer) task.getTaskLocalVariables().get("TASK_STATUS"); + } + + public static String getTaskReason(TaskInfo task) { + return (String) task.getTaskLocalVariables().get("TASK_REASON"); + } + + public static Map getTaskFormVariable(TaskInfo task) { + Map formVariables = new HashMap<>(task.getTaskLocalVariables()); + filterTaskFormVariable(formVariables); + return formVariables; + } + + public static Map filterTaskFormVariable(Map taskLocalVariables) { + taskLocalVariables.remove("TASK_STATUS"); + taskLocalVariables.remove("TASK_REASON"); + return taskLocalVariables; + } + // ========== Expression 相关的工具方法 ========== public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) { From 559bab571ae6a1d80febdaee675bb24fa54e44b3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 20 Mar 2024 13:14:53 +0800 Subject: [PATCH 17/26] =?UTF-8?q?BPM=EF=BC=9A=E7=A7=BB=E9=99=A4=20flowable?= =?UTF-8?q?=20starter=20=E6=A8=A1=E5=9D=97=EF=BC=8C=E8=9E=8D=E5=90=88?= =?UTF-8?q?=E5=88=B0=20bpm=20=E6=A8=A1=E5=9D=97=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-bpm/pom.xml | 1 - yudao-module-bpm/yudao-module-bpm-biz/pom.xml | 16 ++-- .../task/BpmProcessInstanceConvert.java | 2 +- .../bpm/convert/task/BpmTaskConvert.java | 2 +- .../bpm/framework}/FlowableContextHolder.java | 3 +- .../bpm/config/BpmCommonConfiguration.java | 19 ----- .../bpm/core/event/package-info.java | 6 -- .../bpm/framework/bpm/core/package-info.java | 4 - .../bpm/framework/bpm/package-info.java | 6 -- .../config/BpmFlowableConfiguration.java | 32 ++++++++ .../BpmParallelMultiInstanceBehavior.java | 6 +- .../BpmSequentialMultiInstanceBehavior.java | 6 +- .../candidate/BpmTaskCandidateInvoker.java | 2 +- .../BpmTaskCandidateExpressionStrategy.java | 2 +- ...pmProcessInstanceResultEventPublisher.java | 2 +- .../flowable/core/util/BpmnModelUtils.java | 2 +- .../flowable/core/util/FlowableUtils.java | 80 ++++++++++++++++--- .../web/config/BpmWebConfiguration.java | 14 ++++ .../web/core}/FlowableWebFilter.java | 11 +-- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 4 +- ...pmTaskCandidateExpressionStrategyTest.java | 2 +- .../pom.xml | 37 --------- .../config/YudaoFlowableConfiguration.java | 46 ----------- ...ot.autoconfigure.AutoConfiguration.imports | 1 - 25 files changed, 148 insertions(+), 160 deletions(-) rename yudao-module-bpm/{yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context => yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework}/FlowableContextHolder.java (91%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/{bpm => flowable}/core/event/BpmProcessInstanceResultEventPublisher.java (90%) rename yudao-module-bpm/{yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao => yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm}/framework/flowable/core/util/BpmnModelUtils.java (99%) rename yudao-module-bpm/{yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao => yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm}/framework/flowable/core/util/FlowableUtils.java (57%) rename yudao-module-bpm/{yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web => yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core}/FlowableWebFilter.java (84%) delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/yudao-module-bpm/pom.xml b/yudao-module-bpm/pom.xml index 491c99771..95b798904 100644 --- a/yudao-module-bpm/pom.xml +++ b/yudao-module-bpm/pom.xml @@ -11,7 +11,6 @@ yudao-module-bpm-api yudao-module-bpm-biz - yudao-spring-boot-starter-flowable yudao-module-bpm pom diff --git a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml index 1a4b410e8..1ac423e11 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml @@ -64,15 +64,19 @@ yudao-spring-boot-starter-test - - - cn.iocoder.boot - yudao-spring-boot-starter-flowable - ${revision} - + cn.iocoder.boot yudao-spring-boot-starter-excel + + + org.flowable + flowable-spring-boot-starter-process + + + org.flowable + flowable-spring-boot-starter-actuator + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index b1129b2d4..7a73dabdc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 625282b0f..82593b08c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java similarity index 91% rename from yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java index efc6d5340..6e4fb99e3 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.flowable.core.context; +package cn.iocoder.yudao.module.bpm.framework; import cn.hutool.core.collection.CollUtil; import com.alibaba.ttl.TransmittableThreadLocal; @@ -10,6 +10,7 @@ import java.util.Map; /** * 工作流--用户用到的上下文相关信息 */ +@Deprecated // TODO 芋艿:找个方式,去掉这个上下文 public class FlowableContextHolder { private static final ThreadLocal>> ASSIGNEE = new TransmittableThreadLocal<>(); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java deleted file mode 100644 index 7a6ca7711..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.bpm.config; - -import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * BPM 通用的 Configuration 配置类,提供给 Activiti 和 Flowable - */ -@Configuration(proxyBeanMethods = false) -public class BpmCommonConfiguration { - - @Bean - public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) { - return new BpmProcessInstanceResultEventPublisher(publisher); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java deleted file mode 100644 index c4a131128..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 自定义 Event 实现,提供方便业务接入的 Listener! - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java deleted file mode 100644 index b97cb4c8a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占位 - */ -package cn.iocoder.yudao.module.bpm.framework.bpm.core; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java deleted file mode 100644 index 9a5e3ea96..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 提供给 Activiti 和 Flowable 的通用封装 - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.module.bpm.framework.bpm; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java index 9248da552..979d19153 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -4,13 +4,18 @@ import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.AsyncListenableTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.List; @@ -22,6 +27,26 @@ import java.util.List; @Configuration(proxyBeanMethods = false) public class BpmFlowableConfiguration { + /** + * 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean + * + * 如果不创建,会导致项目启动时,Flowable 报错的问题 + */ + @Bean(name = "applicationTaskExecutor") + @ConditionalOnMissingBean(name = "applicationTaskExecutor") + public AsyncListenableTaskExecutor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(8); + executor.setMaxPoolSize(8); + executor.setQueueCapacity(100); + executor.setThreadNamePrefix("flowable-task-Executor-"); + executor.setAwaitTerminationSeconds(30); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAllowCoreThreadTimeOut(true); + executor.initialize(); + return executor; + } + /** * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类: * @@ -56,4 +81,11 @@ public class BpmFlowableConfiguration { return new BpmTaskCandidateInvoker(strategyList, adminUserApi); } + // =========== 自己拓展的 Bean ========== + + @Bean + public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) { + return new BpmProcessInstanceResultEventPublisher(publisher); + } + } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index 938d04ed1..64ebb1aac 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import org.flowable.bpmn.model.Activity; @@ -43,9 +43,9 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav // 第一步,设置 collectionVariable 和 CollectionVariable // 从 execution.getVariable() 读取所有任务处理人的 key super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 - super.collectionVariable = FlowableUtils.formatCollectionVariable(execution.getCurrentActivityId()); + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); // 从 execution.getVariable() 读取当前所有任务处理的人的 key - super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); // 第二步,获取任务的所有处理人 Set assigneeUserIds = taskCandidateInvoker.calculateUsers(execution); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java index 1e4ebc141..a214e2625 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import org.flowable.bpmn.model.Activity; @@ -37,9 +37,9 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB // 第一步,设置 collectionVariable 和 CollectionVariable // 从 execution.getVariable() 读取所有任务处理人的 key super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 - super.collectionVariable = FlowableUtils.formatCollectionVariable(execution.getCurrentActivityId()); + super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); // 从 execution.getVariable() 读取当前所有任务处理的人的 key - super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); + super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); // 第二步,获取任务的所有处理人 Set assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!! diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java index d1ba65df2..e1fb62632 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -5,7 +5,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java index f8be5fe3e..e51ab76e0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; import org.dromara.hutool.core.convert.Convert; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java similarity index 90% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java index b759fe1e1..7457e3d23 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.event; import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; import lombok.AllArgsConstructor; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java similarity index 99% rename from yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 264dd7ec6..a72a4b396 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.flowable.core.util; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java similarity index 57% rename from yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index 7863bece9..3fceb60fd 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -1,5 +1,6 @@ -package cn.iocoder.yudao.framework.flowable.core.util; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.api.variable.VariableContainer; import org.flowable.common.engine.impl.el.ExpressionManager; @@ -32,11 +33,23 @@ public class FlowableUtils { // ========== Execution 相关的工具方法 ========== - public static String formatCollectionVariable(String activityId) { + /** + * 格式化多实例(并签、或签)的 collectionVariable 变量(多实例对应的多审批人列表) + * + * @param activityId 活动编号 + * @return collectionVariable 变量 + */ + public static String formatExecutionCollectionVariable(String activityId) { return activityId + "_assignees"; } - public static String formatCollectionElementVariable(String activityId) { + /** + * 格式化多实例(并签、或签)的 collectionElementVariable 变量(当前实例对应的一个审批人) + * + * @param activityId 活动编号 + * @return collectionElementVariable 变量 + */ + public static String formatExecutionCollectionElementVariable(String activityId) { return activityId + "_assignee"; } @@ -50,43 +63,86 @@ public class FlowableUtils { return getProcessInstanceStatus(processInstance.getProcessVariables()); } - // TODO 芋艿:需要再搞搞 + /** + * 获得流程实例的状态 + * + * @param processVariables 流程实例的 variables + * @return 状态 + */ private static Integer getProcessInstanceStatus(Map processVariables) { - return (Integer) processVariables.get("PROCESS_STATUS"); + return (Integer) processVariables.get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); } + /** + * 获得流程实例的表单 + * + * @param processInstance 流程实例 + * @return 表单 + */ public static Map getProcessInstanceFormVariable(ProcessInstance processInstance) { Map formVariables = new HashMap<>(processInstance.getProcessVariables()); filterProcessInstanceFormVariable(formVariables); return formVariables; } + /** + * 过滤流程实例的表单 + * + * 为什么要过滤?目前使用 processVariables 存储所有流程实例的拓展字段,需要过滤掉一部分的系统字段,从而实现表单的展示 + * + * @param processVariables 流程实例的 variables + * @return 过滤后的表单 + */ public static Map filterProcessInstanceFormVariable(Map processVariables) { - processVariables.remove("PROCESS_STATUS"); + processVariables.remove(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); return processVariables; } // ========== Task 相关的工具方法 ========== - // TODO 芋艿:需要再搞搞 - + /** + * 获得任务的状态 + * + * @param task 任务 + * @return 状态 + */ public static Integer getTaskStatus(TaskInfo task) { - return (Integer) task.getTaskLocalVariables().get("TASK_STATUS"); + return (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); } + /** + * 获得任务的审批原因 + * + * @param task 任务 + * @return 审批原因 + */ public static String getTaskReason(TaskInfo task) { - return (String) task.getTaskLocalVariables().get("TASK_REASON"); + return (String) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_REASON); } + /** + * 获得任务的表单 + * + * @param task 任务 + * @return 表单 + */ public static Map getTaskFormVariable(TaskInfo task) { Map formVariables = new HashMap<>(task.getTaskLocalVariables()); filterTaskFormVariable(formVariables); return formVariables; } + /** + * 过滤任务的表单 + * + * 为什么要过滤?目前使用 taskLocalVariables 存储所有任务的拓展字段,需要过滤掉一部分的系统字段,从而实现表单的展示 + * + * @param taskLocalVariables 任务的 taskLocalVariables + * @return 过滤后的表单 + */ public static Map filterTaskFormVariable(Map taskLocalVariables) { - taskLocalVariables.remove("TASK_STATUS"); - taskLocalVariables.remove("TASK_REASON"); + taskLocalVariables.remove(BpmConstants.TASK_VARIABLE_STATUS); + taskLocalVariables.remove(BpmConstants.TASK_VARIABLE_REASON); return taskLocalVariables; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java index aa9daedab..d4af61c9b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/config/BpmWebConfiguration.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.bpm.framework.web.config; +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import cn.iocoder.yudao.module.bpm.framework.web.core.FlowableWebFilter; import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -21,4 +24,15 @@ public class BpmWebConfiguration { return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("bpm"); } + /** + * 配置 Flowable Web 过滤器 + */ + @Bean + public FilterRegistrationBean flowableWebFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new FlowableWebFilter()); + registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); + return registrationBean; + } + } diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java similarity index 84% rename from yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java index d2135290f..29fc7c3bf 100644 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/web/core/FlowableWebFilter.java @@ -1,16 +1,17 @@ -package cn.iocoder.yudao.framework.flowable.core.web; +package cn.iocoder.yudao.module.bpm.framework.web.core; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import org.springframework.web.filter.OncePerRequestFilter; - +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + import java.io.IOException; + /** - * flowable Web 过滤器,将 userId 设置到 {@link org.flowable.common.engine.impl.identity.Authentication} 中 + * Flowable Web 过滤器,将 userId 设置到 {@link org.flowable.common.engine.impl.identity.Authentication} 中 * * @author jason */ 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 b6b9b142e..26b4cefa4 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.framework.flowable.core.context.FlowableContextHolder; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file 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 95c5e7cf4..dc89a670f 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 @@ -9,8 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +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.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java index caa668eac..eaa2ef7b5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import org.flowable.engine.delegate.DelegateExecution; import org.junit.jupiter.api.Test; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml b/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml deleted file mode 100644 index ae0ed46ee..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-bpm - ${revision} - - 4.0.0 - - yudao-spring-boot-starter-flowable - - - - cn.iocoder.boot - yudao-common - - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - org.flowable - flowable-spring-boot-starter-process - - - org.flowable - flowable-spring-boot-starter-actuator - - - - diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java deleted file mode 100644 index 859eca510..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.config; - -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.flowable.core.web.FlowableWebFilter; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.core.task.AsyncListenableTaskExecutor; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -@AutoConfiguration -public class YudaoFlowableConfiguration { - - /** - * 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean - * - * 如果不创建,会导致项目启动时,Flowable 报错的问题 - */ - @Bean(name = "applicationTaskExecutor") - @ConditionalOnMissingBean(name = "applicationTaskExecutor") - public AsyncListenableTaskExecutor taskExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(8); - executor.setMaxPoolSize(8); - executor.setQueueCapacity(100); - executor.setThreadNamePrefix("flowable-task-Executor-"); - executor.setAwaitTerminationSeconds(30); - executor.setWaitForTasksToCompleteOnShutdown(true); - executor.setAllowCoreThreadTimeOut(true); - executor.initialize(); - return executor; - } - - /** - * 配置 flowable Web 过滤器 - */ - @Bean - public FilterRegistrationBean flowableWebFilter() { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new FlowableWebFilter()); - registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); - return registrationBean; - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 1df61598c..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.yudao.framework.flowable.config.YudaoFlowableConfiguration \ No newline at end of file From c104191821afd7fa7cd1a1e935aaa9deb85f9f3d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 20 Mar 2024 18:51:36 +0800 Subject: [PATCH 18/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=BC=BA=20model=20?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=A8=A1=E5=9E=8B=E9=83=A8=E7=BD=B2=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=90=84=E7=A7=8D=E5=8F=82=E6=95=B0=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 10 +-- .../admin/definition/BpmModelController.java | 3 +- .../admin/task/BpmTaskController.java | 2 +- .../convert/definition/BpmModelConvert.java | 34 ++------- .../BpmProcessDefinitionConvert.java | 3 - .../bpm/convert/task/BpmTaskConvert.java | 2 +- .../flowable/core/util/BpmnModelUtils.java | 27 ++----- .../service/definition/BpmFormService.java | 8 -- .../definition/BpmFormServiceImpl.java | 23 +----- .../definition/BpmModelServiceImpl.java | 74 +++++++++++-------- .../BpmProcessDefinitionService.java | 14 ++-- .../BpmProcessDefinitionServiceImpl.java | 31 ++++---- .../dto/BpmModelMetaInfoRespDTO.java | 2 + .../dto/BpmProcessDefinitionCreateReqDTO.java | 26 +------ 14 files changed, 98 insertions(+), 161 deletions(-) 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 494e4a1b5..310e1b623 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 @@ -10,16 +10,9 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; public interface ErrorCodeConstants { // ========== 通用流程处理 模块 1-009-000-000 ========== - ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1_009_000_002, "获取高亮流程图异常"); // ========== OA 流程模块 1-009-001-000 ========== ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1_009_001_001, "请假申请不存在"); - ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_002, "项目经理岗位未设置"); - ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_009, "部门的项目经理不存在"); - ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_004, "部门经理岗位未设置"); - ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_005, "部门的部门经理不存在"); - ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1_009_001_006, "HR岗位未设置"); - ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1_009_001_007, "请假天数必须>=1"); // ========== 流程模型 1-009-002-000 ========== ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程"); @@ -28,7 +21,8 @@ public interface ErrorCodeConstants { ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); ErrorCode MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + "原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置"); - ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化"); + ErrorCode MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS = new ErrorCode(1_009_002_005, "部署流程失败,原因:BPMN 流程图中,没有开始事件"); + ErrorCode MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS = new ErrorCode(1_009_002_006, "部署流程失败,原因:BPMN 流程图中,用户任务({})的名字不存在"); // ========== 流程定义 1-009-003-000 ========== ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1_009_003_000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图"); 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 4143076ff..dcf91260f 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 @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.io.IoUtils; 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.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; @@ -112,7 +113,7 @@ public class BpmModelController { @Operation(summary = "导入模型") @PreAuthorize("@ss.hasPermission('bpm:model:import')") public CommonResult importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException { - BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO); + BpmModelCreateReqVO createReqVO = BeanUtils.toBean(importReqVO, BpmModelCreateReqVO.class); // 读取文件 String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false); return success(modelService.createModel(createReqVO, bpmnXml)); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index c00f4beb4..d721cf7a8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -104,7 +104,7 @@ public class BpmTaskController { convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 获得 Form Map Map formMap = formService.getFormMap( - convertSet(taskList, task -> Long.parseLong(task.getFormKey()))); + convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, formMap, userMap, deptMap)); } 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 7bcd82a1b..373e71bf3 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 @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.definition.vo.model.BpmModeImportReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; @@ -15,13 +14,11 @@ 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.service.definition.dto.BpmModelMetaInfoRespDTO; -import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; import java.util.List; @@ -43,7 +40,7 @@ public interface BpmModelConvert { Map categoryMap, Map deploymentMap, Map processDefinitionMap) { List list = CollectionUtils.convertList(pageResult.getList(), model -> { - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; BpmCategoryDO category = categoryMap.get(model.getCategory()); Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; @@ -55,7 +52,7 @@ public interface BpmModelConvert { default BpmModelRespVO buildModel(Model model, byte[] bpmnBytes) { - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); if (ArrayUtil.isNotEmpty(bpmnBytes)) { modelVO.setBpmnXml(new String(bpmnBytes)); @@ -95,27 +92,6 @@ public interface BpmModelConvert { return modelRespVO; } - BpmModelCreateReqVO convert(BpmModeImportReqVO bean); - - default BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDO form) { - BpmProcessDefinitionCreateReqDTO createReqDTO = new BpmProcessDefinitionCreateReqDTO(); - createReqDTO.setModelId(model.getId()); - createReqDTO.setName(model.getName()); - createReqDTO.setKey(model.getKey()); - createReqDTO.setCategory(model.getCategory()); - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); - // metaInfo - copyTo(metaInfo, createReqDTO); - // form - if (form != null) { - createReqDTO.setFormConf(form.getConf()); - createReqDTO.setFormFields(form.getFields()); - } - return createReqDTO; - } - - void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to); - default void copyToCreateModel(Model model, BpmModelCreateReqVO bean) { model.setName(bean.getName()); model.setKey(bean.getKey()); @@ -126,7 +102,7 @@ public interface BpmModelConvert { default void copyToUpdateModel(Model model, BpmModelUpdateReqVO bean) { model.setName(bean.getName()); model.setCategory(bean.getCategory()); - model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class), + model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), bean.getDescription(), bean.getFormType(), bean.getFormId(), bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); } @@ -149,4 +125,8 @@ public interface BpmModelConvert { return JsonUtils.toJsonString(metaInfo); } + default BpmModelMetaInfoRespDTO buildMetaInfo(Model model) { + return JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index f1e945178..1b5897dd5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -10,7 +10,6 @@ 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.dal.dataobject.definition.BpmProcessDefinitionInfoDO; -import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; @@ -69,8 +68,6 @@ public interface BpmProcessDefinitionConvert { }); } - BpmProcessDefinitionInfoDO convert2(BpmProcessDefinitionCreateReqDTO bean); - @Mapping(source = "from.id", target = "to.id", ignore = true) void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 82593b08c..ac1da99a0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -80,7 +80,7 @@ public interface BpmTaskConvert { taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); // 表单信息 - BpmFormDO form = MapUtil.get(formMap, Long.parseLong(task.getFormKey()), BpmFormDO.class); + BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); if (form != null) { taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index a72a4b396..9763bc8a6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -71,26 +71,15 @@ public class BpmnModelUtils { return result; } - /** - * 比较 两个bpmnModel 是否相同 - * @param oldModel 老的bpmn model - * @param newModel 新的bpmn model - */ - public static boolean equals(BpmnModel oldModel, BpmnModel newModel) { - // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较 - return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel)); - } - - /** - * 把 bpmnModel 转换成 byte[] - * @param model bpmnModel - */ - public static byte[] getBpmnBytes(BpmnModel model) { - if (model == null) { - return new byte[0]; + public static StartEvent getStartEvent(BpmnModel model) { + Process process = model.getMainProcess(); + // 从 initialFlowElement 找 + FlowElement startElement = process.getInitialFlowElement(); + if (startElement instanceof StartEvent) { + return (StartEvent) startElement; } - BpmnXMLConverter converter = new BpmnXMLConverter(); - return converter.convertToXML(model); + // 从 flowElementList 找 + return (StartEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof StartEvent); } public static BpmnModel getBpmnModel(byte[] bpmnBytes) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java index 9c61ae427..fa9484708 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java @@ -83,12 +83,4 @@ public interface BpmFormService { */ PageResult getFormPage(BpmFormPageReqVO pageReqVO); - /** - * 校验流程表单已配置 - * - * @param configStr configStr 字段 - * @return 流程表单 - */ - BpmFormDO checkFormConfig(String configStr); - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java index d805da6a6..057512995 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -11,17 +11,14 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; -import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 动态表单 Service 实现类 @@ -92,24 +89,6 @@ public class BpmFormServiceImpl implements BpmFormService { return formMapper.selectPage(pageReqVO); } - // TODO @芋艿:这里没搞完! - @Override - public BpmFormDO checkFormConfig(String configStr) { - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(configStr, BpmModelMetaInfoRespDTO.class); - if (metaInfo == null || metaInfo.getFormType() == null) { - throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); - } - // 校验表单存在 - if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { - BpmFormDO form = getForm(metaInfo.getFormId()); - if (form == null) { - throw exception(FORM_NOT_EXISTS); - } - return form; - } - return null; - } - /** * 校验 Field,避免 field 重复 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 933a0b5bf..511b4902a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -13,12 +13,14 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; -import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Model; @@ -85,7 +87,9 @@ public class BpmModelServiceImpl implements BpmModelService { @Override @Transactional(rollbackFor = Exception.class) public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { - validateKeyNCName(createReqVO.getKey()); + if (!ValidationUtils.isXmlNCName(createReqVO.getName())) { + throw exception(MODEL_KEY_VALID); + } // 校验流程标识已经存在 Model keyModel = getModelByKey(createReqVO.getKey()); if (keyModel != null) { @@ -129,26 +133,16 @@ public class BpmModelServiceImpl implements BpmModelService { throw exception(MODEL_NOT_EXISTS); } // 1.2 校验流程图 - // TODO 芋艿:校验流程图的有效性;例如说,是否有开始的元素,是否有结束的元素; byte[] bpmnBytes = getModelBpmnXML(model.getId()); - if (bpmnBytes == null) { - throw exception(MODEL_NOT_EXISTS); - } + validateBpmnXml(bpmnBytes); // 1.3 校验表单已配 - BpmFormDO form = validateFormConfig(model.getMetaInfo()); + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmFormDO form = validateFormConfig(metaInfo); // 1.4 校验任务分配规则已配置 taskCandidateInvoker.validateBpmnConfig(bpmnBytes); - // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 - BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) - .setBpmnBytes(bpmnBytes); - // TODO @芋艿:这里比较可能有点问题 -// if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 -// throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); -// } - // 2.1 创建流程定义 - String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO); + String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form); // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。 updateProcessDefinitionSuspended(model.getDeploymentId()); @@ -159,6 +153,25 @@ public class BpmModelServiceImpl implements BpmModelService { repositoryService.saveModel(model); } + private void validateBpmnXml(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + if (bpmnModel == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 1. 没有 StartEvent + StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); + if (startEvent == null) { + throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS); + } + // 2. 校验 UserTask 的 name 都配置了 + List userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + userTasks.forEach(userTask -> { + if (StrUtil.isEmpty(userTask.getName())) { + throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); + } + }); + } + @Override @Transactional(rollbackFor = Exception.class) public void deleteModel(String id) { @@ -195,32 +208,32 @@ public class BpmModelServiceImpl implements BpmModelService { return repositoryService.getBpmnModel(processDefinitionId); } - private void validateKeyNCName(String key) { - if (!ValidationUtils.isXmlNCName(key)) { - throw exception(MODEL_KEY_VALID); - } - } - /** * 校验流程表单已配置 * - * @param metaInfoStr 流程模型 metaInfo 字段 - * @return 流程表单 + * @param metaInfo 流程模型元数据 + * @return 表单配置 */ - private BpmFormDO validateFormConfig(String metaInfoStr) { - BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(metaInfoStr, BpmModelMetaInfoRespDTO.class); + private BpmFormDO validateFormConfig(BpmModelMetaInfoRespDTO metaInfo) { if (metaInfo == null || metaInfo.getFormType() == null) { throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); } // 校验表单存在 if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { + if (metaInfo.getFormId() == null) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId()); if (form == null) { throw exception(FORM_NOT_EXISTS); } return form; + } else { + if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath()) || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + return null; } - return null; } private void saveModelBpmnXml(Model model, String bpmnXml) { @@ -231,8 +244,11 @@ public class BpmModelServiceImpl implements BpmModelService { } /** - * 挂起 deploymentId 对应的流程定义。 这里一个deploymentId 只关联一个流程定义 - * @param deploymentId 流程发布Id. + * 挂起 deploymentId 对应的流程定义 + * + * 注意:这里一个 deploymentId 只关联一个流程定义 + * + * @param deploymentId 流程发布Id */ private void updateProcessDefinitionSuspended(String deploymentId) { if (StrUtil.isEmpty(deploymentId)) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java index 163fc24aa..7126d652e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -2,10 +2,11 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; -import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; -import jakarta.validation.Valid; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; import java.util.Collection; @@ -41,12 +42,15 @@ public interface BpmProcessDefinitionService { List getProcessDefinitionListBySuspensionState(Integer suspensionState); /** - * 创建流程定义 + * 基于流程模型,创建流程定义 * - * @param createReqDTO 创建信息 + * @param model 流程模型 + * @param modelMetaInfo 流程模型元信息 + * @param bpmnBytes BPMN XML 字节数组 + * @param form 表单 * @return 流程编号 */ - String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); + String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, byte[] bpmnBytes, BpmFormDO form); /** * 更新流程定义状态 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 20a9ee95b..85418fb83 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 @@ -3,22 +3,23 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; 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.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import jakarta.annotation.Resource; -import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; import org.springframework.stereotype.Service; @@ -103,11 +104,12 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } @Override - public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { + public String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, + byte[] bpmnBytes, BpmFormDO form) { // 创建 Deployment 部署 Deployment deploy = repositoryService.createDeployment() - .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) - .addBytes(createReqDTO.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) + .key(model.getKey()).name(model.getName()).category(model.getCategory()) + .addBytes(model.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, bpmnBytes) .tenantId(TenantContextHolder.getTenantIdStr()) .disableSchemaValidation() // 禁用 XML Schema 验证,因为有自定义的属性 .deploy(); @@ -115,20 +117,23 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ // 设置 ProcessDefinition 的 category 分类 ProcessDefinition definition = repositoryService.createProcessDefinitionQuery() .deploymentId(deploy.getId()).singleResult(); - repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory()); + repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory()); // 注意 1,ProcessDefinition 的 key 和 name 是通过 BPMN 中的 的 id 和 name 决定 // 注意 2,目前该项目的设计上,需要保证 Model、Deployment、ProcessDefinition 使用相同的 key,保证关联性。 // 否则,会导致 ProcessDefinition 的分页无法查询到。 - if (!Objects.equals(definition.getKey(), createReqDTO.getKey())) { - throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, createReqDTO.getKey(), definition.getKey()); + if (!Objects.equals(definition.getKey(), model.getKey())) { + throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, model.getKey(), definition.getKey()); } - if (!Objects.equals(definition.getName(), createReqDTO.getName())) { - throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, createReqDTO.getName(), definition.getName()); + if (!Objects.equals(definition.getName(), model.getName())) { + throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, model.getName(), definition.getName()); } // 插入拓展表 - BpmProcessDefinitionInfoDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO) - .setProcessDefinitionId(definition.getId()); + BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) + .setModelId(model.getId()).setProcessDefinitionId(definition.getId()); + if (form != null) { + definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); + } processDefinitionMapper.insert(definitionDO); return definition.getId(); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java index 3a36b0eeb..5b4ef3da5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java @@ -7,6 +7,8 @@ import lombok.Data; * BPM 流程 MetaInfo Response DTO * 主要用于 { Model#setMetaInfo(String)} 的存储 * + * 最终,它的字段和 {@link cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO} 是一致的 + * * @author 芋道源码 */ @Data diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java index ae3f38a96..4008f8f07 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java @@ -1,15 +1,11 @@ package cn.iocoder.yudao.module.bpm.service.definition.dto; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; -import lombok.Data; - -import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.Data; + import java.util.List; -import java.util.Objects; /** * 流程定义创建 Request DTO @@ -82,22 +78,4 @@ public class BpmProcessDefinitionCreateReqDTO { */ private String formCustomViewPath; - @AssertTrue(message = "流程表单信息不全") - public boolean isNormalFormTypeValid() { - // 如果非业务表单,则直接通过 - if (!Objects.equals(formType, BpmModelFormTypeEnum.NORMAL.getType())) { - return true; - } - return formId != null && StrUtil.isNotEmpty(formConf) && CollUtil.isNotEmpty(formFields); - } - - @AssertTrue(message = "业务表单信息不全") - public boolean isNormalCustomTypeValid() { - // 如果非业务表单,则直接通过 - if (!Objects.equals(formType, BpmModelFormTypeEnum.CUSTOM.getType())) { - return true; - } - return StrUtil.isNotEmpty(formCustomCreatePath) && StrUtil.isNotEmpty(formCustomViewPath); - } - } From e5444c5d47a2f71d6d0acfe998eaf763acbcaef8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 20 Mar 2024 21:32:01 +0800 Subject: [PATCH 19/26] =?UTF-8?q?BPM=EF=BC=9A=E4=BC=98=E5=8C=96=20convert?= =?UTF-8?q?=20=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ava => BpmProcessInstanceStatusEvent.java} | 11 ++- ...pmProcessInstanceStatusEventListener.java} | 10 +-- .../admin/definition/BpmFormController.java | 34 +++++---- .../definition/vo/form/BpmFormBaseVO.java | 24 ------- .../vo/form/BpmFormCreateReqVO.java | 22 ------ .../definition/vo/form/BpmFormRespVO.java | 22 ++++-- .../definition/vo/form/BpmFormSaveReqVO.java | 34 +++++++++ .../vo/form/BpmFormSimpleRespVO.java | 16 ----- .../vo/form/BpmFormUpdateReqVO.java | 25 ------- .../process/BpmProcessDefinitionRespVO.java | 7 +- .../admin/oa/BpmOALeaveController.java | 19 +++-- .../admin/oa/vo/BpmOALeaveBaseVO.java | 33 --------- .../admin/oa/vo/BpmOALeaveCreateReqVO.java | 32 +++++++-- .../admin/oa/vo/BpmOALeavePageReqVO.java | 18 +++-- .../admin/oa/vo/BpmOALeaveRespVO.java | 30 ++++---- .../task/BpmProcessInstanceController.java | 35 ++++++++- .../task/vo/activity/BpmActivityRespVO.java | 4 +- .../BpmProcessInstancePageItemRespVO.java | 54 -------------- .../vo/instance/BpmProcessInstanceRespVO.java | 39 +++++----- .../admin/task/vo/task/BpmTaskRespVO.java | 3 - .../convert/definition/BpmFormConvert.java | 34 --------- .../bpm/convert/oa/BpmOALeaveConvert.java | 30 -------- .../task/BpmProcessInstanceConvert.java | 72 ++++++++----------- .../bpm/convert/task/BpmTaskConvert.java | 4 +- .../bpm/dal/dataobject/oa/BpmOALeaveDO.java | 6 +- .../bpm/dal/mysql/oa/BpmOALeaveMapper.java | 2 +- ...pmProcessInstanceResultEventPublisher.java | 6 +- .../service/definition/BpmFormService.java | 7 +- .../definition/BpmFormServiceImpl.java | 21 +++--- .../definition/BpmModelServiceImpl.java | 2 +- .../bpm/service/oa/BpmOALeaveService.java | 4 +- .../bpm/service/oa/BpmOALeaveServiceImpl.java | 12 ++-- ...ner.java => BpmOALeaveStatusListener.java} | 10 +-- .../task/BpmProcessInstanceService.java | 9 --- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 8 ++- .../mapper/category/BpmCategoryMapper.xml | 12 ---- .../definition/BpmFormServiceTest.java | 4 +- .../definition/BpmUserGroupServiceTest.java | 5 +- .../src/test/resources/sql/create_tables.sql | 2 +- ...er.java => CrmContractStatusListener.java} | 10 +-- ....java => CrmReceivableStatusListener.java} | 10 +-- .../src/main/resources/application.yaml | 2 +- 43 files changed, 287 insertions(+), 459 deletions(-) rename yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/{BpmProcessInstanceResultEvent.java => BpmProcessInstanceStatusEvent.java} (65%) rename yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/{BpmProcessInstanceResultEventListener.java => BpmProcessInstanceStatusEventListener.java} (63%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/{BpmOALeaveResultListener.java => BpmOALeaveStatusListener.java} (58%) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/{CrmContractResultListener.java => CrmContractStatusListener.java} (65%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/{CrmReceivableResultListener.java => CrmReceivableStatusListener.java} (65%) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java similarity index 65% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java index 9b703728d..f32094843 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEvent.java @@ -5,14 +5,13 @@ import lombok.Data; import org.springframework.context.ApplicationEvent; /** - * 流程实例的结果发生变化的 Event - * 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件 + * 流程实例的状态(结果)发生变化的 Event * * @author 芋道源码 */ @SuppressWarnings("ALL") @Data -public class BpmProcessInstanceResultEvent extends ApplicationEvent { +public class BpmProcessInstanceStatusEvent extends ApplicationEvent { /** * 流程实例的编号 @@ -27,15 +26,15 @@ public class BpmProcessInstanceResultEvent extends ApplicationEvent { /** * 流程实例的结果 */ - @NotNull(message = "流程实例的结果不能为空") - private Integer result; + @NotNull(message = "流程实例的状态不能为空") + private Integer status; /** * 流程实例对应的业务标识 * 例如说,请假 */ private String businessKey; - public BpmProcessInstanceResultEvent(Object source) { + public BpmProcessInstanceStatusEvent(Object source) { super(source); } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java similarity index 63% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java index bff99a8c1..f8b1863c6 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceStatusEventListener.java @@ -4,15 +4,15 @@ import cn.hutool.core.util.StrUtil; import org.springframework.context.ApplicationListener; /** - * {@link BpmProcessInstanceResultEvent} 的监听器 + * {@link BpmProcessInstanceStatusEvent} 的监听器 * * @author 芋道源码 */ -public abstract class BpmProcessInstanceResultEventListener - implements ApplicationListener { +public abstract class BpmProcessInstanceStatusEventListener + implements ApplicationListener { @Override - public final void onApplicationEvent(BpmProcessInstanceResultEvent event) { + public final void onApplicationEvent(BpmProcessInstanceStatusEvent event) { if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) { return; } @@ -29,6 +29,6 @@ public abstract class BpmProcessInstanceResultEventListener * * @param event 事件 */ - protected abstract void onEvent(BpmProcessInstanceResultEvent event); + protected abstract void onEvent(BpmProcessInstanceStatusEvent event); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java index b5065ed48..b957a75a7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java @@ -1,23 +1,26 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.*; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; -import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - 动态表单") @RestController @@ -31,14 +34,14 @@ public class BpmFormController { @PostMapping("/create") @Operation(summary = "创建动态表单") @PreAuthorize("@ss.hasPermission('bpm:form:create')") - public CommonResult createForm(@Valid @RequestBody BpmFormCreateReqVO createReqVO) { + public CommonResult createForm(@Valid @RequestBody BpmFormSaveReqVO createReqVO) { return success(formService.createForm(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新动态表单") @PreAuthorize("@ss.hasPermission('bpm:form:update')") - public CommonResult updateForm(@Valid @RequestBody BpmFormUpdateReqVO updateReqVO) { + public CommonResult updateForm(@Valid @RequestBody BpmFormSaveReqVO updateReqVO) { formService.updateForm(updateReqVO); return success(true); } @@ -58,14 +61,15 @@ public class BpmFormController { @PreAuthorize("@ss.hasPermission('bpm:form:query')") public CommonResult getForm(@RequestParam("id") Long id) { BpmFormDO form = formService.getForm(id); - return success(BpmFormConvert.INSTANCE.convert(form)); + return success(BeanUtils.toBean(form, BpmFormRespVO.class)); } - @GetMapping("/list-all-simple") + @GetMapping({"/list-all-simple", "/simple-list"}) @Operation(summary = "获得动态表单的精简列表", description = "用于表单下拉框") - public CommonResult> getSimpleForms() { + public CommonResult> getFormSimpleList() { List list = formService.getFormList(); - return success(BpmFormConvert.INSTANCE.convertList2(list)); + return success(convertList(list, formDO -> // 只返回 id、name 字段 + new BpmFormRespVO().setId(formDO.getId()).setName(formDO.getName()))); } @GetMapping("/page") @@ -73,7 +77,7 @@ public class BpmFormController { @PreAuthorize("@ss.hasPermission('bpm:form:query')") public CommonResult> getFormPage(@Valid BpmFormPageReqVO pageVO) { PageResult pageResult = formService.getFormPage(pageVO); - return success(BpmFormConvert.INSTANCE.convertPage(pageResult)); + return success(BeanUtils.toBean(pageResult, BpmFormRespVO.class)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java deleted file mode 100644 index fcc0cc167..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import jakarta.validation.constraints.*; - -/** -* 动态表单 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ -@Data -public class BpmFormBaseVO { - - @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - @NotNull(message = "表单名称不能为空") - private String name; - - @Schema(description = "表单状态-参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "表单状态不能为空") - private Integer status; - - @Schema(description = "备注", example = "我是备注") - private String remark; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java deleted file mode 100644 index aa014a584..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import jakarta.validation.constraints.NotNull; -import java.util.List; - -@Schema(description = "管理后台 - 动态表单创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmFormCreateReqVO extends BpmFormBaseVO { - - @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "表单的配置不能为空") - private String conf; - - @Schema(description = "表单项的数组-JSON 字符串的数组", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "表单项的数组不能为空") - private List fields; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java index b8c8f531f..1c4eb762c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java @@ -1,22 +1,23 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import lombok.Data; + import java.time.LocalDateTime; import java.util.List; @Schema(description = "管理后台 - 动态表单 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmFormRespVO extends BpmFormBaseVO { +public class BpmFormRespVO { @Schema(description = "表单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; + @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表单名称不能为空") + private String name; + @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "表单的配置不能为空") private String conf; @@ -25,6 +26,13 @@ public class BpmFormRespVO extends BpmFormBaseVO { @NotNull(message = "表单项的数组不能为空") private List fields; + @Schema(description = "表单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表单状态不能为空") + private Integer status; // 参见 CommonStatusEnum 枚举 + + @Schema(description = "备注", example = "我是备注") + private String remark; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java new file mode 100644 index 000000000..4da13aaf8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import jakarta.validation.constraints.NotNull; +import java.util.List; + +@Schema(description = "管理后台 - 动态表单创建/更新 Request VO") +@Data +public class BpmFormSaveReqVO { + + @Schema(description = "表单编号", example = "1024") + private Long id; + + @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + @NotNull(message = "表单名称不能为空") + private String name; + + @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单的配置不能为空") + private String conf; + + @Schema(description = "表单项的数组-JSON 字符串的数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "表单项的数组不能为空") + private List fields; + + @Schema(description = "表单状态-参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表单状态不能为空") + private Integer status; + + @Schema(description = "备注", example = "我是备注") + private String remark; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java deleted file mode 100644 index 71d8a1f80..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - 流程表单精简 Response VO") -@Data -public class BpmFormSimpleRespVO { - - @Schema(description = "表单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long id; - - @Schema(description = "表单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java deleted file mode 100644 index 424854780..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import jakarta.validation.constraints.*; -import java.util.List; - -@Schema(description = "管理后台 - 动态表单更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmFormUpdateReqVO extends BpmFormBaseVO { - - @Schema(description = "表单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "表单编号不能为空") - private Long id; - - @Schema(description = "表单的配置-JSON 字符串", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "表单的配置不能为空") - private String conf; - - @Schema(description = "表单项的数组-JSON 字符串的数组", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "表单项的数组不能为空") - private List fields; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index bf015920e..4fa56d4a3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -50,7 +50,10 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer suspensionState; - @Schema(description = "部署时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取 + @Schema(description = "部署时间") + private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取,非必须返回 + + @Schema(description = "BPMN XML") + private String bpmnXml; // 需要从对应的 BpmnModel 读取,非必须返回 } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java index b964694a5..144749450 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java @@ -1,23 +1,22 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO; -import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; - import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -49,7 +48,7 @@ public class BpmOALeaveController { @Parameter(name = "id", description = "编号", required = true, example = "1024") public CommonResult getLeave(@RequestParam("id") Long id) { BpmOALeaveDO leave = leaveService.getLeave(id); - return success(BpmOALeaveConvert.INSTANCE.convert(leave)); + return success(BeanUtils.toBean(leave, BpmOALeaveRespVO.class)); } @GetMapping("/page") @@ -57,7 +56,7 @@ public class BpmOALeaveController { @Operation(summary = "获得请假申请分页") public CommonResult> getLeavePage(@Valid BpmOALeavePageReqVO pageVO) { PageResult pageResult = leaveService.getLeavePage(getLoginUserId(), pageVO); - return success(BpmOALeaveConvert.INSTANCE.convertPage(pageResult)); + return success(BeanUtils.toBean(pageResult, BpmOALeaveRespVO.class)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java deleted file mode 100644 index f7089f859..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.time.LocalDateTime; -import jakarta.validation.constraints.*; -import org.springframework.format.annotation.DateTimeFormat; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -/** -* 请假申请 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ -@Data -public class BpmOALeaveBaseVO { - - @Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "开始时间不能为空") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime startTime; - @Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "结束时间不能为空") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime endTime; - - @Schema(description = "请假类型-参见 bpm_oa_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer type; - - @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") - private String reason; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java index 56ee98b33..8f84a281d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java @@ -1,16 +1,34 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - 请假申请创建 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmOALeaveCreateReqVO extends BpmOALeaveBaseVO { +public class BpmOALeaveCreateReqVO { + + @Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + + @Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + + @Schema(description = "请假类型-参见 bpm_oa_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") + private String reason; @AssertTrue(message = "结束时间,需要在开始时间之后") public boolean isEndTimeValid() { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java index 903a0fcf2..a754370cc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java @@ -1,10 +1,14 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.time.LocalDateTime; + import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - 请假申请分页 Request VO") @@ -13,13 +17,13 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class BpmOALeavePageReqVO extends PageParam { - @Schema(description = "状态-参见 bpm_process_instance_result 枚举", example = "1") - private Integer result; + @Schema(description = "状态", example = "1") + private Integer status; // 参见 BpmProcessInstanceResultEnum 枚举 - @Schema(description = "请假类型-参见 bpm_oa_type", example = "1") + @Schema(description = "请假类型,参见 bpm_oa_type", example = "1") private Integer type; - @Schema(description = "原因-模糊匹配", example = "阅读芋道源码") + @Schema(description = "原因,模糊匹配", example = "阅读芋道源码") private String reason; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java index 669e309e7..dbfe9d90f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java @@ -1,32 +1,36 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import org.springframework.format.annotation.DateTimeFormat; +import lombok.Data; -import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - @Schema(description = "管理后台 - 请假申请 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmOALeaveRespVO extends BpmOALeaveBaseVO { +public class BpmOALeaveRespVO { @Schema(description = "请假表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; - @Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer result; + @Schema(description = "请假类型,参见 bpm_oa_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") + private String reason; @Schema(description = "申请时间", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请时间不能为空") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime createTime; - @Schema(description = "流程id") + @Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + + @Schema(description = "流程编号") private String processInstanceId; + @Schema(description = "审批结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 + } 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 05c845827..2db6b76f9 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 @@ -3,13 +3,19 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +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; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -45,10 +51,15 @@ public class BpmProcessInstanceController { @Resource private BpmCategoryService categoryService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @GetMapping("/my-page") @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") - public CommonResult> getMyProcessInstancePage( + public CommonResult> getMyProcessInstancePage( @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { PageResult pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { @@ -62,7 +73,8 @@ public class BpmProcessInstanceController { convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); Map categoryMap = categoryService.getCategoryMap( convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); - return success(BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, processDefinitionMap, categoryMap, taskMap)); + return success(BpmProcessInstanceConvert.INSTANCE.buildMyProcessInstancePage(pageResult, + processDefinitionMap, categoryMap, taskMap)); } @PostMapping("/create") @@ -77,7 +89,24 @@ public class BpmProcessInstanceController { @Parameter(name = "id", description = "流程实例的编号", required = true) @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult getProcessInstance(@RequestParam("id") String id) { - return success(processInstanceService.getProcessInstanceVO(id)); + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(id); + if (processInstance == null) { + return success(null); + } + + // 拼接返回 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( + processInstance.getProcessDefinitionId()); + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( + processInstance.getProcessDefinitionId()); + String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); + AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); + DeptRespDTO dept = null; + if (startUser != null) { + dept = deptApi.getDept(startUser.getDeptId()); + } + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstance(processInstance, + processDefinition, processDefinitionInfo, bpmnXml, startUser, dept)); } @DeleteMapping("/cancel") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java index ab6468204..8f959e093 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java @@ -19,7 +19,7 @@ public class BpmActivityRespVO { @Schema(description = "流程活动的结束时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime endTime; - @Schema(description = "关联的流程任务的编号-关联的流程任务,只有 UserTask 等类型才有", example = "2048") - private String taskId; + @Schema(description = "关联的流程任务的编号", example = "2048") + private String taskId; // 关联的流程任务,只有 UserTask 等类型才有 } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java deleted file mode 100644 index f1763a27f..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java +++ /dev/null @@ -1,54 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; -import java.util.List; - -// TODO @芋艿:是不是要融合? -@Schema(description = "管理后台 - 流程实例的分页 Item Response VO") -@Data -public class BpmProcessInstancePageItemRespVO { - - @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - - @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") - private String processDefinitionId; - - @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private String category; - @Schema(description = "流程分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假") - private String categoryName; - - @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 - - @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime startTime; - - @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime endTime; - - /** - * 当前任务 - */ - private List tasks; - - @Schema(description = "流程任务") - @Data - public static class Task { - - @Schema(description = "流程任务的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String id; - - @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - private String name; - - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java index e0410e6be..d6e67dd34 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -19,12 +20,14 @@ public class BpmProcessInstanceRespVO { @Schema(description = "流程分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String category; + @Schema(description = "流程分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "请假") + private String categoryName; @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; + private LocalDateTime startTime; @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime endTime; @@ -40,10 +43,17 @@ public class BpmProcessInstanceRespVO { */ private User startUser; + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String processDefinitionId; /** * 流程定义 */ - private ProcessDefinition processDefinition; + private BpmProcessDefinitionRespVO processDefinition; + + /** + * 当前审批中的任务 + */ + private List tasks; // 仅在流程实例分页才返回 @Schema(description = "用户信息") @Data @@ -61,30 +71,15 @@ public class BpmProcessInstanceRespVO { } - @Schema(description = "流程定义信息") + @Schema(description = "流程任务") @Data - public static class ProcessDefinition { + public static class Task { - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Schema(description = "流程任务的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String id; - @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") - private Integer formType; - @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") - private Long formId; - @Schema(description = "表单的配置-JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) - private String formConf; - @Schema(description = "表单项的数组-JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", requiredMode = Schema.RequiredMode.REQUIRED) - private List formFields; - @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/create") - private String formCustomCreatePath; - @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/view") - private String formCustomViewPath; - - @Schema(description = "BPMN XML", requiredMode = Schema.RequiredMode.REQUIRED) - private String bpmnXml; + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 27add6000..26b8e80b0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -42,9 +42,6 @@ public class BpmTaskRespVO { */ private BpmProcessInstanceRespVO.User assigneeUser; - // TODO @芋艿:这个 key 有点问题,应该是 taskDefinitionId - @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "user-001") - private String definitionKey; @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one") private String taskDefinitionKey; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java deleted file mode 100644 index 6ba757417..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.definition; - -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSimpleRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -/** - * 动态表单 Convert - * - * @author 芋艿 - */ -@Mapper -public interface BpmFormConvert { - - BpmFormConvert INSTANCE = Mappers.getMapper(BpmFormConvert.class); - - BpmFormDO convert(BpmFormCreateReqVO bean); - - BpmFormDO convert(BpmFormUpdateReqVO bean); - - BpmFormRespVO convert(BpmFormDO bean); - - List convertList2(List list); - - PageResult convertPage(PageResult page); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java deleted file mode 100644 index f87531bfc..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.oa; - -import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -/** - * 请假申请 Convert - * - * @author 芋艿 - */ -@Mapper -public interface BpmOALeaveConvert { - - BpmOALeaveConvert INSTANCE = Mappers.getMapper(BpmOALeaveConvert.class); - - BpmOALeaveDO convert(BpmOALeaveCreateReqVO bean); - - BpmOALeaveRespVO convert(BpmOALeaveDO bean); - - List convertList(List list); - - PageResult convertPage(PageResult page); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 7a73dabdc..1f6e38a3d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -4,12 +4,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -18,6 +18,7 @@ import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; +import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; @@ -30,39 +31,43 @@ import java.util.Map; * * @author 芋道源码 */ +@Mapper public interface BpmProcessInstanceConvert { BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); - default PageResult convertPage(PageResult pageResult, - Map processDefinitionMap, - Map categoryMap, - Map> taskMap) { - PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); + default PageResult buildMyProcessInstancePage(PageResult pageResult, + Map processDefinitionMap, + Map categoryMap, + Map> taskMap) { + PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstanceRespVO.class); for (int i = 0; i < pageResult.getList().size(); i++) { - BpmProcessInstancePageItemRespVO respVO = vpPageResult.getList().get(i); + BpmProcessInstanceRespVO respVO = vpPageResult.getList().get(i); respVO.setStatus(FlowableUtils.getProcessInstanceStatus(pageResult.getList().get(i))); MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), processDefinition -> respVO.setCategory(processDefinition.getCategory())); MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); - respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstancePageItemRespVO.Task.class)); + respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class)); } return vpPageResult; } - default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, - ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionExt, - String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { - BpmProcessInstanceRespVO respVO = convert2(processInstance); + default BpmProcessInstanceRespVO buildProcessInstance(HistoricProcessInstance processInstance, + ProcessDefinition processDefinition, + BpmProcessDefinitionInfoDO processDefinitionExt, + String bpmnXml, + AdminUserRespDTO startUser, + DeptRespDTO dept) { + BpmProcessInstanceRespVO respVO = BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class); respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)); respVO.setFormVariables(FlowableUtils.filterProcessInstanceFormVariable(processInstance.getProcessVariables())); // definition - respVO.setProcessDefinition(convert2(processDefinition)); + respVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class)); copyTo(processDefinitionExt, respVO.getProcessDefinition()); respVO.getProcessDefinition().setBpmnXml(bpmnXml); // user if (startUser != null) { - respVO.setStartUser(convert2(startUser)); + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); if (dept != null) { respVO.getStartUser().setDeptName(dept.getName()); } @@ -70,42 +75,27 @@ public interface BpmProcessInstanceConvert { return respVO; } - BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean); - - BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); - @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to); + void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); - BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean); - - default BpmProcessInstanceResultEvent convert(Object source, HistoricProcessInstance instance, Integer result) { - BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); - event.setId(instance.getId()); - event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); - event.setBusinessKey(instance.getBusinessKey()); - event.setResult(result); - return event; + default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, HistoricProcessInstance instance, Integer status) { + return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status) + .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey()); } - // TODO @芋艿:需要改下 key! - default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { - BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); - event.setId(instance.getId()); - event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); - event.setBusinessKey(instance.getBusinessKey()); - event.setResult(result); - return event; + default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {; + return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status) + .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey()); } - default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){ - return new BpmMessageSendWhenProcessInstanceApproveReqDTO() + default BpmMessageSendWhenProcessInstanceApproveReqDTO buildProcessInstanceApproveMessage(ProcessInstance instance) { + return new BpmMessageSendWhenProcessInstanceApproveReqDTO() .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())) .setProcessInstanceId(instance.getId()) .setProcessInstanceName(instance.getName()); } - default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String reason) { + default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) { return new BpmMessageSendWhenProcessInstanceRejectReqDTO() .setProcessInstanceName(instance.getName()) .setProcessInstanceId(instance.getId()) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index ac1da99a0..67b882c95 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -6,10 +6,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -18,6 +18,7 @@ import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; +import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; import java.util.Date; @@ -32,6 +33,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAnd * * @author 芋道源码 */ +@Mapper public interface BpmTaskConvert { BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java index e24ce02ad..ca21b538c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -57,12 +57,12 @@ public class BpmOALeaveDO extends BaseDO { */ private Long day; /** - * 请假的结果 + * 审批结果 * * 枚举 {@link BpmTaskStatustEnum} - * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 + * 考虑到简单,所以直接复用了 BpmProcessInstanceStatusEnum 枚举,也可以自己定义一个枚举哈 */ - private Integer result; + private Integer status; /** * 对应的流程编号 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java index ad05b9804..278787450 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java @@ -19,7 +19,7 @@ public interface BpmOALeaveMapper extends BaseMapperX { default PageResult selectPage(Long userId, BpmOALeavePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(BpmOALeaveDO::getUserId, userId) - .eqIfPresent(BpmOALeaveDO::getResult, reqVO.getResult()) + .eqIfPresent(BpmOALeaveDO::getStatus, reqVO.getStatus()) .eqIfPresent(BpmOALeaveDO::getType, reqVO.getType()) .likeIfPresent(BpmOALeaveDO::getReason, reqVO.getReason()) .betweenIfPresent(BpmOALeaveDO::getCreateTime, reqVO.getCreateTime()) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java index 7457e3d23..bf85c58c8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.event; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; import lombok.AllArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.validation.annotation.Validated; @@ -8,7 +8,7 @@ import org.springframework.validation.annotation.Validated; import jakarta.validation.Valid; /** - * {@link BpmProcessInstanceResultEvent} 的生产者 + * {@link BpmProcessInstanceStatusEvent} 的生产者 * * @author 芋道源码 */ @@ -18,7 +18,7 @@ public class BpmProcessInstanceResultEventPublisher { private final ApplicationEventPublisher publisher; - public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceResultEvent event) { + public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceStatusEvent event) { publisher.publishEvent(event); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java index fa9484708..3c8425084 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java @@ -2,9 +2,8 @@ package cn.iocoder.yudao.module.bpm.service.definition; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import jakarta.validation.Valid; @@ -26,14 +25,14 @@ public interface BpmFormService { * @param createReqVO 创建信息 * @return 编号 */ - Long createForm(@Valid BpmFormCreateReqVO createReqVO); + Long createForm(@Valid BpmFormSaveReqVO createReqVO); /** * 更新动态表单 * * @param updateReqVO 更新信息 */ - void updateForm(@Valid BpmFormUpdateReqVO updateReqVO); + void updateForm(@Valid BpmFormSaveReqVO updateReqVO); /** * 删除动态表单 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java index 057512995..95f275993 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -4,10 +4,9 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; -import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; @@ -33,22 +32,22 @@ public class BpmFormServiceImpl implements BpmFormService { private BpmFormMapper formMapper; @Override - public Long createForm(BpmFormCreateReqVO createReqVO) { - this.checkFields(createReqVO.getFields()); + public Long createForm(BpmFormSaveReqVO createReqVO) { + this.vadateFields(createReqVO.getFields()); // 插入 - BpmFormDO form = BpmFormConvert.INSTANCE.convert(createReqVO); + BpmFormDO form = BeanUtils.toBean(createReqVO, BpmFormDO.class); formMapper.insert(form); // 返回 return form.getId(); } @Override - public void updateForm(BpmFormUpdateReqVO updateReqVO) { - this.checkFields(updateReqVO.getFields()); + public void updateForm(BpmFormSaveReqVO updateReqVO) { + vadateFields(updateReqVO.getFields()); // 校验存在 - this.validateFormExists(updateReqVO.getId()); + validateFormExists(updateReqVO.getId()); // 更新 - BpmFormDO updateObj = BpmFormConvert.INSTANCE.convert(updateReqVO); + BpmFormDO updateObj = BeanUtils.toBean(updateReqVO, BpmFormDO.class); formMapper.updateById(updateObj); } @@ -94,7 +93,7 @@ public class BpmFormServiceImpl implements BpmFormService { * * @param fields field 数组 */ - private void checkFields(List fields) { + private void vadateFields(List fields) { if (true) { // TODO 芋艿:兼容 Vue3 工作流:因为采用了新的表单设计器,所以暂时不校验 return; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 511b4902a..eb392ace2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -87,7 +87,7 @@ public class BpmModelServiceImpl implements BpmModelService { @Override @Transactional(rollbackFor = Exception.class) public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { - if (!ValidationUtils.isXmlNCName(createReqVO.getName())) { + if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) { throw exception(MODEL_KEY_VALID); } // 校验流程标识已经存在 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java index 308956659..24ca6d322 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java @@ -29,9 +29,9 @@ public interface BpmOALeaveService { * 更新请假申请的状态 * * @param id 编号 - * @param result 结果 + * @param status 结果 */ - void updateLeaveResult(Long id, Integer result); + void updateLeaveStatus(Long id, Integer status); /** * 获得请假申请 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java index 9477e667d..c71d88505 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -2,19 +2,19 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.hutool.core.date.LocalDateTimeUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; -import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; import java.util.HashMap; import java.util.Map; @@ -47,8 +47,8 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) { // 插入 OA 请假单 long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays(); - BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day) - .setResult(BpmTaskStatustEnum.RUNNING.getStatus()); + BpmOALeaveDO leave = BeanUtils.toBean(createReqVO, BpmOALeaveDO.class) + .setUserId(userId).setDay(day).setStatus(BpmTaskStatustEnum.RUNNING.getStatus()); leaveMapper.insert(leave); // 发起 BPM 流程 @@ -64,9 +64,9 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { } @Override - public void updateLeaveResult(Long id, Integer result) { + public void updateLeaveStatus(Long id, Integer status) { validateLeaveExists(id); - leaveMapper.updateById(new BpmOALeaveDO().setId(id).setResult(result)); + leaveMapper.updateById(new BpmOALeaveDO().setId(id).setStatus(status)); } private void validateLeaveExists(Long id) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java similarity index 58% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java index e1dccb52b..8c70306fb 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.bpm.service.oa.listener; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; import org.springframework.stereotype.Component; @@ -14,7 +14,7 @@ import jakarta.annotation.Resource; * @author 芋道源码 */ @Component -public class BpmOALeaveResultListener extends BpmProcessInstanceResultEventListener { +public class BpmOALeaveStatusListener extends BpmProcessInstanceStatusEventListener { @Resource private BpmOALeaveService leaveService; @@ -25,8 +25,8 @@ public class BpmOALeaveResultListener extends BpmProcessInstanceResultEventListe } @Override - protected void onEvent(BpmProcessInstanceResultEvent event) { - leaveService.updateLeaveResult(Long.parseLong(event.getBusinessKey()), event.getResult()); + protected void onEvent(BpmProcessInstanceStatusEvent event) { + leaveService.updateLeaveStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index 1e78c271e..3473cbcad 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import jakarta.validation.Valid; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; @@ -115,14 +114,6 @@ public interface BpmProcessInstanceService { */ String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO); - /** - * 获得流程实例 VO 信息 - * - * @param id 流程实例的编号 - * @return 流程实例 - */ - BpmProcessInstanceRespVO getProcessInstanceVO(String id); - /** * 取消流程实例 * 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 26b4cefa4..f589e29cd 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.PageUtils; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionExt = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file 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 dc89a670f..e7759c56e 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 @@ -187,8 +187,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); // 3.3 调用 BPM complete 去完成任务 // 其中,variables 是存储动态表单到 local 任务级别。过滤一下,避免 ProcessInstance 系统级的变量被占用 - Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); - taskService.complete(task.getId(), variables, true); + if (CollUtil.isNotEmpty(reqVO.getVariables())) { + Map variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); + taskService.complete(task.getId(), variables, true); + } else { + taskService.complete(task.getId()); + } // 【加签专属】处理加签任务 handleParentTaskIfSign(task.getParentTaskId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml deleted file mode 100644 index cf0954503..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/category/BpmCategoryMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java index fbc069d8a..50bc3ace7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; @@ -43,7 +43,7 @@ public class BpmFormServiceTest extends BaseDbUnitTest { @Test public void testCreateForm_success() { // 准备参数 - BpmFormCreateReqVO reqVO = randomPojo(BpmFormCreateReqVO.class, o -> { + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { o.setConf("{}"); o.setFields(randomFields()); }); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java index 438e3193c..cf119f215 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.test.core.util.AssertUtils; import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupSaveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; import org.junit.jupiter.api.Assertions; @@ -56,7 +55,7 @@ public class BpmUserGroupServiceTest extends BaseDbUnitTest { BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class); userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据 // 准备参数 - BpmUserGroupUpdateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupUpdateReqVO.class, o -> { + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class, o -> { o.setId(dbUserGroup.getId()); // 设置更新的 ID }); @@ -70,7 +69,7 @@ public class BpmUserGroupServiceTest extends BaseDbUnitTest { @Test public void testUpdateUserGroup_notExists() { // 准备参数 - BpmUserGroupUpdateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupUpdateReqVO.class); + BpmUserGroupSaveReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupSaveReqVO.class); // 调用, 并断言异常 AssertUtils.assertServiceException(() -> userGroupService.updateUserGroup(reqVO), USER_GROUP_NOT_EXISTS); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql index 20a939b76..eae4d7e41 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql @@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS "bpm_user_group" ( "name" varchar(63) NOT NULL, "description" varchar(255) NOT NULL, "status" tinyint NOT NULL, - "member_user_ids" varchar(255) NOT NULL, + "user_ids" varchar(255) NOT NULL, "creator" varchar(64) DEFAULT '', "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, "updater" varchar(64) DEFAULT '', diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java similarity index 65% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java index 256259bdf..14d3c66aa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractStatusListener.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.service.contract.listener; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl; import jakarta.annotation.Resource; @@ -13,7 +13,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class CrmContractResultListener extends BpmProcessInstanceResultEventListener { +public class CrmContractStatusListener extends BpmProcessInstanceStatusEventListener { @Resource private CrmContractService contractService; @@ -24,8 +24,8 @@ public class CrmContractResultListener extends BpmProcessInstanceResultEventList } @Override - protected void onEvent(BpmProcessInstanceResultEvent event) { - contractService.updateContractAuditStatus(Long.parseLong(event.getBusinessKey()), event.getResult()); + protected void onEvent(BpmProcessInstanceStatusEvent event) { + contractService.updateContractAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java similarity index 65% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java index 8c4f3e974..4bf0497e6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableStatusListener.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.service.receivable.listener; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent; +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEventListener; import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableServiceImpl; import jakarta.annotation.Resource; @@ -13,7 +13,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class CrmReceivableResultListener extends BpmProcessInstanceResultEventListener { +public class CrmReceivableStatusListener extends BpmProcessInstanceStatusEventListener { @Resource private CrmReceivableService receivableService; @@ -24,8 +24,8 @@ public class CrmReceivableResultListener extends BpmProcessInstanceResultEventLi } @Override - public void onEvent(BpmProcessInstanceResultEvent event) { - receivableService.updateReceivableAuditStatus(Long.parseLong(event.getBusinessKey()), event.getResult()); + public void onEvent(BpmProcessInstanceStatusEvent event) { + receivableService.updateReceivableAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus()); } } diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 4eaba09c8..017258b7f 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -59,7 +59,7 @@ flowable: database-schema-update: true # 设置为 false,可通过 https://github.com/flowable/flowable-sql 初始化 db-history-used: true # flowable6 默认 true 生成信息表,无需手动设置 check-process-definitions: false # 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程 - history-level: full # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 + history-level: audit # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 # MyBatis Plus 的配置项 mybatis-plus: From ba4b3701bf0a8d0fd2bc51f0aba9ee1b20166607 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 22 Mar 2024 08:26:19 +0800 Subject: [PATCH 20/26] =?UTF-8?q?BPM=EF=BC=9A=E6=96=B0=E5=A2=9E=E3=80=90?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8B=E3=80=91=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E4=BA=8E=E5=85=A8=E9=83=A8=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E7=9A=84=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/enums/task/BpmDeleteReasonEnum.java | 5 +- .../process/BpmProcessDefinitionRespVO.java | 6 +- .../task/BpmProcessInstanceController.java | 61 ++++++++++++++++--- ....java => BpmProcessInstancePageReqVO.java} | 11 ++-- .../vo/instance/BpmProcessInstanceRespVO.java | 5 +- .../admin/task/vo/task/BpmTaskRespVO.java | 2 +- .../task/BpmProcessInstanceConvert.java | 14 +++-- .../bpm/convert/task/BpmTaskConvert.java | 1 + .../config/BpmFlowableConfiguration.java | 6 +- ... => BpmProcessInstanceEventPublisher.java} | 2 +- .../task/BpmProcessInstanceService.java | 18 ++++-- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 2 +- 13 files changed, 97 insertions(+), 38 deletions(-) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/{BpmProcessInstanceMyPageReqVO.java => BpmProcessInstancePageReqVO.java} (79%) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/{BpmProcessInstanceResultEventPublisher.java => BpmProcessInstanceEventPublisher.java} (92%) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java index ed07b330a..802b9d890 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java @@ -16,11 +16,12 @@ public enum BpmDeleteReasonEnum { // ========== 流程实例的独有原因 ========== REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法 - CANCEL_PROCESS_INSTANCE("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 + CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 + CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程 // ========== 流程任务的独有原因 ========== - CANCEL_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等 + CANCEL_BY_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等 ; private final String reason; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index 4fa56d4a3..27164c695 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import jakarta.validation.constraints.NotEmpty; - import java.time.LocalDateTime; import java.util.List; @@ -19,9 +17,11 @@ public class BpmProcessDefinitionRespVO { private Integer version; @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") - @NotEmpty(message = "流程名称不能为空") private String name; + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") + private String key; + @Schema(description = "流程描述", example = "我是描述") private String description; 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 2db6b76f9..3208013bd 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 @@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; @@ -59,9 +62,10 @@ public class BpmProcessInstanceController { @GetMapping("/my-page") @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") - public CommonResult> getMyProcessInstancePage( - @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { - PageResult pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO); + public CommonResult> getProcessInstanceMyPage( + @Valid BpmProcessInstancePageReqVO pageReqVO) { + PageResult pageResult = processInstanceService.getProcessInstancePage( + getLoginUserId(), pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty(pageResult.getTotal())); } @@ -73,8 +77,35 @@ public class BpmProcessInstanceController { convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); Map categoryMap = categoryService.getCategoryMap( convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); - return success(BpmProcessInstanceConvert.INSTANCE.buildMyProcessInstancePage(pageResult, - processDefinitionMap, categoryMap, taskMap)); + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, + processDefinitionMap, categoryMap, taskMap, null, null)); + } + + @GetMapping("/manager-page") + @Operation(summary = "获得管理流程实例的分页列表", description = "在【流程实例】菜单中,进行调用") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:manager-query')") + public CommonResult> getProcessInstanceManagerPage( + @Valid BpmProcessInstancePageReqVO pageReqVO) { + PageResult pageResult = processInstanceService.getProcessInstancePage( + null, pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + + // 拼接返回 + Map> taskMap = taskService.getTaskMapByProcessInstanceIds( + convertList(pageResult.getList(), HistoricProcessInstance::getId)); + Map processDefinitionMap = processDefinitionService.getProcessDefinitionMap( + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); + Map categoryMap = categoryService.getCategoryMap( + convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); + // 发起人信息 + Map userMap = adminUserApi.getUserMap( + convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId()))); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult, + processDefinitionMap, categoryMap, taskMap, userMap, deptMap)); } @PostMapping("/create") @@ -109,11 +140,21 @@ public class BpmProcessInstanceController { processDefinition, processDefinitionInfo, bpmnXml, startUser, dept)); } - @DeleteMapping("/cancel") - @Operation(summary = "取消流程实例", description = "撤回发起的流程") + @DeleteMapping("/cancel-by-start-user") + @Operation(summary = "用户取消流程实例", description = "取消发起的流程") @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") - public CommonResult cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { - processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO); + public CommonResult cancelProcessInstanceByStartUser( + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { + processInstanceService.cancelProcessInstanceByStartUser(getLoginUserId(), cancelReqVO); + return success(true); + } + + @DeleteMapping("/cancel-by-admin") + @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel-by-admin')") + public CommonResult cancelProcessInstanceByManager( + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { + processInstanceService.cancelProcessInstanceByAdmin(getLoginUserId(), cancelReqVO); return success(true); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java similarity index 79% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java index 4945b2b9a..bc658eb87 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java @@ -5,19 +5,15 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Schema(description = "管理后台 - 流程实例的分页 Item Response VO") +@Schema(description = "管理后台 - 流程实例分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class BpmProcessInstanceMyPageReqVO extends PageParam { +public class BpmProcessInstancePageReqVO extends PageParam { @Schema(description = "流程名称", example = "芋道") private String name; @@ -36,4 +32,7 @@ public class BpmProcessInstanceMyPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "发起用户编号", example = "1024") + private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数 + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java index d6e67dd34..ac6b90c7e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -26,12 +26,15 @@ public class BpmProcessInstanceRespVO { @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 - @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime startTime; @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime endTime; + @Schema(description = "持续时间", example = "1000") + private Long durationInMillis; + @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) private Map formVariables; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 26b8e80b0..7f5177b94 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -24,7 +24,7 @@ public class BpmTaskRespVO { @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime endTime; - @Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + @Schema(description = "持续时间", example = "1000") private Long durationInMillis; @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 1f6e38a3d..745eab330 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -36,10 +36,12 @@ public interface BpmProcessInstanceConvert { BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); - default PageResult buildMyProcessInstancePage(PageResult pageResult, - Map processDefinitionMap, - Map categoryMap, - Map> taskMap) { + default PageResult buildProcessInstancePage(PageResult pageResult, + Map processDefinitionMap, + Map categoryMap, + Map> taskMap, + Map userMap, + Map deptMap) { PageResult vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstanceRespVO.class); for (int i = 0; i < pageResult.getList().size(); i++) { BpmProcessInstanceRespVO respVO = vpPageResult.getList().get(i); @@ -48,6 +50,10 @@ public interface BpmProcessInstanceConvert { processDefinition -> respVO.setCategory(processDefinition.getCategory())); MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class)); + // user + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId())); + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); } return vpPageResult; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 67b882c95..6fd404e28 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -46,6 +46,7 @@ public interface BpmTaskConvert { if (processInstance == null) { return; } + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); }); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java index 979d19153..8e69fdc75 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -4,7 +4,7 @@ import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.spring.SpringProcessEngineConfiguration; @@ -84,8 +84,8 @@ public class BpmFlowableConfiguration { // =========== 自己拓展的 Bean ========== @Bean - public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) { - return new BpmProcessInstanceResultEventPublisher(publisher); + public BpmProcessInstanceEventPublisher processInstanceEventPublisher(ApplicationEventPublisher publisher) { + return new BpmProcessInstanceEventPublisher(publisher); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java similarity index 92% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java index bf85c58c8..c0429f2c3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java @@ -14,7 +14,7 @@ import jakarta.validation.Valid; */ @AllArgsConstructor @Validated -public class BpmProcessInstanceResultEventPublisher { +public class BpmProcessInstanceEventPublisher { private final ApplicationEventPublisher publisher; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index 3473cbcad..4ef484551 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import jakarta.validation.Valid; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; @@ -93,8 +93,8 @@ public interface BpmProcessInstanceService { * @param pageReqVO 分页请求 * @return 流程实例的分页 */ - PageResult getMyProcessInstancePage(Long userId, - @Valid BpmProcessInstanceMyPageReqVO pageReqVO); + PageResult getProcessInstancePage(Long userId, + @Valid BpmProcessInstancePageReqVO pageReqVO); /** * 创建流程实例(提供给前端) @@ -115,12 +115,20 @@ public interface BpmProcessInstanceService { String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO); /** - * 取消流程实例 + * 发起人取消流程实例 * * @param userId 用户编号 * @param cancelReqVO 取消信息 */ - void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); + void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); + + /** + * 管理员取消流程实例 + * + * @param userId 用户编号 + * @param cancelReqVO 取消信息 + */ + void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO); /** * 更新 ProcessInstance 拓展记录为取消 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 f589e29cd..39914df9c 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file 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 e7759c56e..974055283 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 @@ -375,7 +375,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } - updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_SYSTEM.getReason()); + updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason()); // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 } From acea73c9915e6c8ec9e20efd336b18c982e63b3b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 22 Mar 2024 09:06:52 +0800 Subject: [PATCH 21/26] =?UTF-8?q?BPM=EF=BC=9A=E6=96=B0=E5=A2=9E=E3=80=90?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E4=BB=BB=E5=8A=A1=E3=80=91=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E4=BA=8E=E5=85=A8=E9=83=A8=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E7=9A=84=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/task/BpmTaskController.java | 39 ++++++++++++++++--- .../task/BpmProcessInstanceConvert.java | 8 ++-- .../bpm/convert/task/BpmTaskConvert.java | 13 +++++-- .../bpm/service/task/BpmTaskService.java | 13 ++++++- .../bpm/service/task/BpmTaskServiceImpl.java | 25 +++++++++++- 5 files changed, 83 insertions(+), 15 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index d721cf7a8..7d72a133b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -59,8 +59,12 @@ public class BpmTaskController { @GetMapping("todo-page") @Operation(summary = "获取 Todo 待办任务分页") @PreAuthorize("@ss.hasPermission('bpm:task:query')") - public CommonResult> getTodoTaskPage(@Valid BpmTaskPageReqVO pageVO) { - PageResult pageResult = taskService.getTodoTaskPage(getLoginUserId(), pageVO); + public CommonResult> getTaskTodoPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskTodoPage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + // 拼接数据 Map processInstanceMap = processInstanceService.getProcessInstanceMap( convertSet(pageResult.getList(), Task::getProcessInstanceId)); @@ -72,14 +76,39 @@ public class BpmTaskController { @GetMapping("done-page") @Operation(summary = "获取 Done 已办任务分页") @PreAuthorize("@ss.hasPermission('bpm:task:query')") - public CommonResult> getDoneTaskPage(@Valid BpmTaskPageReqVO pageVO) { - PageResult pageResult = taskService.getDoneTaskPage(getLoginUserId(), pageVO); + public CommonResult> getTaskDonePage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskDonePage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + // 拼接数据 Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); Map userMap = adminUserApi.getUserMap( convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); - return success(BpmTaskConvert.INSTANCE.buildDoneTaskPage(pageResult, processInstanceMap, userMap)); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null)); + } + + @GetMapping("manager-page") + @Operation(summary = "获取全部任务的分页", description = "用于【流程任务】菜单") + @PreAuthorize("@ss.hasPermission('bpm:task:mananger-query')") + public CommonResult> getDoneTaskPage(@Valid BpmTaskPageReqVO pageVO) { + PageResult pageResult = taskService.getTaskPage(getLoginUserId(), pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 拼接数据 + Map processInstanceMap = processInstanceService.getHistoricProcessInstanceMap( + convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId)); + // 获得 User 和 Dept Map + Set userIds = convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())); + userIds.addAll(convertSet(pageResult.getList(), task -> NumberUtils.parseLong(task.getAssignee()))); + Map userMap = adminUserApi.getUserMap(userIds); + Map deptMap = deptApi.getDeptMap( + convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap)); } @GetMapping("/list-by-process-instance-id") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 745eab330..5d28c99a7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -51,9 +51,11 @@ public interface BpmProcessInstanceConvert { MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class)); // user - AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId())); - respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); - MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); + if (userMap != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId())); + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); + MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName())); + } } return vpPageResult; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index 6fd404e28..5f4e915d3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -52,12 +52,19 @@ public interface BpmTaskConvert { }); } - default PageResult buildDoneTaskPage(PageResult pageResult, - Map processInstanceMap, - Map userMap) { + default PageResult buildTaskPage(PageResult pageResult, + Map processInstanceMap, + Map userMap, + Map deptMap) { List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); + // 用户信息 + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class)); + findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName())); + } // 流程实例 HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId()); if (processInstance != null) { 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 83bb3eb0a..f69757f14 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 @@ -27,7 +27,7 @@ public interface BpmTaskService { * @param pageReqVO 分页请求 * @return 流程任务分页 */ - PageResult getTodoTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); + PageResult getTaskTodoPage(Long userId, BpmTaskPageReqVO pageReqVO); /** * 获得已办的流程任务分页 @@ -36,7 +36,16 @@ public interface BpmTaskService { * @param pageReqVO 分页请求 * @return 流程任务分页 */ - PageResult getDoneTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); + PageResult getTaskDonePage(Long userId, BpmTaskPageReqVO pageReqVO); + + /** + * 获得全部的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程任务分页 + */ + PageResult getTaskPage(Long userId, BpmTaskPageReqVO pageReqVO); /** * 获得流程任务 Map 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 974055283..7afed756b 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 @@ -86,7 +86,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { private AdminUserApi adminUserApi; @Override - public PageResult getTodoTaskPage(Long userId, BpmTaskPageReqVO pageVO) { + public PageResult getTaskTodoPage(Long userId, BpmTaskPageReqVO pageVO) { TaskQuery taskQuery = taskService.createTaskQuery() .taskAssignee(String.valueOf(userId)) // 分配给自己 .active() @@ -108,7 +108,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } @Override - public PageResult getDoneTaskPage(Long userId, BpmTaskPageReqVO pageVO) { + public PageResult getTaskDonePage(Long userId, BpmTaskPageReqVO pageVO) { HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery() .finished() // 已完成 .taskAssignee(String.valueOf(userId)) // 分配给自己 @@ -130,6 +130,27 @@ public class BpmTaskServiceImpl implements BpmTaskService { return new PageResult<>(tasks, count); } + @Override + public PageResult getTaskPage(Long userId, BpmTaskPageReqVO pageVO) { + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery() + .includeTaskLocalVariables() + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); + taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[1])); + } + // 执行查询 + long count = taskQuery.count(); + if (count == 0) { + return PageResult.empty(); + } + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + return new PageResult<>(tasks, count); + } + @Override public List getTasksByProcessInstanceIds(List processInstanceIds) { if (CollUtil.isEmpty(processInstanceIds)) { From 528a321f0aa178b4b36b764075371ca1d3ada7e0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 23 Mar 2024 00:54:26 +0800 Subject: [PATCH 22/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=E3=80=8C?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E4=BA=BA=E8=87=AA=E9=80=89=E3=80=8D=E7=9A=84?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=AE=A1=E6=89=B9=E4=BA=BA=E7=9A=84=E5=88=86?= =?UTF-8?q?=E9=85=8D=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/BpmProcessInstanceCreateReqDTO.java | 7 +- .../module/bpm/enums/ErrorCodeConstants.java | 5 +- .../BpmProcessDefinitionController.java | 25 ++++-- .../vo/category/BpmCategorySaveReqVO.java | 3 + .../process/BpmProcessDefinitionRespVO.java | 17 ++++- .../admin/oa/vo/BpmOALeaveCreateReqVO.java | 5 ++ .../task/BpmProcessInstanceController.java | 4 +- .../BpmProcessInstanceCreateReqVO.java | 5 +- .../BpmProcessDefinitionConvert.java | 57 ++++++++++---- .../task/BpmProcessInstanceConvert.java | 2 +- .../dataobject/definition/BpmCategoryDO.java | 11 ++- .../dal/mysql/category/BpmCategoryMapper.java | 2 +- .../bpm/framework/FlowableContextHolder.java | 41 ---------- .../candidate/BpmTaskCandidateInvoker.java | 37 +++------ .../candidate/BpmTaskCandidateStrategy.java | 9 +++ .../BpmTaskAssignLeaderExpression.java | 4 +- .../BpmTaskAssignStartUserExpression.java | 4 +- ...mTaskCandidateStartUserSelectStrategy.java | 76 +++++++++++++++++++ .../flowable/core/enums/BpmConstants.java | 6 ++ .../enums/BpmTaskCandidateStrategyEnum.java | 1 + .../flowable/core/util/BpmnModelUtils.java | 20 +++++ .../flowable/core/util/FlowableUtils.java | 15 +++- .../definition/BpmFormServiceImpl.java | 6 +- .../BpmProcessDefinitionService.java | 15 ++-- .../BpmProcessDefinitionServiceImpl.java | 12 +-- .../bpm/service/oa/BpmOALeaveServiceImpl.java | 3 +- .../task/BpmProcessInstanceService.java | 21 ----- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../BpmTaskAssignLeaderExpressionTest.java | 5 +- .../category/BpmCategoryServiceImplTest.java | 53 +++++++------ .../definition/BpmFormServiceTest.java | 5 +- .../src/test/resources/sql/clean.sql | 1 + .../src/test/resources/sql/create_tables.sql | 15 ++++ 33 files changed, 305 insertions(+), 189 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java index 629742bc8..b1ac35366 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java @@ -32,14 +32,13 @@ public class BpmProcessInstanceCreateReqDTO { @NotEmpty(message = "业务的唯一标识") private String businessKey; - // TODO @hai:assignees 复数 /** - * 提前指派的审批人 + * 发起人自选审批人 Map * * key:taskKey 任务编码 * value:审批人的数组 - * 例如: { taskKey1 :[1, 2] },则表示 taskKey1 这个任务,提前设定了,由 userId 为 1,2 的用户进行审批 + * 例如:{ taskKey1 :[1, 2] },则表示 taskKey1 这个任务,提前设定了,由 userId 为 1,2 的用户进行审批 */ - private Map> assignee; + private Map> startUserSelectAssignees; } 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 310e1b623..70e13cbe1 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 @@ -29,12 +29,13 @@ public interface ErrorCodeConstants { ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1_009_003_001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图"); ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_009_003_002, "流程定义不存在"); ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1_009_003_003, "流程定义处于挂起状态"); - ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1_009_003_004, "流程定义的模型不存在"); // ========== 流程实例 1-009-004-000 ========== ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1_009_004_000, "流程实例不存在"); ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1_009_004_001, "流程取消失败,流程不处于运行中"); ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1_009_004_002, "流程取消失败,该流程不是你发起的"); + ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_003, "审批任务({})的审批人未配置"); + ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS = new ErrorCode(1_009_004_004, "审批任务({})的审批人({})不存在"); // ========== 流程任务 1-009-005-000 ========== ErrorCode TASK_OPERATE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1_009_005_001, "操作失败,原因:该任务的审批人不是你"); @@ -50,8 +51,6 @@ public interface ErrorCodeConstants { ErrorCode TASK_SIGN_DELETE_NO_PARENT = new ErrorCode(1_009_005_012, "任务减签失败,被减签的任务必须是通过加签生成的任务"); ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); - - // ========== 流程任务分配规则 1-009-006-000 TODO 芋艿:这里要改下 ========== ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); // ========== 动态表单模块 1-009-010-000 ========== diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java index ff3c37b08..149737ca0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConver 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.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; 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.BpmProcessDefinitionService; @@ -16,6 +17,8 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.springframework.security.access.prepost.PreAuthorize; @@ -89,13 +92,23 @@ public class BpmProcessDefinitionController { list, null, processDefinitionMap, null, null)); } - @GetMapping ("/get-bpmn-xml") - @Operation(summary = "获得流程定义的 BPMN XML") - @Parameter(name = "id", description = "编号", required = true, example = "1024") + @GetMapping ("/get") + @Operation(summary = "获得流程定义") + @Parameter(name = "id", description = "流程编号", required = true, example = "1024") + @Parameter(name = "key", description = "流程定义标识", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") - public CommonResult getProcessDefinitionBpmnXML(@RequestParam("id") String id) { - String bpmnXML = processDefinitionService.getProcessDefinitionBpmnXML(id); - return success(bpmnXML); + public CommonResult getProcessDefinition( + @RequestParam(value = "id", required = false) String id, + @RequestParam(value = "key", required = false) String key) { + ProcessDefinition processDefinition = id != null ? processDefinitionService.getProcessDefinition(id) + : processDefinitionService.getActiveProcessDefinition(key); + if (processDefinition == null) { + return success(null); + } + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); + List userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); + return success(BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition( + processDefinition, null, null, null, null, bpmnModel, userTaskList)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java index 352cf690b..d1a175ec5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategorySaveReqVO.java @@ -18,6 +18,9 @@ public class BpmCategorySaveReqVO { @NotEmpty(message = "分类名不能为空") private String name; + @Schema(description = "分类描述", example = "你猜") + private String description; + @Schema(description = "分类标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "OA") @NotEmpty(message = "分类标志不能为空") private String code; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index 27164c695..f54e31803 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -48,7 +48,7 @@ public class BpmProcessDefinitionRespVO { private String formCustomViewPath; @Schema(description = "中断状态-参见 SuspensionState 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer suspensionState; + private Integer suspensionState; // 参见 SuspensionState 枚举 @Schema(description = "部署时间") private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取,非必须返回 @@ -56,4 +56,19 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "BPMN XML") private String bpmnXml; // 需要从对应的 BpmnModel 读取,非必须返回 + @Schema(description = "发起用户需要选择审批人的任务数组") + private List startUserSelectTasks; // 需要从对应的 BpmnModel 读取,非必须返回 + + @Schema(description = "BPMN UserTask 用户任务") + @Data + public static class UserTask { + + @Schema(description = "任务标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "sudo") + private String id; + + @Schema(description = "任务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java index 8f84a281d..856a22547 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java @@ -7,6 +7,8 @@ import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -30,6 +32,9 @@ public class BpmOALeaveCreateReqVO { @Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码") private String reason; + @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") + private Map> startUserSelectAssignees; + @AssertTrue(message = "结束时间,需要在开始时间之后") public boolean isEndTimeValid() { return !getEndTime().isBefore(getStartTime()); 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 3208013bd..50fbc9fa8 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 @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; @@ -130,7 +131,8 @@ public class BpmProcessInstanceController { processInstance.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); - String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); + String bpmnXml = BpmnModelUtils.getBpmnXml( + processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId())); AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java index f47749861..b13ff561f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java @@ -18,8 +18,7 @@ public class BpmProcessInstanceCreateReqVO { @Schema(description = "变量实例(动态表单)") private Map variables; - // TODO @hai:assignees 复数 - @Schema(description = "提前指派的审批人", requiredMode = Schema.RequiredMode.REQUIRED, example = "{taskKey1: [1, 2]}") - private Map> assignee; + @Schema(description = "发起人自选审批人 Map", example = "{taskKey1: [1, 2]}") + private Map> startUserSelectAssignees; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index 1b5897dd5..61187424b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -4,12 +4,14 @@ import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; 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.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; @@ -47,27 +49,50 @@ public interface BpmProcessDefinitionConvert { Map formMap, Map categoryMap) { return CollectionUtils.convertList(list, definition -> { - BpmProcessDefinitionRespVO respVO = BeanUtils.toBean(definition, BpmProcessDefinitionRespVO.class); - respVO.setSuspensionState(definition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); - // Deployment - MapUtils.findAndThen(deploymentMap, definition.getDeploymentId(), - deployment -> respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime()))); - // BpmProcessDefinitionInfoDO + Deployment deployment = MapUtil.get(deploymentMap, definition.getDeploymentId(), Deployment.class); BpmProcessDefinitionInfoDO processDefinitionInfo = MapUtil.get(processDefinitionInfoMap, definition.getId(), BpmProcessDefinitionInfoDO.class); + BpmFormDO form = null; if (processDefinitionInfo != null) { - copyTo(processDefinitionInfo, respVO); - // Form - BpmFormDO form = MapUtil.get(formMap, processDefinitionInfo.getFormId(), BpmFormDO.class); - if (form != null) { - respVO.setFormName(form.getName()); - } + form = MapUtil.get(formMap, processDefinitionInfo.getFormId(), BpmFormDO.class); } - // Category - MapUtils.findAndThen(categoryMap, definition.getCategory(), category -> respVO.setCategoryName(category.getName())); - return respVO; + BpmCategoryDO category = MapUtil.get(categoryMap, definition.getCategory(), BpmCategoryDO.class); + return buildProcessDefinition(definition, deployment, processDefinitionInfo, form, category, null, null); }); } + default BpmProcessDefinitionRespVO buildProcessDefinition(ProcessDefinition definition, + Deployment deployment, + BpmProcessDefinitionInfoDO processDefinitionInfo, + BpmFormDO form, + BpmCategoryDO category, + BpmnModel bpmnModel, + List startUserSelectUserTaskList) { + BpmProcessDefinitionRespVO respVO = BeanUtils.toBean(definition, BpmProcessDefinitionRespVO.class); + respVO.setSuspensionState(definition.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + // Deployment + if (deployment != null) { + respVO.setDeploymentTime(LocalDateTimeUtil.of(deployment.getDeploymentTime())); + } + // BpmProcessDefinitionInfoDO + if (processDefinitionInfo != null) { + copyTo(processDefinitionInfo, respVO); + // Form + if (form != null) { + respVO.setFormName(form.getName()); + } + } + // Category + if (category != null) { + respVO.setCategoryName(category.getName()); + } + // BpmnModel + if (bpmnModel != null) { + respVO.setBpmnXml(BpmnModelUtils.getBpmnXml(bpmnModel)); + respVO.setStartUserSelectTasks(BeanUtils.toBean(startUserSelectUserTaskList, BpmProcessDefinitionRespVO.UserTask.class)); + } + return respVO; + } + @Mapping(source = "from.id", target = "to.id", ignore = true) void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 5d28c99a7..d2b326e11 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -68,7 +68,7 @@ public interface BpmProcessInstanceConvert { DeptRespDTO dept) { BpmProcessInstanceRespVO respVO = BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class); respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)); - respVO.setFormVariables(FlowableUtils.filterProcessInstanceFormVariable(processInstance.getProcessVariables())); + respVO.setFormVariables(FlowableUtils.getProcessInstanceFormVariable(processInstance)); // definition respVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class)); copyTo(processDefinitionExt, respVO.getProcessDefinition()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java index 2fe0963bb..560a8ead6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java @@ -1,11 +1,10 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * BPM 流程分类 DO @@ -42,7 +41,7 @@ public class BpmCategoryDO extends BaseDO { /** * 分类状态 * - * 枚举 {@link TODO common_status 对应的类} + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} */ private Integer status; /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java index 888856a45..5fc8236e8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/category/BpmCategoryMapper.java @@ -21,7 +21,7 @@ public interface BpmCategoryMapper extends BaseMapperX { default PageResult selectPage(BpmCategoryPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(BpmCategoryDO::getName, reqVO.getName()) - .eqIfPresent(BpmCategoryDO::getCode, reqVO.getCode()) + .likeIfPresent(BpmCategoryDO::getCode, reqVO.getCode()) .eqIfPresent(BpmCategoryDO::getStatus, reqVO.getStatus()) .betweenIfPresent(BpmCategoryDO::getCreateTime, reqVO.getCreateTime()) .orderByAsc(BpmCategoryDO::getSort)); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java deleted file mode 100644 index 6e4fb99e3..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/FlowableContextHolder.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework; - -import cn.hutool.core.collection.CollUtil; -import com.alibaba.ttl.TransmittableThreadLocal; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * 工作流--用户用到的上下文相关信息 - */ -@Deprecated // TODO 芋艿:找个方式,去掉这个上下文 -public class FlowableContextHolder { - - private static final ThreadLocal>> ASSIGNEE = new TransmittableThreadLocal<>(); - - /** - * 通过流程任务的定义 key ,拿到提前选好的审批人 - * 此方法目的:首次创建流程实例时,数据库中还查询不到 assignee 字段,所以存入上下文中获取 - * - * @param taskDefinitionKey 流程任务 key - * @return 审批人 ID 集合 - */ - public static List getAssigneeByTaskDefinitionKey(String taskDefinitionKey) { - if (CollUtil.isNotEmpty(ASSIGNEE.get())) { - return ASSIGNEE.get().get(taskDefinitionKey); - } - return Collections.emptyList(); - } - - /** - * 存入提前选好的审批人到上下文线程变量中 - * - * @param assignee 流程任务 key -> 审批人 ID 炅和 - */ - public static void setAssignee(Map> assignee) { - ASSIGNEE.set(assignee); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java index e1fb62632..7bad35807 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -4,16 +4,13 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; -import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.DelegateExecution; @@ -60,9 +57,13 @@ public class BpmTaskCandidateInvoker { // 遍历所有的 UserTask,校验审批人配置 userTaskList.forEach(userTask -> { // 1. 非空校验 - Integer strategy = parseCandidateStrategy(userTask); - String param = parseCandidateParam(userTask); - if (strategy == null || StrUtil.isBlank(param)) { + Integer strategy = BpmnModelUtils.parseCandidateStrategy(userTask); + String param = BpmnModelUtils.parseCandidateParam(userTask); + if (strategy == null) { + throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); + } + BpmTaskCandidateStrategy candidateStrategy = getCandidateStrategy(strategy); + if (candidateStrategy.isParamRequired() && StrUtil.isBlank(param)) { throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); } // 2. 具体策略校验 @@ -77,16 +78,8 @@ public class BpmTaskCandidateInvoker { * @return 用户编号集合 */ public Set calculateUsers(DelegateExecution execution) { - // TODO 芋艿:这里需要重构 -// // 1. 先从提前选好的审批人中获取 -// List assignee = processInstanceService.getAssigneeByProcessInstanceIdAndTaskDefinitionKey( -// execution.getProcessInstanceId(), execution.getCurrentActivityId()); -// if (CollUtil.isNotEmpty(assignee)) { -// // TODO @hai:new HashSet 即可 -// return convertSet(assignee, Function.identity()); -// } - Integer strategy = parseCandidateStrategy(execution.getCurrentFlowElement()); - String param = parseCandidateParam(execution.getCurrentFlowElement()); + Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement()); + String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement()); // 1.1 计算任务的候选人 Set userIds = getCandidateStrategy(strategy).calculateUsers(execution, param); // 1.2 移除被禁用的用户 @@ -113,16 +106,6 @@ public class BpmTaskCandidateInvoker { }); } - private static Integer parseCandidateStrategy(FlowElement userTask) { - return NumberUtils.parseInt(userTask.getAttributeValue( - BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); - } - - private static String parseCandidateParam(FlowElement userTask) { - return userTask.getAttributeValue( - BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); - } - private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) { BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy); Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java index a5c5c9b4d..1534d39c2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java @@ -36,4 +36,13 @@ public interface BpmTaskCandidateStrategy { */ Set calculateUsers(DelegateExecution execution, String param); + /** + * 是否一定要输入参数 + * + * @return 是否 + */ + default boolean isParamRequired() { + return true; + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java index cb5306548..7a021ab2b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -32,12 +32,12 @@ public class BpmTaskAssignLeaderExpression { private DeptApi deptApi; @Resource - private BpmProcessInstanceService bpmProcessInstanceService; + private BpmProcessInstanceService processInstanceService; protected Set calculateUsers(DelegateExecution execution, int level) { Assert.isTrue(level > 0, "level 必须大于 0"); // 获得发起人 - ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); // 获得对应 leve 的部门 DeptRespDTO dept = null; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java index c4d8811b4..451ceed60 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -19,10 +19,10 @@ import java.util.Set; public class BpmTaskAssignStartUserExpression { @Resource - private BpmProcessInstanceService bpmProcessInstanceService; + private BpmProcessInstanceService processInstanceService; public Set calculateUsers(DelegateExecution execution) { - ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); return SetUtils.asSet(startUserId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java new file mode 100644 index 000000000..ef31d8885 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +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.task.BpmProcessInstanceService; +import jakarta.annotation.Resource; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.*; + +/** + * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskCandidateStartUserSelectStrategy implements BpmTaskCandidateStrategy { + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmProcessInstanceService processInstanceService; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.START_USER_SELECT; + } + + @Override + public void validateParam(String param) {} + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Assert.notNull(processInstance, "流程实例({})不能为空", execution.getProcessInstanceId()); + Map> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); + Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", + execution.getProcessInstanceId()); + // 获得审批人 + List assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); + return new LinkedHashSet<>(assignees); + } + + @Override + public boolean isParamRequired() { + return false; + } + + /** + * 获得发起人自选审批人的 UserTask 列表 + * + * @param bpmnModel BPMN 模型 + * @return UserTask 列表 + */ + public static List getStartUserSelectUserTaskList(BpmnModel bpmnModel) { + if (bpmnModel == null) { + return null; + } + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + if (CollUtil.isEmpty(userTaskList)) { + return null; + } + userTaskList.removeIf(userTask -> !Objects.equals(BpmnModelUtils.parseCandidateStrategy(userTask), + BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())); + return userTaskList; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java index 6dd5e79c7..e965d2281 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java @@ -15,6 +15,12 @@ public class BpmConstants { * @see ProcessInstance#getProcessVariables() */ public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS"; + /** + * 流程实例的变量 - 发起用户选择的审批人 Map + * + * @see ProcessInstance#getProcessVariables() + */ + public static final String PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES = "PROCESS_START_USER_SELECT_ASSIGNEES"; /** * 任务的变量 - 状态 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java index 0c3199821..a8b538501 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java @@ -20,6 +20,7 @@ public enum BpmTaskCandidateStrategyEnum { DEPT_LEADER(21, "部门的负责人"), POST(22, "岗位"), USER(30, "用户"), + START_USER_SELECT(35, "发起人自选"), // 申请人自己,可在提交申请时选择此节点的审批人 USER_GROUP(40, "用户组"), EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager ; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 9763bc8a6..bcf82d731 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; @@ -14,6 +16,16 @@ import java.util.*; */ public class BpmnModelUtils { + public static Integer parseCandidateStrategy(FlowElement userTask) { + return NumberUtils.parseInt(userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); + } + + public static String parseCandidateParam(FlowElement userTask) { + return userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); + } + /** * 根据节点,获取入口连线 * @@ -91,6 +103,14 @@ public class BpmnModelUtils { return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), false, false); } + public static String getBpmnXml(BpmnModel model) { + if (model == null) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + return new String(converter.convertToXML(model)); + } + // ========== 遍历相关的方法 ========== /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index 3fceb60fd..6a65dd804 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -12,6 +12,7 @@ import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.TaskInfo; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -79,7 +80,7 @@ public class FlowableUtils { * @param processInstance 流程实例 * @return 表单 */ - public static Map getProcessInstanceFormVariable(ProcessInstance processInstance) { + public static Map getProcessInstanceFormVariable(HistoricProcessInstance processInstance) { Map formVariables = new HashMap<>(processInstance.getProcessVariables()); filterProcessInstanceFormVariable(formVariables); return formVariables; @@ -98,6 +99,18 @@ public class FlowableUtils { return processVariables; } + /** + * 获得流程实例的发起用户选择的审批人 Map + * + * @param processInstance 流程实例 + * @return 发起用户选择的审批人 Map + */ + @SuppressWarnings("unchecked") + public static Map> getStartUserSelectAssignees(ProcessInstance processInstance) { + return (Map>) processInstance.getProcessVariables().get( + BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); + } + // ========== Task 相关的工具方法 ========== /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java index 95f275993..d49018f6b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -33,7 +33,7 @@ public class BpmFormServiceImpl implements BpmFormService { @Override public Long createForm(BpmFormSaveReqVO createReqVO) { - this.vadateFields(createReqVO.getFields()); + this.validateFields(createReqVO.getFields()); // 插入 BpmFormDO form = BeanUtils.toBean(createReqVO, BpmFormDO.class); formMapper.insert(form); @@ -43,7 +43,7 @@ public class BpmFormServiceImpl implements BpmFormService { @Override public void updateForm(BpmFormSaveReqVO updateReqVO) { - vadateFields(updateReqVO.getFields()); + validateFields(updateReqVO.getFields()); // 校验存在 validateFormExists(updateReqVO.getId()); // 更新 @@ -93,7 +93,7 @@ public class BpmFormServiceImpl implements BpmFormService { * * @param fields field 数组 */ - private void vadateFields(List fields) { + private void validateFields(List fields) { if (true) { // TODO 芋艿:兼容 Vue3 工作流:因为采用了新的表单设计器,所以暂时不校验 return; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java index 7126d652e..5e2e2f805 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import org.flowable.bpmn.model.BpmnModel; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; @@ -61,12 +62,12 @@ public interface BpmProcessDefinitionService { void updateProcessDefinitionState(String id, Integer state); /** - * 获得流程定义对应的 BPMN XML + * 获得流程定义对应的 BPMN * * @param id 流程定义编号 - * @return BPMN XML + * @return BPMN */ - String getProcessDefinitionBpmnXML(String id); + BpmnModel getProcessDefinitionBpmnModel(String id); /** * 获得流程定义的信息 @@ -89,9 +90,9 @@ public interface BpmProcessDefinitionService { } /** - * 获得编号对应的 ProcessDefinition + * 获得流程定义编号对应的 ProcessDefinition * - * @param id 编号 + * @param id 流程定义编号 * @return 流程定义 */ ProcessDefinition getProcessDefinition(String id); @@ -139,7 +140,7 @@ public interface BpmProcessDefinitionService { * @return 流程部署 Map */ default Map getDeploymentMap(Set ids) { - return convertMap(getDeployments(ids), Deployment::getId); + return convertMap(getDeploymentList(ids), Deployment::getId); } /** @@ -148,7 +149,7 @@ public interface BpmProcessDefinitionService { * @param ids 部署编号的数组 * @return 流程部署的数组 */ - List getDeployments(Set ids); + List getDeploymentList(Set ids); /** * 获得 id 对应的 Deployment 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 85418fb83..3324a5e79 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 @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConsta import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.BpmnModel; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.engine.RepositoryService; @@ -84,7 +83,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } @Override - public List getDeployments(Set ids) { + public List getDeploymentList(Set ids) { if (CollUtil.isEmpty(ids)) { return emptyList(); } @@ -156,13 +155,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ } @Override - public String getProcessDefinitionBpmnXML(String id) { - BpmnModel bpmnModel = repositoryService.getBpmnModel(id); - if (bpmnModel == null) { - return null; - } - BpmnXMLConverter converter = new BpmnXMLConverter(); - return StrUtil.utf8Str(converter.convertToXML(bpmnModel)); + public BpmnModel getProcessDefinitionBpmnModel(String id) { + return repositoryService.getBpmnModel(id); } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java index c71d88505..9a84f676a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -56,7 +56,8 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { processInstanceVariables.put("day", day); String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) - .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId()))); + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId())) + .setStartUserSelectAssignees(createReqVO.getStartUserSelectAssignees())); // 将工作流的编号,更新到 OA 请假单中 leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId)); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index 4ef484551..9ba4cb077 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -49,17 +49,6 @@ public interface BpmProcessInstanceService { return convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); } - /** - * 获得流程实例名字 Map - * - * @param ids 流程实例的编号集合 - * @return 对应的映射关系 - */ - default Map getProcessInstanceNameMap(Set ids) { - return convertMap(getProcessInstances(ids), - ProcessInstance::getProcessInstanceId, ProcessInstance::getName); - } - /** * 获得历史的流程实例 * @@ -152,14 +141,4 @@ public interface BpmProcessInstanceService { */ void updateProcessInstanceReject(String id, String reason); - // TODO @hai:改成 getProcessInstanceAssigneesByTaskDefinitionKey(String id, String taskDefinitionKey) - /** - * 获取流程实例中,取出指定流程任务提前指定的审批人 - * - * @param processInstanceId 流程实例的编号 - * @param taskDefinitionKey 流程任务定义的 key - * @return 审批人集合 - */ - List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey); - } 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 39914df9c..f6283eff8 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 @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; 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.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java index b9a77ca79..f7eac7ca0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java @@ -30,8 +30,9 @@ public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest { private AdminUserApi adminUserApi; @Mock private DeptApi deptApi; + @Mock - private BpmProcessInstanceService bpmProcessInstanceService; + private BpmProcessInstanceService processInstanceService; @Test public void testCalculateUsers_noDept() { @@ -96,7 +97,7 @@ public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest { // mock 返回 startUserId ExecutionEntityImpl processInstance = new ExecutionEntityImpl(); processInstance.setStartUserId(String.valueOf(startUserId)); - when(bpmProcessInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))) + when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))) .thenReturn(processInstance); return execution; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java index 19f576818..f71b8aae5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/category/BpmCategoryServiceImplTest.java @@ -1,26 +1,24 @@ package cn.iocoder.yudao.module.bpm.service.category; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategoryPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.category.BpmCategorySaveReqVO; -import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryServiceImpl; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.mysql.category.BpmCategoryMapper; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - +import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryServiceImpl; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CATEGORY_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.*; /** @@ -40,7 +38,8 @@ public class BpmCategoryServiceImplTest extends BaseDbUnitTest { @Test public void testCreateCategory_success() { // 准备参数 - BpmCategorySaveReqVO createReqVO = randomPojo(BpmCategorySaveReqVO.class).setId(null); + BpmCategorySaveReqVO createReqVO = randomPojo(BpmCategorySaveReqVO.class).setId(null) + .setStatus(randomCommonStatus()); // 调用 Long categoryId = categoryService.createCategory(createReqVO); @@ -59,6 +58,7 @@ public class BpmCategoryServiceImplTest extends BaseDbUnitTest { // 准备参数 BpmCategorySaveReqVO updateReqVO = randomPojo(BpmCategorySaveReqVO.class, o -> { o.setId(dbCategory.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); }); // 调用 @@ -101,29 +101,28 @@ public class BpmCategoryServiceImplTest extends BaseDbUnitTest { } @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 public void testGetCategoryPage() { // mock 数据 BpmCategoryDO dbCategory = randomPojo(BpmCategoryDO.class, o -> { // 等会查询到 - o.setName(null); - o.setCode(null); - o.setStatus(null); - o.setCreateTime(null); + o.setName("芋头"); + o.setCode("xiaodun"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2023, 2, 2)); }); categoryMapper.insert(dbCategory); // 测试 name 不匹配 - categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName(null))); + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName("小盾"))); // 测试 code 不匹配 - categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCode(null))); + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCode("tudou"))); // 测试 status 不匹配 - categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(null))); + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); // 测试 createTime 不匹配 - categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCreateTime(null))); + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setCreateTime(buildTime(2024, 2, 2)))); // 准备参数 BpmCategoryPageReqVO reqVO = new BpmCategoryPageReqVO(); - reqVO.setName(null); - reqVO.setCode(null); - reqVO.setStatus(null); + reqVO.setName("芋"); + reqVO.setCode("xiao"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); // 调用 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java index 50bc3ace7..93281a4fd 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSaveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; @@ -66,7 +65,7 @@ public class BpmFormServiceTest extends BaseDbUnitTest { }); formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据 // 准备参数 - BpmFormUpdateReqVO reqVO = randomPojo(BpmFormUpdateReqVO.class, o -> { + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { o.setId(dbForm.getId()); // 设置更新的 ID o.setConf("{'yudao': 'yuanma'}"); o.setFields(randomFields()); @@ -82,7 +81,7 @@ public class BpmFormServiceTest extends BaseDbUnitTest { @Test public void testUpdateForm_notExists() { // 准备参数 - BpmFormUpdateReqVO reqVO = randomPojo(BpmFormUpdateReqVO.class, o -> { + BpmFormSaveReqVO reqVO = randomPojo(BpmFormSaveReqVO.class, o -> { o.setConf("{'yudao': 'yuanma'}"); o.setFields(randomFields()); }); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql index 6e42d3cfc..d4f93bbc2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql @@ -1,2 +1,3 @@ DELETE FROM "bpm_form"; DELETE FROM "bpm_user_group"; +DELETE FROM "bpm_category"; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql index eae4d7e41..1034962c7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql @@ -12,6 +12,21 @@ CREATE TABLE IF NOT EXISTS "bpm_user_group" ( PRIMARY KEY ("id") ) COMMENT '用户组'; +CREATE TABLE IF NOT EXISTS "bpm_category" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "code" varchar(63) NOT NULL, + "description" varchar(255) NOT NULL, + "status" tinyint NOT NULL, + "sort" int NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '分类'; + CREATE TABLE IF NOT EXISTS "bpm_form" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" varchar(63) NOT NULL, From 889b9406b89a051b91ad3e4be40261f29d586c8d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 23 Mar 2024 15:58:45 +0800 Subject: [PATCH 23/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=9B=91=E5=90=AC=E5=99=A8=E3=80=81=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E5=99=A8=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 6 ++ .../definition/BpmProcessListenerType.java | 21 ++++ .../BpmProcessListenerValueType.java | 22 ++++ .../BpmProcessListenerController.java | 73 +++++++++++++ .../vo/category/BpmCategoryPageReqVO.java | 2 - .../definition/vo/form/BpmFormPageReqVO.java | 2 - .../vo/group/BpmUserGroupPageReqVO.java | 2 - .../listener/BpmProcessListenerPageReqVO.java | 24 +++++ .../vo/listener/BpmProcessListenerRespVO.java | 36 +++++++ .../listener/BpmProcessListenerSaveReqVO.java | 39 +++++++ .../vo/model/BpmModeImportReqVO.java | 2 - .../vo/model/BpmModelPageReqVO.java | 2 - .../BpmProcessDefinitionPageReqVO.java | 2 - .../admin/oa/vo/BpmOALeavePageReqVO.java | 2 - .../BpmProcessInstanceCopyPageReqVO.java | 4 - .../admin/task/vo/task/BpmTaskPageReqVO.java | 2 - .../dataobject/definition/BpmCategoryDO.java | 2 - .../dal/dataobject/definition/BpmFormDO.java | 4 +- .../BpmProcessDefinitionInfoDO.java | 4 +- .../definition/BpmProcessListenerDO.java | 70 ++++++++++++ .../definition/BpmTaskMessageRuleDO.java | 5 - .../dataobject/definition/BpmUserGroupDO.java | 4 +- .../bpm/dal/dataobject/oa/BpmOALeaveDO.java | 2 - .../task/BpmProcessInstanceCopyDO.java | 2 - .../definition/BpmProcessListenerMapper.java | 26 +++++ .../DemoDelegateClassExecutionListener.java | 21 ++++ ...moDelegateExpressionExecutionListener.java | 23 ++++ ...DemoSpringExpressionExecutionListener.java | 21 ++++ .../DemoDelegateClassExecutionListener.java | 22 ++++ ...moDelegateExpressionExecutionListener.java | 20 ++++ ...DemoSpringExpressionExecutionListener.java | 19 ++++ .../definition/BpmProcessListenerService.java | 54 ++++++++++ .../BpmProcessListenerServiceImpl.java | 102 ++++++++++++++++++ 33 files changed, 602 insertions(+), 40 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionExecutionListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java 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 70e13cbe1..b2b732ecf 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 @@ -66,4 +66,10 @@ public interface ErrorCodeConstants { ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); + // ========== BPM 流程监听器 1-009-013-000 ========== + ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在"); + ErrorCode PROCESS_LISTENER_CLASS_NOT_FOUND = new ErrorCode(1_009_013_001, "流程监听器类({})不存在"); + ErrorCode PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR = new ErrorCode(1_009_013_002, "流程监听器类({})没有实现接口({})"); + ErrorCode PROCESS_LISTENER_EXPRESSION_INVALID = new ErrorCode(1_009_013_003, "流程监听器表达式({})不合法"); + } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java new file mode 100644 index 000000000..3dde5dfb5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerType.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 流程监听器的类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessListenerType { + + EXECUTION("execution", "执行监听器"), + TASK("task", "任务执行器"); + + private final String type; + private final String name; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java new file mode 100644 index 000000000..63e23af23 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmProcessListenerValueType.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 流程监听器的值类型 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessListenerValueType { + + CLASS("class", "Java 类"), + DELEGATE_EXPRESSION("delegateExpression", "代理表达式"), + EXPRESSION("expression", "表达式"); + + private final String type; + private final String name; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java new file mode 100644 index 000000000..843f53dba --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessListenerController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessListenerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - BPM 流程监听器") +@RestController +@RequestMapping("/bpm/process-listener") +@Validated +public class BpmProcessListenerController { + + @Resource + private BpmProcessListenerService processListenerService; + + @PostMapping("/create") + @Operation(summary = "创建流程监听器") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:create')") + public CommonResult createProcessListener(@Valid @RequestBody BpmProcessListenerSaveReqVO createReqVO) { + return success(processListenerService.createProcessListener(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程监听器") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:update')") + public CommonResult updateProcessListener(@Valid @RequestBody BpmProcessListenerSaveReqVO updateReqVO) { + processListenerService.updateProcessListener(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程监听器") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-listener:delete')") + public CommonResult deleteProcessListener(@RequestParam("id") Long id) { + processListenerService.deleteProcessListener(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程监听器") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:query')") + public CommonResult getProcessListener(@RequestParam("id") Long id) { + BpmProcessListenerDO processListener = processListenerService.getProcessListener(id); + return success(BeanUtils.toBean(processListener, BpmProcessListenerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程监听器分页") + @PreAuthorize("@ss.hasPermission('bpm:process-listener:query')") + public CommonResult> getProcessListenerPage( + @Valid BpmProcessListenerPageReqVO pageReqVO) { + PageResult pageResult = processListenerService.getProcessListenerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmProcessListenerRespVO.class)); + } + +} \ 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/vo/category/BpmCategoryPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java index ea3c2cb6c..b76e96c31 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/category/BpmCategoryPageReqVO.java @@ -15,8 +15,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - BPM 流程分类分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmCategoryPageReqVO extends PageParam { @Schema(description = "分类名", example = "王五") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java index 0227e0ad9..1657f0204 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java @@ -8,8 +8,6 @@ import lombok.ToString; @Schema(description = "管理后台 - 动态表单分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmFormPageReqVO extends PageParam { @Schema(description = "表单名称", example = "芋道") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java index 499e47a42..234ff2849 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java @@ -12,8 +12,6 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - 用户组分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmUserGroupPageReqVO extends PageParam { @Schema(description = "编号", example = "1024") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java new file mode 100644 index 000000000..6783127f5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - BPM 流程监听器分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessListenerPageReqVO extends PageParam { + + @Schema(description = "监听器名字", example = "赵六") + private String name; + + @Schema(description = "监听器类型", example = "execution") + private String type; + + @Schema(description = "监听事件", example = "start") + private String event; + +} \ 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/vo/listener/BpmProcessListenerRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java new file mode 100644 index 000000000..f7a484254 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程监听器 Response VO") +@Data +public class BpmProcessListenerRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13089") + private Long id; + + @Schema(description = "监听器名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "监听器类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "execution") + private String type; + + @Schema(description = "监听器状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "监听事件", requiredMode = Schema.RequiredMode.REQUIRED, example = "start") + private String event; + + @Schema(description = "监听器值类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "class") + private String valueType; + + @Schema(description = "监听器值", requiredMode = Schema.RequiredMode.REQUIRED) + private String value; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ 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/vo/listener/BpmProcessListenerSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java new file mode 100644 index 000000000..f69d0dfe1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerSaveReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - BPM 流程监听器新增/修改 Request VO") +@Data +public class BpmProcessListenerSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13089") + private Long id; + + @Schema(description = "监听器名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "监听器名字不能为空") + private String name; + + @Schema(description = "监听器类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "execution") + @NotEmpty(message = "监听器类型不能为空") + private String type; + + @Schema(description = "监听器状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "监听器状态不能为空") + private Integer status; + + @Schema(description = "监听事件", requiredMode = Schema.RequiredMode.REQUIRED, example = "start") + @NotEmpty(message = "监听事件不能为空") + private String event; + + @Schema(description = "监听器值类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "class") + @NotEmpty(message = "监听器值类型不能为空") + private String valueType; + + @Schema(description = "监听器值", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "监听器值不能为空") + private String value; + +} \ 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/vo/model/BpmModeImportReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java index 798355057..a78a96fcb 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java @@ -10,8 +10,6 @@ import jakarta.validation.constraints.NotNull; @Schema(description = "管理后台 - 流程模型的导入 Request VO 相比流程模型的新建来说,只是多了一个 bpmnFile 文件") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmModeImportReqVO extends BpmModelCreateReqVO { @Schema(description = "BPMN 文件", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java index 86766f187..ec14b1aa8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java @@ -9,8 +9,6 @@ import lombok.ToString; @Schema(description = "管理后台 - 流程模型分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmModelPageReqVO extends PageParam { @Schema(description = "标识,精准匹配", example = "process1641042089407") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java index f5c7f36d6..828654f1e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java @@ -8,8 +8,6 @@ import lombok.ToString; @Schema(description = "管理后台 - 流程定义分页 Request VO") @Data -@ToString(callSuper = true) -@EqualsAndHashCode(callSuper = true) public class BpmProcessDefinitionPageReqVO extends PageParam { @Schema(description = "标识-精准匹配", example = "process1641042089407") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java index a754370cc..3777564b4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java @@ -13,8 +13,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - 请假申请分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmOALeavePageReqVO extends PageParam { @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/vo/instance/BpmProcessInstanceCopyPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java index a0c431814..b702afd2b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -13,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - 流程实例抄送的分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmProcessInstanceCopyPageReqVO extends PageParam { @Schema(description = "流程名称", example = "芋道") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java index fe115fdf0..d90eb632a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java @@ -12,8 +12,6 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - 流程任务的的分页 Request VO") // 待办、已办,都使用该分页 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class BpmTaskPageReqVO extends PageParam { @Schema(description = "流程任务名", example = "芋道") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java index 560a8ead6..916009d37 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java @@ -14,8 +14,6 @@ import lombok.*; @TableName("bpm_category") @KeySequence("bpm_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java index 76bf777e5..4c0218896 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java @@ -10,15 +10,13 @@ import lombok.*; import java.util.List; /** - * 工作流的表单定义 + * BPM 工作流的表单定义 * 用于工作流的申请表单,需要动态配置的场景 * * @author 芋道源码 */ @TableName(value = "bpm_form", autoResultMap = true) @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor 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 5f94b3b95..436476b27 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 @@ -11,15 +11,13 @@ import lombok.*; import java.util.List; /** - * Bpm 流程定义的拓信息 + * BPM 流程定义的拓信息 * 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表 * * @author 芋道源码 */ @TableName(value = "bpm_process_definition_info", autoResultMap = true) @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java new file mode 100644 index 000000000..56be88ff3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * BPM 流程监听器 DO + * + * 目的:本质上它是流程监听器的模版,用于 BPMN 在设计时,直接选择这些模版 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_listener") +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessListenerDO extends BaseDO { + + /** + * 主键 ID,自增 + */ + @TableId + private Long id; + /** + * 监听器名字 + */ + private String name; + /** + * 状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 监听类型 + * + * 枚举 {@link cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerType} + * + * 1. execution:ExecutionListener 执行监听器 + * 2. task:TaskListener 任务监听器 + */ + private String type; + /** + * 监听事件 + * + * execution 时:start、end + * task 时:create 创建、assignment 指派、complete 完成、delete 删除、update 更新、timeout 超时 + */ + private String event; + + /** + * 值类型 + * + * 1. class:Java 类,ExecutionListener 需要 {@link org.flowable.engine.delegate.JavaDelegate},TaskListener 需要 {@link org.flowable.engine.delegate.TaskListener} + * 2. delegateExpression:委托表达式,在 class 的基础上,需要注册到 Spring 容器里,后续表达式通过 Spring Bean 名称即可 + * 3. expression:表达式,一个普通类的普通方法,将这个普通类注册到 Spring 容器中,然后表达式中还可以执行这个类中的方法 + */ + private String valueType; + /** + * 值 + */ + private String value; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java deleted file mode 100644 index db204c027..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; - -// TODO 芋艿:先埋个坑。任务消息的配置规则。说白了,就是不同的 -public class BpmTaskMessageRuleDO { -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java index 6e209e241..87df0472b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java @@ -11,14 +11,12 @@ import lombok.*; import java.util.Set; /** - * Bpm 用户组 + * BPM 用户组 * * @author 芋道源码 */ @TableName(value = "bpm_user_group", autoResultMap = true) @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java index ca21b538c..ff63f8e43 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -18,8 +18,6 @@ import java.time.LocalDateTime; */ @TableName("bpm_oa_leave") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java index fe3b28de2..57e729605 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java @@ -13,8 +13,6 @@ import lombok.*; */ @TableName(value = "bpm_process_instance_copy", autoResultMap = true) @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java new file mode 100644 index 000000000..0b72aa283 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * BPM 流程监听器 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessListenerMapper extends BaseMapperX { + + default PageResult selectPage(BpmProcessListenerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmProcessListenerDO::getName, reqVO.getName()) + .eqIfPresent(BpmProcessListenerDO::getType, reqVO.getType()) + .eqIfPresent(BpmProcessListenerDO::getEvent, reqVO.getEvent()) + .orderByDesc(BpmProcessListenerDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java new file mode 100644 index 000000000..0ce920e3f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateClassExecutionListener.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +/** + * 类型为 class 的 ExecutionListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +public class DemoDelegateClassExecutionListener implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java new file mode 100644 index 000000000..00f3504ac --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoDelegateExpressionExecutionListener.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.stereotype.Component; + +/** + * 类型为 delegateExpression 的 ExecutionListener 监听器示例 + * + * 和 {@link DemoDelegateClassExecutionListener} 的差异是,需要注册到 Spring 中 + */ +@Component +@Slf4j +public class DemoDelegateExpressionExecutionListener implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java new file mode 100644 index 000000000..949140fdf --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/exection/DemoSpringExpressionExecutionListener.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.exection; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +/** + * 类型为 expression 的 ExecutionListener 监听器示例 + * + * 和 {@link DemoDelegateClassExecutionListener} 的差异是,需要注册到 Spring 中,但不用实现 {@link org.flowable.engine.delegate.JavaDelegate} 接口 + */ +@Component +@Slf4j +public class DemoSpringExpressionExecutionListener { + + public void execute(DelegateExecution execution) { + log.info("[execute][execution({}) 被调用!变量有:{}]", execution.getId(), + execution.getCurrentFlowableListener().getFieldExtensions()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassExecutionListener.java new file mode 100644 index 000000000..58578841a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassExecutionListener.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; + +/** + * 类型为 class 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class DemoDelegateClassExecutionListener implements TaskListener { + + @Override + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionExecutionListener.java new file mode 100644 index 000000000..8438a8b10 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateExpressionExecutionListener.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; + +/** + * 类型为 delegateExpression 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +public class DemoDelegateExpressionExecutionListener implements TaskListener { + + @Override + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionExecutionListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionExecutionListener.java new file mode 100644 index 000000000..75ba722f7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionExecutionListener.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.task.service.delegate.DelegateTask; + +/** + * 类型为 expression 的 TaskListener 监听器示例 + * + * @author 芋道源码 + */ +@Slf4j +public class DemoSpringExpressionExecutionListener { + + public void notify(DelegateTask delegateTask) { + log.info("[execute][task({}) 被调用]", delegateTask.getId()); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java new file mode 100644 index 000000000..65290054a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import jakarta.validation.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * BPM 流程监听器 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessListenerService { + + /** + * 创建流程监听器 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProcessListener(@Valid BpmProcessListenerSaveReqVO createReqVO); + + /** + * 更新流程监听器 + * + * @param updateReqVO 更新信息 + */ + void updateProcessListener(@Valid BpmProcessListenerSaveReqVO updateReqVO); + + /** + * 删除流程监听器 + * + * @param id 编号 + */ + void deleteProcessListener(Long id); + + /** + * 获得流程监听器 + * + * @param id 编号 + * @return 流程监听器 + */ + BpmProcessListenerDO getProcessListener(Long id); + + /** + * 获得流程监听器分页 + * + * @param pageReqVO 分页查询 + * @return 流程监听器分页 + */ + PageResult getProcessListenerPage(BpmProcessListenerPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java new file mode 100644 index 000000000..078c92287 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessListenerServiceImpl.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener.BpmProcessListenerSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessListenerDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessListenerMapper; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerType; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessListenerValueType; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.JavaDelegate; +import org.flowable.engine.delegate.TaskListener; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 流程监听器 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmProcessListenerServiceImpl implements BpmProcessListenerService { + + @Resource + private BpmProcessListenerMapper processListenerMapper; + + @Override + public Long createProcessListener(BpmProcessListenerSaveReqVO createReqVO) { + // 校验 + validateCreateProcessListenerValue(createReqVO); + // 插入 + BpmProcessListenerDO processListener = BeanUtils.toBean(createReqVO, BpmProcessListenerDO.class); + processListenerMapper.insert(processListener); + return processListener.getId(); + } + + @Override + public void updateProcessListener(BpmProcessListenerSaveReqVO updateReqVO) { + // 校验存在 + validateProcessListenerExists(updateReqVO.getId()); + validateCreateProcessListenerValue(updateReqVO); + // 更新 + BpmProcessListenerDO updateObj = BeanUtils.toBean(updateReqVO, BpmProcessListenerDO.class); + processListenerMapper.updateById(updateObj); + } + + private void validateCreateProcessListenerValue(BpmProcessListenerSaveReqVO createReqVO) { + // class 类型 + if (createReqVO.getValueType().equals(BpmProcessListenerValueType.CLASS.getType())) { + try { + Class clazz = Class.forName(createReqVO.getValue()); + if (createReqVO.getType().equals(BpmProcessListenerType.EXECUTION.getType()) + && !JavaDelegate.class.isAssignableFrom(clazz)) { + throw exception(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, createReqVO.getValue(), + JavaDelegate.class.getName()); + } else if (createReqVO.getType().equals(BpmProcessListenerType.TASK.getType()) + && !TaskListener.class.isAssignableFrom(clazz)) { + throw exception(PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR, createReqVO.getValue(), + TaskListener.class.getName()); + } + } catch (ClassNotFoundException e) { + throw exception(PROCESS_LISTENER_CLASS_NOT_FOUND, createReqVO.getValue()); + } + return; + } + // 表达式 + if (!StrUtil.startWith(createReqVO.getValue(), "${") || !StrUtil.endWith(createReqVO.getValue(), "}")) { + throw exception(PROCESS_LISTENER_EXPRESSION_INVALID, createReqVO.getValue()); + } + } + + @Override + public void deleteProcessListener(Long id) { + // 校验存在 + validateProcessListenerExists(id); + // 删除 + processListenerMapper.deleteById(id); + } + + private void validateProcessListenerExists(Long id) { + if (processListenerMapper.selectById(id) == null) { + throw exception(PROCESS_LISTENER_NOT_EXISTS); + } + } + + @Override + public BpmProcessListenerDO getProcessListener(Long id) { + return processListenerMapper.selectById(id); + } + + @Override + public PageResult getProcessListenerPage(BpmProcessListenerPageReqVO pageReqVO) { + return processListenerMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file From 6d44bf0d7a8839043723ceb9c9acf3deff5ace88 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 23 Mar 2024 19:23:11 +0800 Subject: [PATCH 24/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=9B=91=E5=90=AC=E5=99=A8=E3=80=81=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E5=99=A8=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/vo/listener/BpmProcessListenerPageReqVO.java | 6 ++++++ .../bpm/dal/mysql/definition/BpmProcessListenerMapper.java | 1 + ...tionListener.java => DemoDelegateClassTaskListener.java} | 2 +- ...istener.java => DemoDelegateExpressionTaskListener.java} | 4 +++- ...nListener.java => DemoSpringExpressionTaskListener.java} | 3 +-- 5 files changed, 12 insertions(+), 4 deletions(-) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/{DemoDelegateClassExecutionListener.java => DemoDelegateClassTaskListener.java} (87%) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/{DemoDelegateExpressionExecutionListener.java => DemoDelegateExpressionTaskListener.java} (78%) rename yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/{DemoSpringExpressionExecutionListener.java => DemoSpringExpressionTaskListener.java} (79%) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java index 6783127f5..d3b974672 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/listener/BpmProcessListenerPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.listener; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,4 +23,8 @@ public class BpmProcessListenerPageReqVO extends PageParam { @Schema(description = "监听事件", example = "start") private String event; + @Schema(description = "状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java index 0b72aa283..10ccd2fba 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessListenerMapper.java @@ -20,6 +20,7 @@ public interface BpmProcessListenerMapper extends BaseMapperX Date: Sat, 23 Mar 2024 21:11:53 +0800 Subject: [PATCH 25/26] =?UTF-8?q?BPM=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 3 + .../BpmProcessExpressionController.java | 73 +++++++++++++++++++ .../BpmProcessExpressionPageReqVO.java | 33 +++++++++ .../BpmProcessExpressionRespVO.java | 30 ++++++++ .../BpmProcessExpressionSaveReqVO.java | 27 +++++++ .../definition/BpmProcessExpressionDO.java | 45 ++++++++++++ .../BpmProcessExpressionMapper.java | 26 +++++++ .../BpmTaskAssignLeaderExpression.java | 2 +- .../BpmTaskAssignStartUserExpression.java | 3 +- .../BpmProcessExpressionService.java | 54 ++++++++++++++ .../BpmProcessExpressionServiceImpl.java | 72 ++++++++++++++++++ 11 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java 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 b2b732ecf..ec167719c 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 @@ -72,4 +72,7 @@ public interface ErrorCodeConstants { ErrorCode PROCESS_LISTENER_CLASS_IMPLEMENTS_ERROR = new ErrorCode(1_009_013_002, "流程监听器类({})没有实现接口({})"); ErrorCode PROCESS_LISTENER_EXPRESSION_INVALID = new ErrorCode(1_009_013_003, "流程监听器表达式({})不合法"); + // ========== BPM 流程表达式 1-009-014-000 ========== + ErrorCode PROCESS_EXPRESSION_NOT_EXISTS = new ErrorCode(1_009_014_000, "流程表达式不存在"); + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java new file mode 100644 index 000000000..4b119f799 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessExpressionController.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessExpressionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - BPM 流程表达式") +@RestController +@RequestMapping("/bpm/process-expression") +@Validated +public class BpmProcessExpressionController { + + @Resource + private BpmProcessExpressionService processExpressionService; + + @PostMapping("/create") + @Operation(summary = "创建流程表达式") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:create')") + public CommonResult createProcessExpression(@Valid @RequestBody BpmProcessExpressionSaveReqVO createReqVO) { + return success(processExpressionService.createProcessExpression(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新流程表达式") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:update')") + public CommonResult updateProcessExpression(@Valid @RequestBody BpmProcessExpressionSaveReqVO updateReqVO) { + processExpressionService.updateProcessExpression(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除流程表达式") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-expression:delete')") + public CommonResult deleteProcessExpression(@RequestParam("id") Long id) { + processExpressionService.deleteProcessExpression(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得流程表达式") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:query')") + public CommonResult getProcessExpression(@RequestParam("id") Long id) { + BpmProcessExpressionDO processExpression = processExpressionService.getProcessExpression(id); + return success(BeanUtils.toBean(processExpression, BpmProcessExpressionRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得流程表达式分页") + @PreAuthorize("@ss.hasPermission('bpm:process-expression:query')") + public CommonResult> getProcessExpressionPage( + @Valid BpmProcessExpressionPageReqVO pageReqVO) { + PageResult pageResult = processExpressionService.getProcessExpressionPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BpmProcessExpressionRespVO.class)); + } + +} \ 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/vo/expression/BpmProcessExpressionPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java new file mode 100644 index 000000000..37b02f0d9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - BPM 流程表达式分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessExpressionPageReqVO extends PageParam { + + @Schema(description = "表达式名字", example = "李四") + private String name; + + @Schema(description = "表达式状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ 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/vo/expression/BpmProcessExpressionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java new file mode 100644 index 000000000..d877f60a8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - BPM 流程表达式 Response VO") +@Data +public class BpmProcessExpressionRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3870") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "表达式名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("表达式名字") + private String name; + + @Schema(description = "表达式状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "表达式", requiredMode = Schema.RequiredMode.REQUIRED) + private String expression; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ 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/vo/expression/BpmProcessExpressionSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java new file mode 100644 index 000000000..9c7301a7d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/expression/BpmProcessExpressionSaveReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - BPM 流程表达式新增/修改 Request VO") +@Data +public class BpmProcessExpressionSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3870") + private Long id; + + @Schema(description = "表达式名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "表达式名字不能为空") + private String name; + + @Schema(description = "表达式状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "表达式状态不能为空") + private Integer status; + + @Schema(description = "表达式", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "表达式不能为空") + private String expression; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java new file mode 100644 index 000000000..6f6be586e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * BPM 流程表达式 DO + * + * @author 芋道源码 + */ +@TableName("bpm_process_expression") +@KeySequence("bpm_process_expression_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessExpressionDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 表达式名字 + */ + private String name; + /** + * 表达式状态 + * + * 枚举 {@link TODO common_status 对应的类} + */ + private Integer status; + /** + * 表达式 + */ + private String expression; + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java new file mode 100644 index 000000000..ab8c18ccf --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessExpressionMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * BPM 流程表达式 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessExpressionMapper extends BaseMapperX { + + default PageResult selectPage(BpmProcessExpressionPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmProcessExpressionDO::getName, reqVO.getName()) + .eqIfPresent(BpmProcessExpressionDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmProcessExpressionDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmProcessExpressionDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java index 7a021ab2b..0200dbace 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -34,7 +34,7 @@ public class BpmTaskAssignLeaderExpression { @Resource private BpmProcessInstanceService processInstanceService; - protected Set calculateUsers(DelegateExecution execution, int level) { + public Set calculateUsers(DelegateExecution execution, int level) { Assert.isTrue(level > 0, "level 必须大于 0"); // 获得发起人 ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java index 451ceed60..4df9eb1a5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import jakarta.annotation.Resource; -import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Component; @@ -21,7 +20,7 @@ public class BpmTaskAssignStartUserExpression { @Resource private BpmProcessInstanceService processInstanceService; - public Set calculateUsers(DelegateExecution execution) { + public Set calculateUsers(org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl execution) { ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); return SetUtils.asSet(startUserId); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java new file mode 100644 index 000000000..caca96e25 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import jakarta.validation.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * BPM 流程表达式 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessExpressionService { + + /** + * 创建流程表达式 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProcessExpression(@Valid BpmProcessExpressionSaveReqVO createReqVO); + + /** + * 更新流程表达式 + * + * @param updateReqVO 更新信息 + */ + void updateProcessExpression(@Valid BpmProcessExpressionSaveReqVO updateReqVO); + + /** + * 删除流程表达式 + * + * @param id 编号 + */ + void deleteProcessExpression(Long id); + + /** + * 获得流程表达式 + * + * @param id 编号 + * @return 流程表达式 + */ + BpmProcessExpressionDO getProcessExpression(Long id); + + /** + * 获得流程表达式分页 + * + * @param pageReqVO 分页查询 + * @return 流程表达式分页 + */ + PageResult getProcessExpressionPage(BpmProcessExpressionPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java new file mode 100644 index 000000000..122f3921d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessExpressionServiceImpl.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.expression.BpmProcessExpressionSaveReqVO; +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessExpressionDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessExpressionMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 流程表达式 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmProcessExpressionServiceImpl implements BpmProcessExpressionService { + + @Resource + private BpmProcessExpressionMapper processExpressionMapper; + + @Override + public Long createProcessExpression(BpmProcessExpressionSaveReqVO createReqVO) { + // 插入 + BpmProcessExpressionDO processExpression = BeanUtils.toBean(createReqVO, BpmProcessExpressionDO.class); + processExpressionMapper.insert(processExpression); + // 返回 + return processExpression.getId(); + } + + @Override + public void updateProcessExpression(BpmProcessExpressionSaveReqVO updateReqVO) { + // 校验存在 + validateProcessExpressionExists(updateReqVO.getId()); + // 更新 + BpmProcessExpressionDO updateObj = BeanUtils.toBean(updateReqVO, BpmProcessExpressionDO.class); + processExpressionMapper.updateById(updateObj); + } + + @Override + public void deleteProcessExpression(Long id) { + // 校验存在 + validateProcessExpressionExists(id); + // 删除 + processExpressionMapper.deleteById(id); + } + + private void validateProcessExpressionExists(Long id) { + if (processExpressionMapper.selectById(id) == null) { + throw exception(PROCESS_EXPRESSION_NOT_EXISTS); + } + } + + @Override + public BpmProcessExpressionDO getProcessExpression(Long id) { + return processExpressionMapper.selectById(id); + } + + @Override + public PageResult getProcessExpressionPage(BpmProcessExpressionPageReqVO pageReqVO) { + return processExpressionMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file From 5c5bd0e5dab432d53128fb2c3909f710614de530 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 24 Mar 2024 10:08:51 +0800 Subject: [PATCH 26/26] =?UTF-8?q?BPM=EF=BC=9A=E6=B5=81=E7=A8=8B=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=20icon=20=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmModelFormTypeEnum.java | 15 +++++++++++++-- .../definition/vo/model/BpmModelRespVO.java | 17 +++++++++-------- .../vo/model/BpmModelUpdateReqVO.java | 11 +++++++++-- .../process/BpmProcessDefinitionRespVO.java | 3 +++ .../convert/definition/BpmModelConvert.java | 19 ++++++++++++------- .../BpmProcessDefinitionConvert.java | 1 - .../BpmProcessDefinitionInfoDO.java | 5 +++++ .../dto/BpmModelMetaInfoRespDTO.java | 5 +++++ 8 files changed, 56 insertions(+), 20 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java index c21d6f999..3bca6c82b 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.bpm.enums.definition; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Arrays; + /** * BPM 模型的表单类型的枚举 * @@ -10,12 +13,20 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum BpmModelFormTypeEnum { +public enum BpmModelFormTypeEnum implements IntArrayValuable { NORMAL(10, "流程表单"), // 对应 BpmFormDO CUSTOM(20, "业务表单") // 业务自己定义的表单,自己进行数据的存储 ; + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmModelFormTypeEnum::getType).toArray(); + private final Integer type; - private final String desc; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + } 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 c08393359..aad2015c7 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 @@ -19,6 +19,9 @@ public class BpmModelRespVO { @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; + @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + @Schema(description = "流程描述", example = "我是描述") private String description; @@ -30,17 +33,15 @@ public class BpmModelRespVO { @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") private Integer formType; - @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") - private Long formId; + @Schema(description = "表单编号", example = "1024") + private Long formId; // 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 @Schema(description = "表单名字", example = "请假表单") private String formName; - @Schema(description = "自定义表单的提交路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/create") - private String formCustomCreatePath; - @Schema(description = "自定义表单的查看路径,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", - example = "/bpm/oa/leave/view") - private String formCustomViewPath; + @Schema(description = "自定义表单的提交路径", example = "/bpm/oa/leave/create") + private String formCustomCreatePath; // 使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 + @Schema(description = "自定义表单的查看路径", example = "/bpm/oa/leave/view") + private String formCustomViewPath; // ,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java index cc2420b28..94585af3d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.hibernate.validator.constraints.URL; @Schema(description = "管理后台 - 流程模型的更新 Request VO") @Data @@ -16,6 +18,10 @@ public class BpmModelUpdateReqVO { @Schema(description = "流程名称", example = "芋道") private String name; + @Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg") + @URL(message = "流程图标格式不正确") + private String icon; + @Schema(description = "流程描述", example = "我是描述") private String description; @@ -26,6 +32,7 @@ public class BpmModelUpdateReqVO { private String bpmnXml; @Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1") + @InEnum(BpmModelFormTypeEnum.class) private Integer formType; @Schema(description = "表单编号-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空", example = "1024") private Long formId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java index f54e31803..2fb8dd4dc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -22,6 +22,9 @@ public class BpmProcessDefinitionRespVO { @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") private String key; + @Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg") + private String icon; + @Schema(description = "流程描述", example = "我是描述") private String 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 373e71bf3..3fe5cc068 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 @@ -71,7 +71,7 @@ public interface BpmModelConvert { modelRespVO.setFormType(metaInfo.getFormType()).setFormId(metaInfo.getFormId()) .setFormCustomCreatePath(metaInfo.getFormCustomCreatePath()) .setFormCustomViewPath(metaInfo.getFormCustomViewPath()); - modelRespVO.setDescription(metaInfo.getDescription()); + modelRespVO.setIcon(metaInfo.getIcon()).setDescription(metaInfo.getDescription()); } if (form != null) { modelRespVO.setFormId(form.getId()).setFormName(form.getName()); @@ -95,24 +95,29 @@ public interface BpmModelConvert { default void copyToCreateModel(Model model, BpmModelCreateReqVO bean) { model.setName(bean.getName()); model.setKey(bean.getKey()); - model.setMetaInfo(buildMetaInfoStr(null, bean.getDescription(), null, null, - null, null)); + model.setMetaInfo(buildMetaInfoStr(null, + null, bean.getDescription(), + null, null, null, null)); } default void copyToUpdateModel(Model model, BpmModelUpdateReqVO bean) { model.setName(bean.getName()); model.setCategory(bean.getCategory()); model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), - bean.getDescription(), bean.getFormType(), bean.getFormId(), - bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); + bean.getIcon(), bean.getDescription(), + bean.getFormType(), bean.getFormId(), bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); } - default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType, - Long formId, String formCustomCreatePath, String formCustomViewPath) { + default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, + String icon, String description, + Integer formType, Long formId, String formCustomCreatePath, String formCustomViewPath) { if (metaInfo == null) { metaInfo = new BpmModelMetaInfoRespDTO(); } // 只有非空,才进行设置,避免更新时的覆盖 + if (StrUtil.isNotEmpty(icon)) { + metaInfo.setIcon(icon); + } if (StrUtil.isNotEmpty(description)) { metaInfo.setDescription(description); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java index 61187424b..0e767d787 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -33,7 +33,6 @@ public interface BpmProcessDefinitionConvert { BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class); - default PageResult buildProcessDefinitionPage(PageResult page, Map deploymentMap, Map processDefinitionInfoMap, 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 436476b27..9ac9252d5 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 @@ -40,6 +40,11 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { * 关联 Model 的 id 属性 */ private String modelId; + + /** + * 图标 + */ + private String icon; /** * 描述 */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java index 5b4ef3da5..8ec9dc64b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java @@ -14,10 +14,15 @@ import lombok.Data; @Data public class BpmModelMetaInfoRespDTO { + /** + * 流程图标 + */ + private String icon; /** * 流程描述 */ private String description; + /** * 表单类型 */