From cdbcd4d673d491ad5203b8cdb05b00919deda6c9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 13 Mar 2024 21:18:07 +0800 Subject: [PATCH 01/33] =?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 ea131e86e4..c928e2fcfd 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 08cea833f1..c434b2577f 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 51eebda236..646841b348 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 25426f6047..62b1dff1cc 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 3c7e404de7..0000000000 --- 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 1521abc8e0..0000000000 --- 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 90e6b7e33e..0000000000 --- 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 ac4f85e789..0000000000 --- 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 7d13cc07ad..0000000000 --- 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 c616e90b09..0000000000 --- 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 e65764f1a8..0000000000 --- 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 c4061c0f88..0000000000 --- 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 08f8acf6bd..7012fa9f80 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 c9b3872cdc..dd5f035a9d 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 47cf2c0ed2..012141adf9 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 e035be070c..b7bab57534 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 2ce14a2013..6ae6e06ca5 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 d41ae4c14d..2690787614 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 7b23a467a0..6de30aa94f 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/33] =?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 b7ccc7ae82..d220da7468 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 b5c91ebad8..c390590481 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 9ef7d3b30c..22ef4cde7b 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 af7d8b5a74..9c31970f76 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 068ab3d2f3..9355451008 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 8f4c2c2659..0329aec6a1 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 ee81a9cf46..0000000000 --- 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 7012fa9f80..00ba49de4c 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 b7bab57534..a1474afd0d 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 c3cce4272c..f279e95df4 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 2a0fc38ac5..d697989953 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 bc850b5902..e5b816b9b2 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/33] =?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 3a66524bc1..1b5fc92c15 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 c434b2577f..d236d1817f 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 646841b348..bdc3d17ce5 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 d220da7468..0000000000 --- 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 7fc0e3b8bc..0000000000 --- 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 cff03488b2..0000000000 --- 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 c048d9c732..9248da552b 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 dced1c5bdc..e9f1f32d7c 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 0b60faa067..ed51b23fa2 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 aeda4d52c4..de17502bf2 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 c390590481..0000000000 --- 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 9c31970f76..0000000000 --- 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 9355451008..0000000000 --- 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 0000000000..d1ba65df2b --- /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 0000000000..a5c5c9b4d9 --- /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 22ef4cde7b..cb5306548d 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 0329aec6a1..c4d8811b41 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 0000000000..485552f91f --- /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 0000000000..f60b1cc8b2 --- /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 0000000000..f8be5fe3e4 --- /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 0000000000..b8fa00f84d --- /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 0000000000..3f2ae58f15 --- /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 0000000000..0dd1786268 --- /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 0000000000..390e4903a0 --- /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 0000000000..0c31998215 --- /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 0000000000..c8fefd55b3 --- /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 0c5f099d68..0000000000 --- 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 0fe741c201..0000000000 --- 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 dafc0835ac..0000000000 --- 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 536b3eec21..0000000000 --- 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 6fcfa23fd7..0000000000 --- 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 f924d87ef3..0000000000 --- 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 f3ba5b92bb..0000000000 --- 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 4bf25694d1..0000000000 --- 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 b0720b0d54..0000000000 --- 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 00ba49de4c..729e176b0f 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 dd5f035a9d..82f15beecf 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 012141adf9..0000000000 --- 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 a1474afd0d..0000000000 --- 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 208749a576..4d1db29585 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 50d042cdc8..d800d1932d 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 0000000000..702dce3f17 --- /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 f462780835..b9a77ca79e 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 0000000000..9b89e2bd38 --- /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 0000000000..4e72c0281a --- /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 0000000000..caa668eac8 --- /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 0000000000..07958a51b7 --- /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 0000000000..a30ce28eb0 --- /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 0000000000..7c4247bcd1 --- /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 0000000000..d71ccebfd7 --- /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 29caf9ced7..0000000000 --- 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 2ca2ff914c..0000000000 --- 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 f279e95df4..0000000000 --- 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 de8d6279d7..0000000000 --- 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 324d3de0ec..0000000000 --- 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/33] =?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 e9f1f32d7c..b5278f5aba 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 ed51b23fa2..938d04ed1d 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 0000000000..1e4ebc1416 --- /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 de17502bf2..c494652731 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/33] =?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 70a31dd342..089690457b 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 0000000000..1db19cf649 --- /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 62b1dff1cc..0000000000 --- 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 9d1301a277..c22ee3c6b8 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 6bb269f1d1..4cfaf171d5 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 a9cc810f72..faa770c473 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 1a79441cef..14dca13ea6 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 41f2184c5c..11166c62e3 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 5a481fff0f..0000000000 --- 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 52e66219c2..0000000000 --- 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 0000000000..b2bd419e6a --- /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 c8fefd55b3..3eb6981ef9 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 9f37c9ae75..f8e5920f17 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 f2d5c9d0ec..5f6d5f1482 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 82f15beecf..ef8fd6e4d0 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 01a29c5593..ca312df812 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 1a4b437e1c..fa92e7e6ec 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/33] =?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 bdc3d17ce5..e88e27b1f2 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 615416c736..bd4f361d5c 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 089690457b..b8c05ad98c 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 42c212e28c..47e06bf6fb 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 8f51441587..c7fd78cacc 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 efecbf5821..c78d8a4324 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 60ce840218..2f94219833 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 a79fce4128..7ebe25e01e 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 8108e613da..0d91545c2e 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 b2bd419e6a..7649b0fbcb 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 08638a9d3c..7a647c2059 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 76fe216696..3c786d805d 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 ca312df812..bb94dd2e22 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 97018451d6..08a07bdb55 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 6e9929d379..199662519c 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/33] =?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 1db19cf649..0000000000 --- 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 ba14b61f1d..78429ea210 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 c7fd78cacc..0000000000 --- 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 52daea445e..0000000000 --- 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 605007ef5c..fe115fdf06 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 1af839e26b..1e1bebf043 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 ca27ff6d5d..a5c3edac2e 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 b98a25a222..0000000000 --- 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 c78d8a4324..0000000000 --- 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 4b57f47770..0000000000 --- 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 2f94219833..dcc34f0de8 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 7ebe25e01e..0000000000 --- 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 0d91545c2e..0000000000 --- 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 08a07bdb55..6114a612b1 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 199662519c..9587de8236 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/33] =?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 89d56b3c08..06269a31e8 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 e1ad107ab0..e86f013151 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 78429ea210..f18926582f 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 0000000000..4b397fc1c7 --- /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 3a1b1d45c2..0000000000 --- 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 4b149a65e4..0000000000 --- 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 7b4effaddf..a0c431814b 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 14dca13ea6..c5ca09b371 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 f482c71e6f..0000000000 --- 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 dcc34f0de8..8bbe10f8bd 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 7ca65f3db2..99bca609d6 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 de6fa14f53..2179525e00 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 4d1db29585..67135167af 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 0000000000..e45ce881cd --- /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 9587de8236..a2211e6402 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 d800d1932d..0000000000 --- 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 d010d89691..0000000000 --- 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/33] =?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 06269a31e8..f2c2ded53a 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 bd4f361d5c..ee06b08476 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 1e1bebf043..46ac3f36d4 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 8bbe10f8bd..ee7b5245ce 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 6a53114a8c..0000000000 --- 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 4e4e68d6f7..e24ce02adf 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 7649b0fbcb..6dd5e79c7b 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 3c786d805d..9477e667dd 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 a2211e6402..b0bc45e3f0 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 6de30aa94f..264dd7ec66 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 665e98fbed..43e681c5e7 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/33] =?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 f2c2ded53a..c48b4f439c 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 ee06b08476..020ed3daf7 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 2d16206617..cd1fce4416 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 b0bc45e3f0..915bc6162c 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/33] =?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 e88e27b1f2..cb22e70fc1 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 c48b4f439c..8a7757cca0 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 f18926582f..151610e2b7 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 51c10bfc58..b388705ceb 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 6114a612b1..1e60ce04f3 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 915bc6162c..2044d98996 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/33] =?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 8a7757cca0..8b7b7ce11f 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 0000000000..ed07b330ab --- /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 4f99d0a3dc..0000000000 --- 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 f8e5920f17..cf1506e8df 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 7a647c2059..a8f1788f34 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 bb94dd2e22..1e78c271e1 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 fa92e7e6ec..6b81092ace 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 1e60ce04f3..4ec8272a57 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 2044d98996..5c1de8a56a 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/33] =?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 cb22e70fc1..a689ad3e62 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 47e06bf6fb..b01153d794 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 020ed3daf7..eb4af0f623 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 151610e2b7..6e17a0901d 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 68369696b5..0000000000 --- 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 0000000000..71278b37f5 --- /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 a2966a399e..9ea8a105b8 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 ee7b5245ce..e9f04f4981 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 4ec8272a57..83bb3eb0a9 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 5c1de8a56a..aa1fc6345b 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/33] =?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 82404b9253..64b80345c0 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 416c4793ae..0000000000 --- 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 05f17788ab..499e47a420 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 0f89e95388..f20722a8d7 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 efe1155c3c..1993cdba07 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 e5e2060bb7..0000000000 --- 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 02bb2b31c4..0000000000 --- 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 bbf00ba524..0000000000 --- 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 ec11681805..6e209e241c 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 b8fa00f84d..bc161886b0 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 6ae6e06ca5..a95dc24dac 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 2690787614..3c64891046 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 07958a51b7..8bd2c88afd 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 9aca274768..438e3193cb 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/33] =?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 a689ad3e62..494e4a1b5d 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 b8c05ad98c..82a4119b57 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 f1ac4c0ee8..1a4b410e88 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 0000000000..322666615b --- /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 4e7195ccdd..4143076fff 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 0c0fcd7d34..ff3c37b08d 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 0000000000..ea3c2cb6cd --- /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 0000000000..7ada55a1d9 --- /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 0000000000..352cf690b4 --- /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 c0b1443cbe..0000000000 --- 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 4fc5b61d49..0000000000 --- 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 15283208e4..86766f1878 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 df4abf750b..c083933596 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 9cfb7bbbe3..cc2420b289 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 4d583dac23..7c5a356a24 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 35243d2ac7..0000000000 --- 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 901c8aa770..0000000000 --- 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 c649c8219f..bf015920ee 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 c22ee3c6b8..05c8458274 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 e86f013151..e9f0eb4441 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 5b5d9fb26d..4945b2b9ad 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 4cfaf171d5..f1763a27f5 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 faa770c473..e0410e6be8 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 9f79032f60..a0abde8c61 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 b52b48ee9e..f1e9451788 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 11166c62e3..a7c621590e 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 0000000000..2fe0963bb5 --- /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 57abc0b99b..5f94b3b95d 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 99bca609d6..fe3b28de28 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 0000000000..888856a45a --- /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 3ff53f2d9c..0000000000 --- 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 0000000000..419d638f8e --- /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 2179525e00..c5ec50f659 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 0000000000..a61b132b5e --- /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 0000000000..8db37a46e4 --- /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 dd618226e5..9c61ae4272 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 54bee9ce1e..d805da6a69 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 bddd790816..e1acce0649 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 729e176b0f..933a0b5bfc 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 5f6d5f1482..163fc24aa6 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 ef8fd6e4d0..20a9ee95b0 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 eb715edb42..ae3f38a96d 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 67135167af..bd84490e8e 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 e45ce881cd..aba8bd9f17 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 6b81092ace..f9a44482b8 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 0000000000..cf0954503c --- /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 0000000000..19f576818b --- /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/33] =?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 b20a449df5..629742bc82 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 6e17a0901d..c00f4beb43 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 93c22dddc8..f477498616 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 c5ca09b371..0be06a6c8d 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 46ac3f36d4..27add6000d 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 a0abde8c61..7bcd82a1b9 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 a7c621590e..b1129b2d43 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 e9f04f4981..625282b0f9 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 f9a44482b8..b6b9b142e6 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 aa1fc6345b..95c5e7cf45 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 d697989953..7863bece98 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/33] =?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 491c99771a..95b798904c 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 1a4b410e88..1ac423e11c 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 b1129b2d43..7a73dabdc3 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 625282b0f9..82593b08cb 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 efc6d5340d..6e4fb99e32 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 7a6ca7711d..0000000000 --- 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 c4a1311289..0000000000 --- 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 b97cb4c8ae..0000000000 --- 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 9a5e3ea962..0000000000 --- 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 9248da552b..979d191535 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 938d04ed1d..64ebb1aac8 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 1e4ebc1416..a214e26255 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 d1ba65df2b..e1fb626320 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 f8be5fe3e4..e51ab76e00 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 b759fe1e16..7457e3d23e 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 264dd7ec66..a72a4b396b 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 7863bece98..3fceb60fd2 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 aa9daedab1..d4af61c9bf 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 d2135290fd..29fc7c3bff 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 b6b9b142e6..26b4cefa42 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 95c5e7cf45..dc89a670fd 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 caa668eac8..eaa2ef7b58 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 ae0ed46eef..0000000000 --- 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 859eca510d..0000000000 --- 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 1df61598ce..0000000000 --- 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/33] =?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 494e4a1b5d..310e1b623c 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 4143076fff..dcf91260fb 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 c00f4beb43..d721cf7a8f 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 7bcd82a1b9..373e71bf36 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 f1e9451788..1b5897dd50 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 82593b08cb..ac1da99a0f 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 a72a4b396b..9763bc8a60 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 9c61ae4272..fa9484708f 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 d805da6a69..0575129950 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 933a0b5bfc..511b4902ae 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 163fc24aa6..7126d652ef 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 20a9ee95b0..85418fb830 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 3a36b0eeb0..5b4ef3da53 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 ae3f38a96d..4008f8f077 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/33] =?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 9b703728d4..f320948437 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 bff99a8c19..f8b1863c6c 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 b5065ed48e..b957a75a7a 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 fcc0cc167a..0000000000 --- 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 aa014a584d..0000000000 --- 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 b8c8f531fe..1c4eb762ca 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 0000000000..4da13aaf8c --- /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 71d8a1f802..0000000000 --- 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 4248547802..0000000000 --- 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 bf015920ee..4fa56d4a37 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 b964694a5a..1447494506 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 f7089f8594..0000000000 --- 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 56ee98b337..8f84a281d2 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 903a0fcf27..a754370ccb 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 669e309e7e..dbfe9d90f3 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 05c8458274..2db6b76f91 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 ab6468204c..8f959e0938 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 f1763a27f5..0000000000 --- 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 e0410e6be8..d6e67dd349 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 27add6000d..26b8e80b05 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 6ba7574170..0000000000 --- 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 f87531bfc5..0000000000 --- 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 7a73dabdc3..1f6e38a3d4 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 ac1da99a0f..67b882c954 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 e24ce02adf..ca21b538cd 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 ad05b98041..2787874506 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 7457e3d23e..bf85c58c8e 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 fa9484708f..3c8425084c 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 0575129950..95f2759938 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 511b4902ae..eb392ace2f 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 3089566598..24ca6d3227 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 9477e667dd..c71d885054 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 e1dccb52bd..8c70306fb5 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 1e78c271e1..3473cbcadf 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 26b4cefa42..f589e29cdd 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 dc89a670fd..e7759c56ec 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 cf0954503c..0000000000 --- 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 fbc069d8aa..50bc3ace76 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 438e3193cb..cf119f2152 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 20a939b761..eae4d7e41a 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 256259bdf7..14d3c66aac 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 8c4f3e974d..4bf0497e60 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 4eaba09c83..017258b7f9 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/33] =?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 ed07b330ab..802b9d8904 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 4fa56d4a37..27164c6957 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 2db6b76f91..3208013bd7 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 4945b2b9ad..bc658eb874 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 d6e67dd349..ac6b90c7e1 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 26b8e80b05..7f5177b948 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 1f6e38a3d4..745eab330b 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 67b882c954..6fd404e289 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 979d191535..8e69fdc752 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 bf85c58c8e..c0429f2c3a 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 3473cbcadf..4ef484551d 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 f589e29cdd..39914df9c6 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 e7759c56ec..9740552834 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/33] =?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 d721cf7a8f..7d72a133bd 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 745eab330b..5d28c99a76 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 6fd404e289..5f4e915d3f 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 83bb3eb0a9..f69757f142 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 9740552834..7afed756b8 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/33] =?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 629742bc82..b1ac35366f 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 310e1b623c..70e13cbe18 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 ff3c37b08d..149737ca0f 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 352cf690b4..d1a175ec57 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 27164c6957..f54e318031 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 8f84a281d2..856a225477 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 3208013bd7..50fbc9fa8b 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 f477498616..b13ff561fb 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 1b5897dd50..61187424bb 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 5d28c99a76..d2b326e116 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 2fe0963bb5..560a8ead6d 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 888856a45a..5fc8236e84 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 6e4fb99e32..0000000000 --- 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 e1fb626320..7bad358070 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 a5c5c9b4d9..1534d39c28 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 cb5306548d..7a021ab2be 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 c4d8811b41..451ceed609 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 0000000000..ef31d88854 --- /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 6dd5e79c7b..e965d22811 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 0c31998215..a8b5385012 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 9763bc8a60..bcf82d731c 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 3fceb60fd2..6a65dd8044 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 95f2759938..d49018f6ba 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 7126d652ef..5e2e2f8051 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 85418fb830..3324a5e79a 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 c71d885054..9a84f676a8 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 4ef484551d..9ba4cb0774 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 39914df9c6..f6283eff84 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 b9a77ca79e..f7eac7ca0d 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 19f576818b..f71b8aae50 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 50bc3ace76..93281a4fde 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 6e42d3cfc6..d4f93bbc27 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 eae4d7e41a..1034962c70 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/33] =?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 70e13cbe18..b2b732ecfe 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 0000000000..3dde5dfb53 --- /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 0000000000..63e23af236 --- /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 0000000000..843f53dbaf --- /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 ea3c2cb6cd..b76e96c314 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 0227e0ad92..1657f02046 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 499e47a420..234ff2849d 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 0000000000..6783127f55 --- /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 0000000000..f7a484254b --- /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 0000000000..f69d0dfe1a --- /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 798355057f..a78a96fcbd 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 86766f1878..ec14b1aa8e 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 f5c7f36d61..828654f1e7 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 a754370ccb..3777564b4a 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 a0c431814b..b702afd2bf 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 fe115fdf06..d90eb632a9 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 560a8ead6d..916009d377 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 76bf777e5d..4c0218896d 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 5f94b3b95d..436476b27d 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 0000000000..56be88ff3c --- /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 db204c0273..0000000000 --- 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 6e209e241c..87df0472bf 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 ca21b538cd..ff63f8e43b 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 fe3b28de28..57e729605d 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 0000000000..0b72aa283e --- /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 0000000000..0ce920e3fd --- /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 0000000000..00f3504ace --- /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 0000000000..949140fdfc --- /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 0000000000..58578841a2 --- /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 0000000000..8438a8b10a --- /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 0000000000..75ba722f75 --- /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 0000000000..65290054a8 --- /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 0000000000..078c92287a --- /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/33] =?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} (77%) 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 6783127f55..d3b9746727 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 0b72aa283e..10ccd2fbae 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/33] =?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 b2b732ecfe..ec167719cc 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 0000000000..4b119f7996 --- /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 0000000000..37b02f0d9f --- /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 0000000000..d877f60a88 --- /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 0000000000..9c7301a7d7 --- /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 0000000000..6f6be586ec --- /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 0000000000..ab8c18ccf6 --- /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 7a021ab2be..0200dbace3 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 451ceed609..4df9eb1a56 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 0000000000..caca96e25e --- /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 0000000000..122f3921da --- /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/33] =?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 c21d6f9991..3bca6c82b8 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 c083933596..aad2015c7e 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 cc2420b289..94585af3de 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 f54e318031..2fb8dd4dcb 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 373e71bf36..3fe5cc068e 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 61187424bb..0e767d787c 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 436476b27d..9ac9252d5b 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 5b4ef3da53..8ec9dc64b3 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; + /** * 表单类型 */ From 18f6bdd1c0f624d36859f56c921fa2349ae04762 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 24 Mar 2024 10:41:54 +0800 Subject: [PATCH 27/33] =?UTF-8?q?=E6=9C=80=E6=96=B0=E8=8F=9C=E5=8D=95=20SQ?= =?UTF-8?q?L=20=E7=9A=84=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/ruoyi-vue-pro.sql | 134 +++++++++++------- .../banner/core/BannerApplicationRunner.java | 2 +- 2 files changed, 83 insertions(+), 53 deletions(-) diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 49da40058b..e5e9635625 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -11,7 +11,7 @@ Target Server Version : 80200 (8.2.0) File Encoding : 65001 - Date: 01/03/2024 19:39:45 + Date: 24/03/2024 10:40:51 */ SET NAMES utf8mb4; @@ -385,7 +385,7 @@ CREATE TABLE `infra_api_error_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 15660 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 16372 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; -- ---------------------------- -- Records of infra_api_error_log @@ -423,7 +423,7 @@ CREATE TABLE `infra_codegen_column` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2248 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; +) ENGINE = InnoDB AUTO_INCREMENT = 2305 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义'; -- ---------------------------- -- Records of infra_codegen_column @@ -461,7 +461,7 @@ CREATE TABLE `infra_codegen_table` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 171 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; +) ENGINE = InnoDB AUTO_INCREMENT = 176 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义'; -- ---------------------------- -- Records of infra_codegen_table @@ -690,7 +690,7 @@ CREATE TABLE `infra_file` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1281 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1294 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; -- ---------------------------- -- Records of infra_file @@ -879,7 +879,7 @@ CREATE TABLE `system_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1509 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1529 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; -- ---------------------------- -- Records of system_dict_data @@ -973,26 +973,21 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, 0, '等待退款', '0', 'pay_refund_status', 0, 'info', '', '等待退款', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, 20, '退款失败', '20', 'pay_refund_status', 0, 'danger', '', '退款失败', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1124, 10, '退款成功', '10', 'pay_refund_status', 0, 'success', '', '退款成功', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1125, 0, '默认', '1', 'bpm_model_category', 0, 'primary', '', '流程分类 - 默认', '1', '2022-01-02 08:41:11', '1', '2022-02-16 20:01:42', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1126, 0, 'OA', '2', 'bpm_model_category', 0, 'success', '', '流程分类 - OA', '1', '2022-01-02 08:41:22', '1', '2022-02-16 20:01:50', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1127, 0, '进行中', '1', 'bpm_process_instance_status', 0, 'primary', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2022-02-16 20:07:49', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1128, 2, '已完成', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2022-02-16 20:07:54', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1129, 1, '处理中', '1', 'bpm_process_instance_result', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2022-02-16 09:53:26', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1130, 2, '通过', '2', 'bpm_process_instance_result', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2022-02-16 09:53:31', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1131, 3, '不通过', '3', 'bpm_process_instance_result', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2022-02-16 09:53:38', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1132, 4, '已取消', '4', 'bpm_process_instance_result', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2022-02-16 09:53:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1127, 1, '审批中', '1', 'bpm_process_instance_status', 0, 'default', '', '流程实例的状态 - 进行中', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1128, 2, '审批通过', '2', 'bpm_process_instance_status', 0, 'success', '', '流程实例的状态 - 已完成', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1129, 1, '审批中', '1', 'bpm_task_status', 0, 'primary', '', '流程实例的结果 - 处理中', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1130, 2, '审批通过', '2', 'bpm_task_status', 0, 'success', '', '流程实例的结果 - 通过', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1131, 3, '审批不通过', '3', 'bpm_task_status', 0, 'danger', '', '流程实例的结果 - 不通过', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1132, 4, '已取消', '4', 'bpm_task_status', 0, 'info', '', '流程实例的结果 - 撤销', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1133, 10, '流程表单', '10', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 流程表单', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1134, 20, '业务表单', '20', 'bpm_model_form_type', 0, '', '', '流程的表单类型 - 业务表单', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1135, 10, '角色', '10', 'bpm_task_assign_rule_type', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2022-02-16 20:06:14', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_assign_rule_type', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2022-02-16 20:05:28', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_assign_rule_type', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2022-02-16 20:05:31', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1138, 30, '用户', '30', 'bpm_task_assign_rule_type', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2022-02-16 20:05:50', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1139, 40, '用户组', '40', 'bpm_task_assign_rule_type', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2022-02-16 20:05:57', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1140, 50, '自定义脚本', '50', 'bpm_task_assign_rule_type', 0, 'danger', '', '任务分配规则的类型 - 自定义脚本', '103', '2022-01-12 23:34:43', '1', '2022-02-16 20:06:01', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1141, 22, '岗位', '22', 'bpm_task_assign_rule_type', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2022-02-16 20:05:39', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1142, 10, '流程发起人', '10', 'bpm_task_assign_script', 0, '', '', '任务分配自定义脚本 - 流程发起人', '103', '2022-01-15 00:10:57', '103', '2022-01-15 21:24:10', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1143, 20, '流程发起人的一级领导', '20', 'bpm_task_assign_script', 0, '', '', '任务分配自定义脚本 - 流程发起人的一级领导', '103', '2022-01-15 21:24:31', '103', '2022-01-15 21:24:31', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1144, 21, '流程发起人的二级领导', '21', 'bpm_task_assign_script', 0, '', '', '任务分配自定义脚本 - 流程发起人的二级领导', '103', '2022-01-15 21:24:46', '103', '2022-01-15 21:24:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1135, 10, '角色', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 角色', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1136, 20, '部门的成员', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的成员', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1137, 21, '部门的负责人', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '任务分配规则的类型 - 部门的负责人', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1138, 30, '用户', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '任务分配规则的类型 - 用户', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1139, 40, '用户组', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '任务分配规则的类型 - 用户组', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1140, 60, '流程表达式', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '任务分配规则的类型 - 流程表达式', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1141, 22, '岗位', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '任务分配规则的类型 - 岗位', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1145, 1, '管理后台', '1', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 管理后台', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1146, 2, '用户 APP', '2', 'infra_codegen_scene', 0, '', '', '代码生成的场景枚举 - 用户 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1150, 1, '数据库', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', b'0'); @@ -1246,7 +1241,18 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1505, 71, '采购入库(作废)', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1506, 80, '采购退货出库', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1507, 81, '采购退货出库(作废)', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1508, 3, 'CRM', '3', 'bpm_model_category', 0, 'success', '', '', '1', '2024-02-24 07:58:38', '1', '2024-02-24 07:58:44', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1509, 3, '审批不通过', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1510, 4, '已取消', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1511, 5, '已退回', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1526, 1, 'Java 类', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1527, 2, '表达式', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1528, 3, '代理表达式', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', b'0'); COMMIT; -- ---------------------------- @@ -1267,7 +1273,7 @@ CREATE TABLE `system_dict_type` ( `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 613 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; +) ENGINE = InnoDB AUTO_INCREMENT = 616 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; -- ---------------------------- -- Records of system_dict_type @@ -1296,12 +1302,10 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (131, '支付回调状态', 'pay_notify_status', 0, '支付回调状态(包括退款回调)', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (132, '支付订单状态', 'pay_order_status', 0, '支付订单状态', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (134, '退款订单状态', 'pay_refund_status', 0, '退款订单状态', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', b'0', NULL); -INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (138, '流程分类', 'bpm_model_category', 0, '流程分类', '1', '2022-01-02 08:40:45', '1', '2022-01-02 08:40:45', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (139, '流程实例的状态', 'bpm_process_instance_status', 0, '流程实例的状态', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', b'0', NULL); -INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (140, '流程实例的结果', 'bpm_process_instance_result', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2022-01-07 23:48:10', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (140, '流程实例的结果', 'bpm_task_status', 0, '流程实例的结果', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (141, '流程的表单类型', 'bpm_model_form_type', 0, '流程的表单类型', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', b'0', NULL); -INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (142, '任务分配规则的类型', 'bpm_task_assign_rule_type', 0, '任务分配规则的类型', '103', '2022-01-12 23:21:04', '103', '2022-01-12 15:46:10', b'0', NULL); -INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (143, '任务分配自定义脚本', 'bpm_task_assign_script', 0, '任务分配自定义脚本', '103', '2022-01-15 00:10:35', '103', '2022-01-15 00:10:35', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (142, '任务分配规则的类型', 'bpm_task_candidate_strategy', 0, 'BPM 任务的候选人的策略', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (144, '代码生成的场景枚举', 'infra_codegen_scene', 0, '代码生成的场景枚举', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (145, '角色类型', 'system_role_type', 0, '角色类型', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (146, '文件存储器', 'infra_file_storage', 0, '文件存储器', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', b'0', NULL); @@ -1356,6 +1360,8 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (610, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (611, 'ERP 库存明细的业务类型', 'erp_stock_record_biz_type', 0, 'ERP 库存明细的业务类型', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (612, 'ERP 审批状态', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', b'0', '1970-01-01 00:00:00'); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', b'0', '1970-01-01 00:00:00'); COMMIT; -- ---------------------------- @@ -1404,7 +1410,7 @@ CREATE TABLE `system_login_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 3023 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; +) ENGINE = InnoDB AUTO_INCREMENT = 3031 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; -- ---------------------------- -- Records of system_login_log @@ -1534,7 +1540,7 @@ CREATE TABLE `system_menu` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2712 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; +) ENGINE = InnoDB AUTO_INCREMENT = 2736 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; -- ---------------------------- -- Records of system_menu @@ -1696,25 +1702,25 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1178, '支付订单导出', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1185, '工作流程', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1186, '流程管理', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1187, '流程表单', '', 2, 0, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2024-02-29 12:36:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1187, '流程表单', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1188, '表单查询', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1189, '表单创建', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1190, '表单更新', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1191, '表单删除', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1192, '表单导出', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1193, '流程模型', '', 2, 5, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, b'1', b'1', b'1', '1', '2021-12-31 23:24:58', '1', '2024-02-29 12:36:53', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1193, '流程模型', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, b'1', b'1', b'1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1194, '模型查询', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1195, '模型创建', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1196, '模型导入', 'bpm:model:import', 3, 3, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:01:35', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1197, '模型更新', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1198, '模型删除', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1199, '模型发布', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1200, '任务管理', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-01-07 23:51:48', '1', '2024-02-29 12:37:07', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, '我的流程', '', 2, 0, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstance', 0, b'1', b'1', b'1', '', '2022-01-07 15:53:44', '1', '2024-02-29 12:37:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1200, '审批中心', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1201, '我的流程', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, b'1', b'1', b'1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1202, '流程实例的查询', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1207, '待办任务', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, b'1', b'1', b'1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1208, '已办任务', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, b'1', b'1', b'1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1209, '用户分组', '', 2, 2, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '1', '2024-02-29 12:36:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1209, '用户分组', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1210, '用户组查询', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1211, '用户组创建', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1212, '用户组更新', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', b'0'); @@ -2304,6 +2310,29 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', '', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-03-09 16:43:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2713, '抄送我的', '', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, b'1', b'1', b'1', '1', '2024-03-17 21:50:23', '1', '2024-03-17 22:12:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2717, '分类更新', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2718, '分类删除', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2720, '发起流程', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, b'1', b'0', b'1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2721, '流程实例', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, b'1', b'1', b'1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2722, '流程实例的查询(管理员)', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2723, '流程实例的取消(管理员)', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2724, '流程任务', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, b'1', b'1', b'1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2725, '流程任务的查询(管理员)', 'bpm:task:mananger-query', 3, 1, 2724, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-03-22 08:43:49', '1', '2024-03-22 08:43:49', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2726, '流程监听器', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2727, '流程监听器查询', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2728, '流程监听器创建', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2729, '流程监听器更新', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2730, '流程监听器删除', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2731, '流程表达式', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2732, '流程表达式查询', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); COMMIT; -- ---------------------------- @@ -2424,7 +2453,7 @@ CREATE TABLE `system_oauth2_access_token` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_access_token`(`access_token` ASC) USING BTREE, INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 5237 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 6042 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; -- ---------------------------- -- Records of system_oauth2_access_token @@ -2546,7 +2575,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1410 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 1415 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; -- ---------------------------- -- Records of system_oauth2_refresh_token @@ -2586,7 +2615,7 @@ CREATE TABLE `system_operate_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 10705 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录'; +) ENGINE = InnoDB AUTO_INCREMENT = 11782 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录'; -- ---------------------------- -- Records of system_operate_log @@ -4805,7 +4834,7 @@ CREATE TABLE `system_sms_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 610 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 911 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; -- ---------------------------- -- Records of system_sms_log @@ -4986,7 +5015,7 @@ CREATE TABLE `system_tenant_package` ( `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '套餐名', `status` tinyint NOT NULL DEFAULT 0 COMMENT '租户状态(0正常 1停用)', `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '备注', - `menu_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联的菜单编号', + `menu_ids` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '关联的菜单编号', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', @@ -5017,7 +5046,7 @@ CREATE TABLE `system_user_post` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 118 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户岗位表'; +) ENGINE = InnoDB AUTO_INCREMENT = 119 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户岗位表'; -- ---------------------------- -- Records of system_user_post @@ -5025,10 +5054,10 @@ CREATE TABLE `system_user_post` ( BEGIN; INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); -INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 114, 3, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', b'0', 1); INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', b'0', 1); INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', b'0', 1); INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', b'0', 1); +INSERT INTO `system_user_post` (`id`, `user_id`, `post_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 114, 1, '1', '2024-03-15 19:48:11', '1', '2024-03-15 19:48:11', b'0', 1); COMMIT; -- ---------------------------- @@ -5046,7 +5075,7 @@ CREATE TABLE `system_user_role` ( `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 35 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; +) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表'; -- ---------------------------- -- Records of system_user_role @@ -5073,7 +5102,6 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (24, 120, 115, '1', '2022-12-30 11:33:42', '1', '2022-12-30 11:33:42', b'0', 126); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (25, 121, 116, '1', '2022-12-30 11:33:49', '1', '2022-12-30 11:33:49', b'0', 127); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (26, 122, 118, '1', '2022-12-30 11:47:53', '1', '2022-12-30 11:47:53', b'0', 129); -INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (27, 112, 101, '1', '2023-02-09 23:18:51', '1', '2023-02-09 23:18:51', b'0', 1); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (28, 123, 136, '1', '2023-03-05 21:23:35', '1', '2023-03-05 21:23:35', b'0', 147); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (29, 124, 137, '1', '2023-03-05 21:42:27', '1', '2023-03-05 21:42:27', b'0', 148); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (30, 125, 138, '1', '2023-03-05 21:59:03', '1', '2023-03-05 21:59:03', b'0', 149); @@ -5081,6 +5109,8 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (32, 126, 140, '1', '2023-12-02 23:35:05', '1', '2023-12-02 23:35:05', b'0', 151); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (33, 127, 141, '1', '2023-12-30 11:43:17', '1', '2023-12-30 11:43:17', b'0', 152); INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (34, 128, 143, '1', '2024-02-27 21:58:25', '1', '2024-02-27 21:58:25', b'0', 153); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', b'0', 1); +INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', b'0', 1); COMMIT; -- ---------------------------- @@ -5116,22 +5146,22 @@ CREATE TABLE `system_users` ( -- Records of system_users -- ---------------------------- BEGIN; -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-03-01 09:37:59', 'admin', '2021-01-05 17:03:47', NULL, '2024-03-01 09:37:59', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-03-15 19:32:26', 'admin', '2021-01-05 17:03:47', NULL, '2024-03-15 19:32:26', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-07-08 01:26:27', '', '2021-01-13 23:50:35', NULL, '2022-07-08 01:26:27', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$osUERr6VErPvY3mGUh40Teb06H2pJiFuGaWFLRku82pdU713WTGFS', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-02-29 22:40:00', '', '2021-01-21 02:13:53', NULL, '2024-02-29 22:40:00', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '小王', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-09-25 22:47:33', '1', '2022-02-22 00:56:14', NULL, '2022-09-25 22:47:33', b'0', 121); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '测试用户', NULL, NULL, '[]', '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2023-12-30 11:42:17', b'0', 121); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 'newobject', '$2a$10$3alwklxqfq8/hKoW6oUV0OJp0IdQpBDauLy4633SpUjrRsStl6kMa', '新对象', NULL, 100, '[]', '', '', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-02-10 13:48:13', '1', '2022-02-23 19:08:03', NULL, '2023-02-10 13:48:13', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '新对象', NULL, 100, '[]', '', '15601691235', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2024-03-16 23:11:38', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', b'0', 122); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[3]', '', '', 0, '', 0, '127.0.0.1', '2022-03-19 22:15:43', '1', '2022-03-19 21:50:58', NULL, '2022-03-19 22:15:43', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$10$/WCwGHu1eq0wOVDd/u8HweJ0gJCHyLS6T7ndCqI8UXZAQom1etk2e', '1', '11', 101, '[]', '', '', 1, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2022-06-22 13:34:58', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[1]', '', '15601691236', 1, '', 0, '127.0.0.1', '2022-03-19 22:15:43', '1', '2022-03-19 21:50:58', '1', '2024-03-15 19:48:11', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$10$/WCwGHu1eq0wOVDd/u8HweJ0gJCHyLS6T7ndCqI8UXZAQom1etk2e', '1', '11', 101, '[]', '', '15601691238', 1, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-03-15 19:48:22', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (116, '15601691302', '$2a$10$L5C4S0U6adBWMvFv1Wwl4.DI/NwYS3WIfLj5Q.Naqr5II8CmqsDZ6', '小豆', NULL, NULL, NULL, '', '', 0, '', 0, '', NULL, '1', '2022-05-17 10:07:10', '1', '2022-05-17 10:07:10', b'0', 124); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', b'0', 1); -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '', 2, '', 0, '', NULL, '1', '2022-07-09 17:44:43', '1', '2023-12-05 19:33:20', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 2, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', NULL, '2024-03-17 09:10:27', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (126, 'tudou123', '$2a$04$lecJZ/CqgknEp7mDV2d4ou0beyj1GbM3.nVEZe//8WgQpR.JBgnAu', '土豆', NULL, NULL, NULL, '', '', 0, '', 0, '', NULL, '1', '2023-12-02 23:35:05', '1', '2023-12-02 23:35:05', b'0', 151); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (127, 'admin2024', '$2a$04$cHdZ7N6AUKysa2XTUG/J/egYtAzdwtpnNpcMVHDrupt1dyn4teOku', '土豆', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:43:28', '1', '2023-12-30 11:43:17', NULL, '2023-12-30 11:43:28', b'0', 152); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (128, 'xiaoming', '$2a$04$BRinw4an9PBGvx6K7GLNre6rWU0.1HMYHkQCN6Oir74zNFKkNKRzm', 'xiaoming', NULL, NULL, NULL, '', '15601691301', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-02-29 23:48:33', '1', '2024-02-27 21:58:25', NULL, '2024-02-29 23:48:33', b'0', 153); diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java index 444f7856ed..bd931e2137 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java @@ -35,7 +35,7 @@ public class BannerApplicationRunner implements ApplicationRunner { System.out.println("[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]"); } // 工作流 - if (isNotPresent("cn.iocoder.yudao.framework.flowable.config.YudaoFlowableConfiguration")) { + if (isNotPresent("cn.iocoder.yudao.module.bpm.framework.flowable.config.BpmFlowableConfiguration")) { System.out.println("[工作流模块 yudao-module-bpm - 已禁用][参考 https://doc.iocoder.cn/bpm/ 开启]"); } // 商城系统 From cc27652f86686e71362d4c5c69ea8aefb2770c5e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 24 Mar 2024 10:43:37 +0800 Subject: [PATCH 28/33] =?UTF-8?q?=E6=9C=80=E6=96=B0=E8=8F=9C=E5=8D=95=20SQ?= =?UTF-8?q?L=20=E7=9A=84=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- yudao-server/pom.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 1b5fc92c15..3a66524bc1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - yudao-module-bpm + diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index e5b816b9b2..bc850b5902 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - cn.iocoder.boot - yudao-module-bpm-biz - ${revision} - + + + + + From 3b8dee4963df6ddaa11baa11a8dbcd01cb298f2f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 26 Mar 2024 08:38:59 +0800 Subject: [PATCH 29/33] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tatustEnum.java => BpmTaskStatusEnum.java} | 2 +- .../admin/task/BpmTaskController.java | 2 +- .../bpm/dal/dataobject/oa/BpmOALeaveDO.java | 4 +-- .../candidate/BpmTaskCandidateInvoker.java | 2 ++ .../bpm/service/oa/BpmOALeaveServiceImpl.java | 4 +-- .../bpm/service/task/BpmTaskServiceImpl.java | 36 +++++++++---------- .../module/crm/util/CrmAuditStatusUtils.java | 8 ++--- .../controller/admin/auth/AuthController.java | 2 +- 8 files changed, 31 insertions(+), 29 deletions(-) rename yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/{BpmTaskStatustEnum.java => BpmTaskStatusEnum.java} (98%) 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/BpmTaskStatusEnum.java similarity index 98% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatustEnum.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskStatusEnum.java index eb4af0f623..40a385a582 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/BpmTaskStatusEnum.java @@ -11,7 +11,7 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum BpmTaskStatustEnum { +public enum BpmTaskStatusEnum { RUNNING(1, "审批中"), APPROVE(2, "审批通过"), 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 7d72a133bd..70eb0f5e3d 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 @@ -93,7 +93,7 @@ public class BpmTaskController { @GetMapping("manager-page") @Operation(summary = "获取全部任务的分页", description = "用于【流程任务】菜单") @PreAuthorize("@ss.hasPermission('bpm:task:mananger-query')") - public CommonResult> getDoneTaskPage(@Valid BpmTaskPageReqVO pageVO) { + public CommonResult> getTaskManagerPage(@Valid BpmTaskPageReqVO pageVO) { PageResult pageResult = taskService.getTaskPage(getLoginUserId(), pageVO); if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty()); 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 ff63f8e43b..6c5b648dac 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.BpmTaskStatustEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -57,7 +57,7 @@ public class BpmOALeaveDO extends BaseDO { /** * 审批结果 * - * 枚举 {@link BpmTaskStatustEnum} + * 枚举 {@link BpmTaskStatusEnum} * 考虑到简单,所以直接复用了 BpmProcessInstanceStatusEnum 枚举,也可以自己定义一个枚举哈 */ private Integer status; 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 7bad358070..c0c7ca0d9d 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,6 +4,7 @@ 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.datapermission.core.annotation.DataPermission; 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.system.api.user.AdminUserApi; @@ -77,6 +78,7 @@ public class BpmTaskCandidateInvoker { * @param execution 执行任务 * @return 用户编号集合 */ + @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到候选人 public Set calculateUsers(DelegateExecution execution) { Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement()); String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement()); 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 9a84f676a8..53e2759142 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.BpmOALeaveCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; 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 cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -48,7 +48,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService { // 插入 OA 请假单 long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays(); BpmOALeaveDO leave = BeanUtils.toBean(createReqVO, BpmOALeaveDO.class) - .setUserId(userId).setDay(day).setStatus(BpmTaskStatustEnum.RUNNING.getStatus()); + .setUserId(userId).setDay(day).setStatus(BpmTaskStatusEnum.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 7afed756b8..176d38a0d3 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 @@ -17,7 +17,7 @@ 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.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.enums.task.BpmTaskStatusEnum; 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; @@ -202,7 +202,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 情况三:审批普通的任务。大多数情况下,都是这样 // 3.1 更新 task 状态、原因 - updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus(), reqVO.getReason()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); // 3.2 添加评论 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); @@ -230,14 +230,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { // 更新父 task 状态 + 原因 - updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVING.getStatus(), reqVO.getReason()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVING.getStatus(), reqVO.getReason()); // 2. 激活子任务 List childrenTaskList = getTaskListByParentTaskId(task.getId()); for (Task childrenTask : childrenTaskList) { taskService.resolveTask(childrenTask.getId()); // 更新子 task 状态 - updateTaskStatus(childrenTask.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); + updateTaskStatus(childrenTask.getId(), BpmTaskStatusEnum.RUNNING.getStatus()); } } @@ -261,7 +261,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 1.2 只处理加签的父任务 Task parentTask = validateTaskExist(parentTaskId); String scopeType = parentTask.getScopeType(); - if (BpmTaskSignTypeEnum.of(scopeType) == null){ + if (BpmTaskSignTypeEnum.of(scopeType) == null) { return; } @@ -275,17 +275,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批 taskService.resolveTask(parentTaskId); // 3.1.2 更新流程任务 status - updateTaskStatus(parentTaskId, BpmTaskStatustEnum.RUNNING.getStatus()); + updateTaskStatus(parentTaskId, BpmTaskStatusEnum.RUNNING.getStatus()); // 3.2 情况二:处理向【向后】加签 } 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())) { + if (ObjectUtil.notEqual(status, BpmTaskStatusEnum.APPROVING.getStatus())) { return; } // 3.2.2 完成自己(因为它已经没有子任务,所以也可以完成) - updateTaskStatus(parentTaskId, BpmTaskStatustEnum.APPROVE.getStatus()); + updateTaskStatus(parentTaskId, BpmTaskStatusEnum.APPROVE.getStatus()); taskService.complete(parentTaskId); } @@ -311,7 +311,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee taskService.resolveTask(task.getId()); // 2.2 更新 task 状态 + 原因 - updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus(), reqVO.getReason()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus(), reqVO.getReason()); } @Override @@ -326,7 +326,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 2.1 更新流程实例为不通过 - updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.REJECT.getStatus(), reqVO.getReason()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.REJECT.getStatus(), reqVO.getReason()); // 2.2 添加评论 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); @@ -378,7 +378,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status); return; } - updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus()); + updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus()); } @Override @@ -392,11 +392,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 更新 task 状态 + 原因 Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS); - if (BpmTaskStatustEnum.isEndStatus(status)) { + if (BpmTaskStatusEnum.isEndStatus(status)) { log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status); return; } - updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason()); + updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason()); // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 } @@ -525,7 +525,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { 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()); + updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RETURN.getStatus(), reqVO.getReason()); }); // 3. 执行驳回 @@ -562,7 +562,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString()); // 3.3 更新 task 状态。 // 为什么不更新原因?因为原因目前主要给审批通过、不通过时使用 - updateTaskStatus(taskId, BpmTaskStatustEnum.DELEGATE.getStatus()); + updateTaskStatus(taskId, BpmTaskStatusEnum.DELEGATE.getStatus()); } @Override @@ -616,7 +616,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.saveTask(taskEntity); // 2.6 更新 task 状态为 WAIT,只有在向前加签的时候 if (reqVO.getType().equals(BpmTaskSignTypeEnum.BEFORE.getType())) { - updateTaskStatus(taskEntity.getId(), BpmTaskStatustEnum.WAIT.getStatus()); + updateTaskStatus(taskEntity.getId(), BpmTaskStatusEnum.WAIT.getStatus()); } // 3. 创建加签任务 @@ -703,7 +703,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3. 向后前签,设置子任务的状态为 WAIT,因为需要等父任务审批完 if (BpmTaskSignTypeEnum.AFTER.getType().equals(parentTask.getScopeType())) { - updateTaskStatus(task.getId(), BpmTaskStatustEnum.WAIT.getStatus()); + updateTaskStatus(task.getId(), BpmTaskStatusEnum.WAIT.getStatus()); } } @@ -727,7 +727,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { childTaskList.add(task); // 2.2 更新子任务为已取消 String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname()); - childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatustEnum.CANCEL.getStatus(), cancelReason)); + childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), cancelReason)); // 2.2 删除任务和所有子任务 taskService.deleteTasks(convertList(childTaskList, Task::getId)); 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 43e681c5e7..c1d4eaab7c 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.BpmTaskStatustEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; 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 = 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; + Integer auditStatus = BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() + : BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() + : BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult) ? BpmTaskStatusEnum.CANCEL.getStatus() : null; Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); return auditStatus; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index 241cff87e2..f24db16a92 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -99,7 +99,7 @@ public class AuthController { // 1.1 获得用户信息 AdminUserDO user = userService.getUser(getLoginUserId()); if (user == null) { - return null; + return success(null); } // 1.2 获得角色列表 From 62de6c36bc5fdd51968b0f0f4753fcbdf5bf6712 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 27 Mar 2024 19:42:08 +0800 Subject: [PATCH 30/33] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- yudao-module-bpm/yudao-module-bpm-biz/pom.xml | 1 + .../expression/BpmTaskAssignLeaderExpression.java | 7 +++++++ .../expression/BpmTaskAssignStartUserExpression.java | 9 ++++++++- .../flowable/core/listener/BpmTaskEventListener.java | 2 +- .../demo/task/DemoDelegateClassTaskListener.java | 2 -- .../demo/task/DemoSpringExpressionTaskListener.java | 2 ++ .../module/bpm/service/task/BpmTaskServiceImpl.java | 2 +- 8 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 3a66524bc1..1b5fc92c15 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - + yudao-module-bpm diff --git a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml index 1ac423e11c..4ba9929e71 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml @@ -69,6 +69,7 @@ cn.iocoder.boot yudao-spring-boot-starter-excel + org.flowable 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 0200dbace3..7c1950f8ce 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,6 +34,13 @@ public class BpmTaskAssignLeaderExpression { @Resource private BpmProcessInstanceService processInstanceService; + /** + * 计算审批的候选人 + * + * @param execution 流程执行实体 + * @param level 指定级别 + * @return 指定级别的领导 + */ public Set calculateUsers(DelegateExecution execution, int level) { Assert.isTrue(level > 0, "level 必须大于 0"); // 获得发起人 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 4df9eb1a56..ac243c0f43 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,6 +4,7 @@ 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.impl.persistence.entity.ExecutionEntityImpl; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Component; @@ -20,7 +21,13 @@ public class BpmTaskAssignStartUserExpression { @Resource private BpmProcessInstanceService processInstanceService; - public Set calculateUsers(org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl execution) { + /** + * 计算审批的候选人 + * + * @param execution 流程执行实体 + * @return 发起人 + */ + public Set calculateUsers(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/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 a8f1788f34..733cc2b41b 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 @@ -20,7 +20,7 @@ import java.util.List; import java.util.Set; /** - * 监听 {@link org.flowable.task.api.Task} 的开始与完成 + * 监听 {@link Task} 的开始与完成 * * @author jason */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java index 136c33efc0..dee2b95870 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoDelegateClassTaskListener.java @@ -3,14 +3,12 @@ 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 DemoDelegateClassTaskListener implements TaskListener { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java index df13797107..0917abd573 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/demo/task/DemoSpringExpressionTaskListener.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.demo.task; import lombok.extern.slf4j.Slf4j; import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; /** * 类型为 expression 的 TaskListener 监听器示例 @@ -9,6 +10,7 @@ import org.flowable.task.service.delegate.DelegateTask; * @author 芋道源码 */ @Slf4j +@Component public class DemoSpringExpressionTaskListener { public void notify(DelegateTask delegateTask) { 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 176d38a0d3..daf0cb7418 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 @@ -728,7 +728,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.2 更新子任务为已取消 String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname()); childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), cancelReason)); - // 2.2 删除任务和所有子任务 + // 2.3 删除任务和所有子任务 taskService.deleteTasks(convertList(childTaskList, Task::getId)); // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 From aea8fb7fc61fdfcd87c23f24e76af374f8edf370 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 27 Mar 2024 19:49:06 +0800 Subject: [PATCH 31/33] =?UTF-8?q?BPM=EF=BC=9A=E5=AE=8C=E5=96=84=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1b5fc92c15..3a66524bc1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - yudao-module-bpm + From ec1ce2f358ec47777743fca1dea25765ede7e7c1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 27 Mar 2024 21:05:13 +0800 Subject: [PATCH 32/33] =?UTF-8?q?README=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=9B=BE=EF=BC=8C=E6=96=B9=E4=BE=BF=E7=90=86?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .image/common/bpm-feature.png | Bin 0 -> 16260 bytes .image/common/infra-feature.png | Bin 0 -> 16920 bytes .image/common/system-feature.png | Bin 0 -> 13584 bytes README.md | 6 ++++++ 4 files changed, 6 insertions(+) create mode 100644 .image/common/bpm-feature.png create mode 100644 .image/common/infra-feature.png create mode 100644 .image/common/system-feature.png diff --git a/.image/common/bpm-feature.png b/.image/common/bpm-feature.png new file mode 100644 index 0000000000000000000000000000000000000000..23787fb4f090154f2d914100ca91174c1e60cafc GIT binary patch literal 16260 zcmaKTWmp_du}F7A2qsR$0x_XXa4N%@2#w^Y;J8G-JXw(jk+R1Rn^tK{e96fF;);r zR(7_Lv1xEfsH2mkrqKdmxXA8e7Nz?o;y- zv-cT8x6VJW@BO1X;E$!{9dQ7Fl#r6#Tb{qJ$o|w;%BEsvc z#m2%*LiH;@pLIXPMBp?1zmGg#Jo2ECCcKi(0yH9hf6XB6Ceb*UhVq;@DT7a}hO*(y zU$42zY!6pTgL$E2Ohp$HW1(aj(?*mqn*C-Fj>Eipf9)@#*;2p+GsrQLBWcop93L5rW;J%S&-vR(*cBO5K{AOtMx}`ocWj;N<1^v04%%NRbXZtLO|y%ZJY)@ znJ|B>WWICm983pI;(sYBqfEj;*_fS^t*!Npeae!MR{hS~1MNh_AE8ebF6gg3=L)bV z-Ok-I)VeeLrAy^q_wfaLGYO#S2-UnY@|o6~z4#>J6YKb36DM@hf@c<{m9Vm(>6*M~ za&fNC{b774(l$WU^t;XI4#aHT5s^sD@+c=U+JecDUEAjh9%yyI?`Ae}x0?>ipU^TV z=eJ*W-dck$leb@_M)jYDU*AK?{lo_%AIe z#UtqQ^&$>gr8d|5zczxaW5ev?BG$%Og%WaFt0sLJjwnI2lwKf(yaC_lZSwmBX8Ma= zrCaYTwe@!(#lMn3O{$`%GI*042l}oFUQ^xLq-oEBSlm`1C=6%l+k); zeTq)mz&6yNE~-j?judMdYR7ZJkQTr}tpf-N!AC#-%+}f^@3ES-69jucp+L=!_rDgD zSEaG-dmO|1PgM6)emj<1F8%w{K%P8xvU}OoouAQYr2ov1OgtAbyZHzMCo^8NSz|wo z_Gez|kE-3Ng)Kj3x_7$9ER?b;Q?VXCDl%B{9*mZuh5S2u2V4x%0EGlW8LdQyL*tj& zfwG?YVBEQw{|m4g_qQX9*tA0eJqL_?Q!y~Tc7UcwJZcq4RV@JRRF)&+s{!!U+H49` z@3)YPN8l=kQ-c9!N|w2-dVaZ#uNkPZ*ki-Ig?uvaWu?C|R_P-ffSIjA)_WQJpTy0u zCR3#f+HdLFxz1d5@#GK2<#lA>-x^3=Afz>WM1X0Y(%^0VK|sVhC6#lfC2#alFn>n4 zWzE0E_GQhSD;c=fP*BO~z3XVQzjB_B>Dxh=pO|0UBlOYbO`QXsYc3A(j*7aSvO2G@ z5$wbEGdV~E*X+gsF$=;hOWtdeC1zAC1Zxt)IM&3aYm#4wd4mSLvo?NA{>Z6;g8Ih> zD0u2nsIl505Y0;s%FfLyg#Hf}YlfhB_-6^44R?*OPt|Im^rv}f= zBN0%E2uVy5O@U%E^1616ZiTQ(=xesRY6G3I%d0m+7}A$ZN`7i*UjKxy6_$O;c8hc) zf+WEXT(+du;82WJ30?I_JJZ<-F_fR#BHf17d&_8>cGxR+fVMkhGzfKH;s{pSsX;AM zJv${MSpX9^J&PUR5Bm1O38!53b##}=+!q@L0HJvxXaZ!S3ykTl8GG2j4HNZ*( zw#Bl)X1H5G<3e~@MyR(6U3j6V0_Opz*MLY0qP7Xog;XR+p*ca- zWX<8g#k1S1Z;)68#JxzUABnvx<`eVn#5U`jin3%7Ct&0q-waseWu2DWc!$KWf^Uo$mMXfj;7C~h2pXB-=TKp`UBO9!mK&(_QbKr2QuEl z-M*wdj46=RyCieF4zVW7iX;y0H%ZfyFNF7}CeS=1n_48+=ZCJ_ruGmk-=DH>(Y)({ zkGe`shFZSk;+~B-x(|5?M1DbY!?#`dwq-lpn{y5|n`9@pu0yj033y{=AJPAq*qX9c`l2Hf5g%bjJroeoo4364iSHMV|}2yzyS5#-XHF<%0*`cmG``&fx%_y4rbOrF61CW%w7{IEtPS&6>us z&=38CIQ@T@$t}M_8R?VBy_^Y>ks_CWAtJ66_!!55n=J>To@DRQx)e3ZB`_A8nkhJR{wzMi!p=EDPr1?lkI6=L!q+sr11vE?Fjf+gGA86TpYcTz zTR|?B(3o8+=}DXv$w{t}vSAh-UDoneU&vdo!bO%dIsCg4t=zp@N!=-)6te7(7Q>0Z7m}70aar-#SYs$0t{3?AQ^HVGU1MG9~6X#KO>X zu2yL^T%|bHUqYZvrHN(v)ZG}1Zy0(C1Xyb7~y}PyhtD0j7>oOK|5x``l92v*r6dcZ}K2A z=P};|K57Z%COf46NaiOTXmE@>ye%B?dJjV=nP3&Lyu-#_Z3Xo!08^l4BfvE;=P8L&4O8owd>x7c;F z(71ObQU%;xDX!{`>l3^L2Dhf3V6P6$9DaS6b+IavuXO{12aM3{E$w-FR)fDRek5cf zAMma;rSLp6!3u>ZSFZ%v5W1CQ(0xFC_bwnfc=^c`uplC>RN_v3wm2KHr8JnqUBVfxl_+k8l-DbzJfVY?%#NesKG?u z-t;`SfcLicXKwz=>AjM{@{WbUa)wFUnkitSWjr-w;Wu-+$c=3;c)ql~hKQk)XA5+! zR4vyPAUFTFfPS88KEFhABFbH=wQx#?+HZ>6JJv!H|Db`N@#Zyq;QsTWVqQHqA5A^K zQWTN3@+8?uV#@~J;Dq$OpOa){ICIE8{pJ%-b5F!k7Z#wxs$X;So;}4i*V@&eYvcZK`F8d^69cVqEb*RYsbP6*T7&!BHq!tjG{HqImx{ z`IXO9x<$u$D7KnhXyo7~kDKj=C^6NjrmW(7S|0;)L1IK9AX9r-U)zxAZxf9WsR)yn z2hy_YPWKb$k=8ct4Ha5%3m`q#zy~4f9GP{QjquMVIG1n*jYxEQ$_{`SyJxfqDU&hO9plV#{M`?~Gx9G|iM6t_Po zzdi^0ERU~CANSsw({FbFzVIj-EORwiG$)o5niqukEi9V4DNT>jQAfzDCtWrPk`#o? z)C4jdU!QWVqi<^m^v2@BC%rXM9HAj#quVoy`aHhMosSq%sx<-L)GWGGO@Bcq{#-CTOhe zYeC{iT*NDT4kP>3+una>CQt*RTg=YhL{-bflUPl5PK_gc{uxV&xpI$TG2m%V<{`E# z=7`}dz}SbOW+_>4itlCa)&N2X`tmn7Ip^7;$HBX3;+jwiSE6q+u(8THW}u*hN@KP5 zQt3dZUH7V37~mJj$eVs11p+fVFa-x24dR;IkFsW;a0lB}Q#mOmpKk@VE~36QA|K8t z-`i=AOXVu(*33Z4UTmf7v5B6UCaAmJCDR7`KqLxv^*=y+(e3Hb2NLVz4em>T+2I`* zUJC*Xb%T#b1c&w$bGL%QKNv3rfm#1vpf%yIN&(-?=pQGlpmPdTQ`80NeL7>zM9Aq% znl++Ly!)kef%r9dt@EyP%xgs3Xy&aTvkGWt17dr_4$RUz`w^z?nQ9?Xbb1$jHqoFv z)9?onr0cs46_0Pt!bwykZi=iRA*Qjk7xbBEtk941HcFBQE6`bjBvsH~YxlWbsZY*)r8YC3$@_Cgn;g6DO4fkdj z;v`reT{b7;R`aJAwfY6u3+1XtEWjscc~b?n{?_Ex%~RJ5HDq{#a7*N&q$FB~#0*b0 z{K_916+!DKhMQ3TA^E{sCPakvFtYWD1FEVDC5=Dhk!D0hcv(5zP!7r8%YWY_U_{^| zuy52gNUDyYJ5;<1kZ8@$2w&0`vDS{05xOG-npX4)@m_hck}cG){QZ{CKleuuBplMA zPR#MH18}RzZALPL-E7qIoWfn@`j+{M<-7Ez=h0IU4+h2pe56o}@$uA}_1_Q$$W&$E@h3RgjrH4A8J!{&x2 zIn6HB$eX_sW}$1z72S!nYK|g?y&Di8Jl5Sz)NoJ*`I!(X!u)yq0OYdp+Sh)@ ztfKdi|Iy*RZ)12(&AhpVrZ=ZUlwE{pyNc?O6Wle@c1e*aFch{D@3%OL9}*wap`Ly& zbJs>8u2m{ls546`{_-U2(Ny~Rp&xvX#3*v(O}_jHq&tcbbzJz`;gSyIniS0u@?G|t z4isF5-PwOQDQKQn#XNrl3Pw0o90&%HL-r{IZeOjOCh~kH0Si4<>4TOz z(AzElzV6Iem9NRo*sQ$kSsZ0h7u(4nKvL)hI;P(Vb~ZR2?K)VcM$k1Z6c)Qd0&m*L z>*u~dZF({NJm4emSWP%#8*1EZt;dJ+GX4<{2hm!WhGL6M&Oo_qF|i^GDH0N0I1~!{ zh?JQs(x{W=%FiOP|J=wKKBaZ~sOOU5)njZHP)775f&}s;g2|t%svx=lbNW0b%1_sS zsgIvg^o|(!z#i#I2EpW`@Dn8^@Xz}a`oMen*F^6V1#ZuA@y5#JEZu-76Wcs>5OzHK zYDCyw2S*~nLcC!PEAxWcKr^afxGZ|wio!`)__pU*{rUt-8D@m2nWPUh+C6!BGg^bM z$`Jkz^BxU%)}vp^E}w*aMhGnrfM!NH_KuLI9AlL&IB9y@ATWjBx<-WEKnHybi_cmx zOoao8Dz=UEA(nF*gDaUD+D}K>XGYpvYNOR*(P+}JsvA6?WRbI)V#S;JV;IoQW;0^p zOu}l$Bf@WrG(P}e6c22MBPihbDej!j^s`>7-nfdM+nGC zLaaKeUdiFLMk!8R<4Cmz1bWl0m`a;9wHUb6@(08uG+I(jN2zD@K~U*I ztfmioTL&^SD1yKl`gn|r8PZ)dn7v-*S)Y8)Zf}!-J7@DP8qH&HaJ(h$GvGznCwYEO zl|GWe!!q|womj7V$B;`MX_dpAQsjlVQ<|yQfP41QPlBKBZ_m%)wO6OaJ^q@;JQHj| z2I$QI&TetO-8o?_(?+>J9~>$M=oyP8lS9?GQte~4) zg;QF??}?{F3KsWJx zf^T-8djdOD4s91D(*KO5<|1fhJ0qFX#zsK1@5u~LK)R$SAO|5$bAyo0Q;}@x_Q!Lq z9=pxc;5Od{&F2vtq7T%uf@y0EQ91mS-B@pZ7zrw+MDZeV5L~)HfC0t9&o$4$Y-O{ zZ>_8>Rlkyl_;X@kqV1yFVR{{kw!6@9d5)O1M{d6e8dwd)|L1$W=#dz^qpX4LiuBFP@8)hBF>kC067{>KB$dz_Ny`u+vDJF)eX(WRHs(@%3BqtHFyAIs;Y*t${Rr z#rL+h;m$oMEBD&@iQyulfHK3<7>8e%+fV^)sFzUI=M6AtCP9NET;(e@8~P&d-)MAw zN2b0;4$HS@HI%F0XZ8Pl6>pF1BO`v!#Ty|;;&?46ep%O7=jolI;{V}qCM?_pRIt0j z@IHU0j_ut-Qh7&7^hya!#XPxOEZMSSRU}=IO?|s72r;$=YbH+m;71*A zQ!@I+KbxJu1=7nDmg0Fiv*V?t%Z_^Zi1_ES5V{$z}Cu z3erI(60%^|bl|5&vaf4cmr$o!_X6n7>a!~W(?_6w(VgK7%oMt9ViXfV_e54-wp`m> z%^psV($XFJSl>35HXh?Tok-ub&k*&sU)lxO+T?=(tQ{Z<$xFZsK7A`+seT z)iPlmx(;ZtGqsW8dSnv#ly^vmOp7ge+YI~>F%@rId8m|N&nBs>VI9-JdRL?!2OavQ zt5v)2HknBi_25Ns<-Y6AqJfZL|NX@>ys~=fiV_m4$!=r_{--{Tbtr}?iUCTJ@!l?Rpi9TKZtc=x*@jT)r0k2vW91pPt_eM}!C6 ztyVsy%2_IRk~Y zw_Et$u0YXF$4wK@YWftvf1fC4#Y)Z57(jyw{mFb+sn$zr#0=!h>1=tS<_SkT{!D%(}MB{Uw>xeWot#tIo1 zq~OtYJ-<4)Lct&nM6!%GTm`|rFvZ@;(viINc9@xUE*Z(o|0GG+xZqRBqC1xV*n8%J zJx!fVRgx(GM!=9FE6%7t=+G0V7T(Ve#M8P!WUwdrTg05mf{5%QlYg`@d)~z!Y%6=L z2y7-JgYBB{|A6-x;W#|66+ZZbn7t708p-~kz7zeI3=7)XFwLYkDXhM=P%w+9&kvdp z|4waY#Hga?br$l5&Nz{=TDn$ue-NpEO;Hlt7A-D^CsI!AeKEmV_TAVIku&kW9Pn{t z&;<-Z!y9}r1#jktG%&NbfPMOgD4>X--E@Xx8XuFAZ;e@ zYB6w=i4pSa6WK>2%mrmTN*}2lnu?PO2o=N2mJAC`Bs>f!n*o^@=YwZ3SB={H z;1*w^H<*%|0GL=ggugH3vS5UoUZX_QKR<%@XDl8AoZ9)}>eJs~(nG8(N#2u94>0i9 zksBNt4!^lrRoaxb^+uc{?~Us$>d+ZO$|9$}pE2*!MNeMKOPMf8@f*M|< zGgbWoLX{839po+TPAM+@DbfQgiO9MW%Fp*OurBB{5DB@w%H9P(40dL%RkeL5_@PR= zZqs~t-X|aBDckG^votuIt$l$;qx6RS;~rovVWENXW+2WTcs&(}C6B|%=`wrN%`6r6C()h>p2_%&?C;>p%6Gg2Q zm}+6gMbfFurx*x7FM=p1tIZWHoIr zAjpvgC5^vAyEy@|LF%pA?=J-lL;&t?6y?C1H~jh!LpuSNO|q?>o#CD(1P z!Uo>zNm^-6!Sr=fbNj51BJLD#9h1;D6j>Nx^Nk?#kJT8fYcmZ$zxshb-_H)mtNbWpVmi|t$|2v`K8A7jY#6NZM? zCa#JX1m7ZGIC~kbVn(pUUs)zNXW_D3JXr}(rE~Ekhz)rzywq5`dvE{A5WJJk!!|9{ z0yP|NuP%d*>3svA!NKjtjYsV!ex?uZ?fGZZaOPz}T?>$)ug0>w9T)zZBFEAou2^bB z#=#hc2X2Z*lqyStCK|v0b6xSL@o8Ikx@woFvaD>uod@dRLZduV=uC3;&>|WXetrAS z)B{vSxxn1UY=Fvh^R@?x%*qCe6pn4NC#ND~B>zmyKfxt_DgwFIH+#2$BJU^{8eDnW z29}@rJK#^41G&9mY)|^{WAdoeZON2*r}v&O`qKRdTp3=}&suuR7L85|_PMeP!i%x$ zmZa#{41B~TOx8q`(~#?U^VEKl^(J&3>x#)~D&ta}JRJ0EpL~?};YZV!X*}MbCjliN zohQ;ssx1tQ&#jtL5LUk2^|#*_LUD$El|F_C{ZdauNbG?392~C5rBTwwx`!PJl>xQj zy=qp2viYUy>D8iRmNb1`<15KudI&^x?(g64E(44COggzsok#DzK_34-!O@oYZ_xVZ zFS+o$zyuYZOZ`tT_vdwt%W0i ze&ITM3jRZ?a#dRl?!Tm7%u)W8@050h`&0_Fr|+SjaYxx^_E;ks~itYrbS8ypwY8YBgY~W zy01Vx z06zD5%y-+ZdRX7>%HlmRaHdBLu42K|x`~FwUb93c?_($a5Jk5Lb`e}#x=O7=hONGJ!oJnk3w&X>=W%a!g234>$+1(twVML#od{-P}2{_2rX7E$F}@2v+Y zB{w;2S;C)kw(TURqY(_CYY5U{=##|mBg2ugSeF-e3t5v_1T*B=YI9*S#K?lsxf!|- z>Ym95;fl%vgBrnmcjJhO!SKocggl>)tt{v+uTR^^8?wDLt~)d*iL(;~50YC`zTcN5 zB#BPJ+gm2l9|QXdq${T_ALxE^ZxlQPOLM~4T=*!7%@@u{1D}4}IMjI77Br^i47bDv7wQ*3!2)M%vvkqcKf4OPQV(H63WQyPmJz#_-C%v`6Z z)NfRfSoxW4++h<48oss=4t}6&|342w-$`DImA5G9Ebi~;){<~CwF9v~J78kE=`Njb z1g7GKrYI=QdC1&I;pO}NeXtbq&>y~AkO3onp1z{W?MCoTD!9VU;6FAkuHfQ1@uS3D z``Sdew1wxb6Nq2Kt8L@WxXpuJ_CT|DGgBAbb~oA-X%z@@ z&`KUWyg(jOhJk``U6r&*daAP6H_mTq*pn_Gb?Z;6493slF<7Ow78w z81$M>t#Y?HkI(v)%-cOtYciIm04;Bj2>TBqAel^!qS7v_0f@FRx!A2l0#1`puS59O zGOn|6OY1KGf+N8ET0^KPDB^PpK~U@%WMIv_aE)Gza4p6kea#43@^A7s-5&m-g)4Qv z7sDNNH(ID4{kFO%ml!^JB5Ui2^H2#EwTy%*Mu?6Vrn5wjK{}G8d0)v>c1b;(n&p+f zRseZ4H$LJZSTt9A&9Vkk5V(x)pbo*NcUYo=DeuBubz)y%68zqV+Kg*z*ntG33x4a+ zjk+-cBF47fJxemY(;qtaM|GEtVyR2&gskhmI(xpRRJKto>XL$h_5LQ;0RhU;b`83L)ehAa(sCh@#f=Wq8ODlncDpBFRQvX zl3&<{%^bV~)Kw?7qYgwwNk|}M=$&A+l9RFjAv)#U+Hqxv=gr*T8X<(AoiKcagP&ht zh{o6R?r!Qql`p6&NF?y$c6#e>l1?QF`9s1<*TtS3ZqaGWy<7$HHAPmx8xzy5>z$B4 z$NXbuWvS8|Bng}WJ)gB43L?0qGrj*%gysn&p;0r6ksNflv){eyUX-nMA<)<+TV(7% zkOjs6=*R|XKe0#E=PxbB9&eXbUC{j5Cwy4Tw=3oNS#uCqX&hyEdMaaT)cHLdJ0?OU zm)2yiJ#RE% z+1=rg>thGLp!pVvtVd!<8f7=IRApz+xQs}wKwc=Ms303YXO0;yJ|OgCTcS4=5sQ}Z z3e71#@e&4$S$tDzimu0rSj!WmBzUpjIud#u;o(Ml8e$d<0t>r`+Y5qKLHV_m_Ml8p z?$U4-4)z>NV(}!Te}YOon}G;Co*3_4ayU5IC@Y!=(1LIw`Uui_k+ojlLwPBEYT4jj zS*7zGtWenWRl-$RTEv($6TEHreNR-)au~Avp2L2HlE9zy2n5~T;ksq~gNRUUZU2QL z#6FjagZeu;dGjNphpn-byoBKnEu+K;hnie;4#>Llt_G+pGv#x#%6ifun_FnsC+ORi zp64#V!K<>g)Dy>5Q6%a%8($~&v zRvwW&D^SZg>9tyD-nxTg%CmT#uiZ(^hoDG;xE|#4@D)0SNw#+;?(>qqd|#JrsQXQk zXm%B39%P&{)Rzj1wb`T`Lc=jDf}MEZU&S>v#Uqi(Be*Fa=PNjgk595t)H8$9GXllUE;R$Z@&;r>@H3-3_ZZLhU0WW^RNE)I9ddLfiU7?s0YNS@a!%k zR>csD&Q3OQ16_)MC=DJj8KiW=XEHlK=O5SN2zCsa;e8J4&UE$9yAL;oJne8~&*8H5 zoC+nH5V?3or^%(E{?V=Za@;2ceJ!Udvu)~wNL|h~7z}e(>Bk%g;>GqWlrUzfl&pa% zSmaVvfD~{!E5HS=){7@#aT>!{M?nKyyjzzJe7b;~gI~lT){b?5y8aNMX(-iiH0@;q z7MpjQV`s=!nh%;V6)TWGxOBi4PFfrIZ;MLGWPO!E!}wkDRDhyL2?f2@c>QC3F&pE( zOy(&=HN$)7>XYRCI!#|c2?7E*&9wnzz4$BHDv|-i9B^YlNMduqJ-U{ z<`lNG9eWp{S;-QnaaVoJ&0=g%=7^|D8txfAsBHJ|%6chGz*zfSHrNwJbBX=Qm>8k> zDuM&&i?iyf3W%Xe6lD&`avALNP6eq>u7-dMp0O6hw>=ZkuilDpV&}$Mc`K%?tn^HW zfWg=S!}9W406V!(lvjVuwqT@=zYy+L6aDIHFB?#bw=qWr1_) z2CA{)FM0E+UODo;XX#JAZjaMBMAHvKBRqCCGd|RM(_!^Qs4yfG_ZtyAZP1VnIPa>8 z5hzgbIy3y28_)Q6V_^^4OHt=)l&EHE1;!OEJ_d!O_K(LmEy+bg+S-v%E4G}5b}U2@ z*!?2zgG{+bN)V8F1gPK8)~i^0X##xnSksNZQ9*4 zJOoAUmxwS`%t?zx2U5&fTX=rF%ybVWA`zgg(Ij^y)qa0w%!%>N20gggt!u-N!TX5V zlqHC{TK1)2X+e-Y=$j%Y0~du2Ibx@0(ISV9AcwDdr0|muAVqx;>)0~Ff1)MS0ARFh zBs(ceahBSq3=#k&F#|GPF1jZ#2kw8{1n)g{NJl3UI+tWvO#xews3NpbWp39@juHz7cN`vS(h(AtNmI_1djKuTN55(d9VX;}pgs)C&pS~)CkdIHS^Q4(!#*av z*Fpzp(7FP!B#_L-ys@_jRQf`HbsDq*Ue$I9viWNM_ZJBG`e3k^Y>?4c$F=i|`#)XA zXivJau>&Zjrw%=~8E$U=b0`Og*K+6QC+}Z{0*1!D+L8}0Wu%b9Vc-6oJCIQIpauH< zZ=K5yvtjr#yr?=9)4ZToV4*ZMWmg0Bae2dm~-%gnz3;ex`3W z^m=4@sl16O_-U|XFi1g7$MMW{#+dsHbE4;0lXa(Wa0=FNCF7bKyN z0Gmx}Bor~>)ZgQT?pA{3W)7-*d|mLg6WVM~yEg0GZki3BiMPgmMF0NFrJV0_VwjKk6Rji5PE#hsH?&@WRT83B}7pVy1l8IqBt!;o?KzLtW) z%OSM>klJWHh*A&1VZB#0RE)}4F0@pGl^36=bGq-FZB^SHJA46bwXh9-25tj|Jmd1! z)GNyw?HQ9n97G;h5;LK?jdHY>?>tW1(Q?6mH9)>U`;&0RJq^2e)TV>sa6ZE?*yaK|>5~`8Ak$f=IN}>{v%S zPQJcp{(xxxz{>;o=Y$#lnck_T;N^f5C~e990VN~(mA7u*!_{Z#E2V2fbHK#x->Pan z5dn`&oBv)LVGcuNOZ*Bax2learBy_vW;g#2$uUo=0ph%oD)1C7JN)kH zzDCcR+J!b($50E@#vj;yiuElY zPJ^Xz^o?t=hGysZ@S28FN1q)i|1!S-9IL@;>fw%94z10O_cv>d$L3O{Ku<4dGLN$j z>&JtuN5;6>4PwnwTs#BPh0x*Dp7-D zH1LpAWNV7LXLQg^Z0l4t!0!&D@br8h0v|&CV>qKb=p_CMagrJ|zumxaa&chuj5c53 zvu>RHJ4Hc1)VD}`;cjxOt)HMaPZ6$PTTX8fMyEUr#g$dGrmhr44R7h$jj!IVIt@eUgMGQ-mF)N721J9#>P*KXHjAFCEt=(m`#JyMeyA9GXh5bqb& zCM*zhPD>KRHLujT0whw9a$6go+D@tgDpWD{*lvT6eXW{tta&eoXb8IBIbJgI=daTfpz;>ogNr-jaI0s?utU_3w9%;ldxh4gq*+PM?4Q6kS`jE5 zM)g8CMKT4pk-iteP719PR zLQCd{0uANQWY1-z-&)C&Qd%;i5*^&nn~;H5`$o!Jq_>m4{Zc50OA@{1>fmRnHzN$G z)GPp6o|fXsQ`^J5Fef-HQmUGFvwOtsgWDP(33NAvD-@T7#;F4ke7&@IMR_8T&t^(x`3+ zix%+xAU*fRfImo};W1uC-R+0@r|r#kd`bB!$g%RHBz!`ZK6nvZBy%ajysj^I)~YVOc9r}2vhntOVU!-% z$8GR1x=Z&_gIZ0HQjjB~Z=DCO{p*-sdl~ym`sPd7I0q_^>lK~Aikl3|Z;+NGtOb>vN_w4GI-?HIUluE`q=^>QosnoWWy+%9S) z;wLroov0nH&}Sb51OrIo`_M~&8``I0>LTX~c2XXjx5 zVXUjv-)~qdm_sls@sIws_z_Ht%dveD!gE9zR+w|~Fz1-R*EJ)wAJv|yts|4StB6DSHs-gbZMQgiv*UYsKo~Y@=>qK5optd1H zBf!X0#)}n@#85ib^ST8rpxN^a*K@4U&YS0LK2og7ilCTxGq0+(US3ZR9Z>c38Qyl( zW`VaIDd(#In>}eas6sVj-rM$llau?XgY}8yw%y>O4Z}Msg&;fTt%)MYqfm=4b&$MY zZ;PcwpQ`dp9w%f5jVrYj%<)-|$}F_~Q;;E*`2O3h-mSc+e7Mig)|kp2^}ehW!6Ye8)oYJM^b8dcfO9Q}Levaz6pAqkNT@6yIw8gO%hz K$W_Xkef=LKHG>cU literal 0 HcmV?d00001 diff --git a/.image/common/infra-feature.png b/.image/common/infra-feature.png new file mode 100644 index 0000000000000000000000000000000000000000..f5cef50c56ff3a4acccbfbb4f5f3e453dda5e12b GIT binary patch literal 16920 zcmeIaRa9I-*Dcz(y9Esdm&QGW5G=TB;~JoG3j`+wcXziyH{N(~cWnsn?h-7(&3FEX z|Gr!~4`-Zl$GG*hSNU42cGaAa6I57KC@U+g4KfRl2oDL1j*Lw(wFcjf z7T$J7KW+>^%+&ln+k9GVdp`Od6&3aRaC_4d*wWVVXCTAU#?i^my8>EsRqgn9bLP7K z>%&UV^W2A*jja9Ko0l2K$=cV~{pRyNalh7w;?4TkhRAF9%~BapSNiLdgHPCEPVL-N z=FsD7Z&8`ct4#jgb?5%;FRtfpRZFujz(M zeXnf?{WUg3t8MAidoMHRi=MM_ec?hoqxG}*1oZ%bgpR!QCoQj~lkQIh|NI2tF3SvS zda+_q>vF*Q=dJ(CAndN}&o__ox8Y=t2M54|jaK5kh1Pl zfQ9I#^xNq#;$#{0Qr+nRn>0`>@Xw znlq+Wq z08}a%`xH2|M_n31pZ)oMzg=>a!{EXk#m9<@$I1dB!rPdFJRt%4P=&eAani zMzC-FK1j8G$tu&9EmFkhK+=ko&0i%)$m`CLI(P+E$JE$s<=ynx1rxpIdtoX?Y4dec z+j$w6AXa1?(VAe!;A3BRgA&*Gsr&yi#vOA23>QFE$<(y!y@=fw5aL;=DTA{SbX@j#>s(ul+&(svoX@XifsqG^_Pi#VvX6O;! zOn}>U%Ee9OJnz$Jh4+_h8qLbX;fJ0!WEBEV?_MLb!JqcVOF#yRb{MsUar1RuTpy@Z z2DiN*t8cfx#9-%URq=5Mkn)gqNe;>h$ zEl%MN%v)9n5?(wDG7xsRb$XG89>PXlU0-eb7RmJ)2>4FxU=w2%NcDyU)u@zX=LNy-i)?`GWq-( z>W*7oVTI@qCtBQeXqFeUcwJ}2U$?Ifz0wV5`l8BCW%K7R1TS2jC;%d5Cr9ZLe zug0Fe8s+8_t>Y_6JTw)*+aa7t_kV4@HoMsVCRa*brRzGW9ImQUS+Ftdq7N(yJ*K&~ zE!f5*Dtz}z+NjG>tjn0VLVJ||opG7{s^g)v?StFA2IpZOB$YbO%ow_e_AW8hg85p% z1*Cza0kbQiXOa$lE^iiox7U5)`ODa88wtO1XbpP9L@@v9&HpgwF)eK$&}3B<9y z8&ZD#_Olk2>05<)*VSEjJz>pB#YZVvJ4p<|;E+sQWxp)GdZmCs`;LLecH(Uv$gdTB z?EqmhDiVu7=lq2|Uq9PCdYCmMy+BYQzJabDF6u8kx8xGhqYQNP4zTd|@lgWK7^fFjJh>pZunrv!q=5d zS@8UmX4?XAl+mlqr{b-CL)ccEw_T-=4pHav2f?+s zCzV#`-|8azxlx+;^$`I=^iJ5cw12F!^ue=?FiXLcQcK2Rhi{s8X!n~mc35%BTe?(F zZch%E?ndKEPMWm~#s*oOl^As-{(x7ZM1#f1pC&FFljD;kJH)m6j+);bG&4CNBm#}? zNPTIM!$76}xoY8)eI}3o>T%aBa`qumUMFJ;@*es=&j?FA8hxE@MDT786Yd|VB5@m( zXH!32G8PQ%$;idTOm1oCI8tiWAdb9Hk|lk5mCeQWl@+XBOvJcPeB*xoj{jib%VnfW zQ)d_VWd=`7Ow@4xz<`k>cQq8|87s&sc^ONY*Iy~JDjsu*0+A8oEFEtkofnJ%gN@X| zM#G1VwscPB6o)XFpmPUQQfLZvvjj@ZY`m^-4uTg_rVrq>uZWMsU=y25AYIc|2hfl% ze+;Epi(e)foYM<~Rdu;P>C&zHUtaA-IcV9-QJk-czHH)>+6TiN*E@agUNmxF0^pCQ z+iPo1!eKEr@anM7VV&j?I1TWZu+>$+vESi`o=?B)P5!8=)nCGw{GVdBPCw?vMH_)A zoPNFPT)m);JzT+;I_`3|)@0iItLk9l9j&b1u&;jt?2#ZI_cuPnv%OKqEla!l$Gu6E ziOg-UUct~#d;8X$_6N}A-nmzl-_iVj9elW3$j#XNhZdSx&S82{2BwExAWI*n_b3}o zcIN(KS>#-oczT%D<=vbxT{giUcD*P(I0(TL*(OHscyNDxyd}zmiFD8Yr<4&&PdLCD z1%2jtUtPdLyzz$fp z^DBcC-^>exA2g$l7L7?l_FXPAxX|Bp%`iX?Og?~5R}C*lgcm@v2|ORmZIG-b@NcP0ftK_dD&vj+^;{huxhytItAc=ov6^wJqd>&%%@e>IYd(jk$vL`Hn$ z)mB(l0*&tdv&e_nvxn#XyEAR0t!tUwo1mV!9X-UNkay90a0Ll(4@qU*{2kvFGRtg3 z5wKso_x0tr?p8qq>}xIz+Z^`|TcqGdpJ|J~9dPff4Zjjyx-eh{ogrUY|M=qR{H>T5 z8;yd&=kg3$XViJ-ToMHSJzEp*TyO07f_?=&B@kGN$c^~8NS%w4eB9u;H-<8f<^us< z3Dk&VNI_>auD~0U4m-ln4$3WuEKV)6X2XG<{e<|<1^kPs>hW@MU2N>0s(jYa8P)Ho@Q#EL`P~rxj_8h$J zdY6ZbiAb@xbL0`;qvPW zU;o?M{#E{BSDTVjjt@7dm+2_U9UB2r8ynG|dJR~N(nof+U%2})X?a{>cMZREa4&G_ zby1yh=jVLpl^6`?$Hqh@_pkyA&FxUuao}Qt1sM`;To2)i0`MHN+e-wym3)iX0T-%o z^<7Aj;(*_$PA!4MWlI{+60+ORU?j%lxE?LMxPnE}!H?OqbbqKn5hEA)Hfj%k_;?)b z-xXLTh?5bE3Sk68^3E3qCu^k-Bur7Ya>lU#j5RWM;8&KSs53z4Be$aiiM1v!I`8&K=6?)>qFf4F?0yBg$cRSn+AA$c`Q#_=Y3~*_wSO_8cvvNXQ z=>o>kT=iOXE>1l7ZTQx|S8^Ed5Nn|Cr4$TG=#UV;?idQX$2gXQFd{!U`Bo(x=x zyKxqoFrxH!4?AGatl3KD*Kp1VckG+Xn;ED_jUCjf(M5q-PV`6KfK0VAc7D=S zwP0`Zng)vMNp~ZsUdr#JH$CuHm^Czv9nQ-!s$elXLuY1u;sY_BD+Gj7@L+&Alr=w+ zA+2Zn!Zuh9X0 z4cD=PA_xA2^#3)rV?x#r8ybP?<86x(-{XShC2kC*q^P$xGhs9wkd&jUnpD;TQ`4fL zk5S%>#~L;*4LW+(F8XZXUF7Xt^N<1P?dCZsO2OJf#4ZIkf-tp7Pzgc#P@Dfly!!|A z_RJ70BSRtUkFSodkjvbc9fKfvx%d<2UW0I+2O5=oCSCIF;#>u-L-db}jkP$haRJNK z#sgx}^rXqDBwsYgiz?w;wiHi8jcS556al^+up6-~P!PR1=`#X@iv5qx8u3dV>XcM8 z!*ks+QL-lZS1|mM0E=Hdkvx;lsx@QNR?lc5lTk(;c}~SGH|2wkryv%gD+~f_vWBjI zw1TRX6|sYF|GF>XxY$A2fF5CQLbGo;_^qHt*U%EtzL0$x9z__7%3m9asX8$lFC7X% zX=pAM%g1Co-%4imqCF_=2?IR76)7D_XJU%<9k+)D8Jb>x1b3Z##9gJ|q_hQ{M>#d5pxa8~s?gi3)9&T>%gkt_FrB_+m|XrR zQ)ZOX1i|)iJfUUOh5O#Mb@2QgWdSyHdLA1FCvs~CV4SP@ zoB#^A6fXMh;^tx@rzPSZ&y@s}i>A7K*HI(-130PuRU9}vh+3kOKDts3?t|ue^z+y_jsef4iLON!a4_qqJ zhB=B&@KJ5>FQX>XI&@Qt@PAWM2$F*f4X$kluXix(2SwapIdqt`u_M2KnS%o0(#t_#yye(Qqyrqp)gTPf9h z-Eoi?%nnLDc6j6wCOmVD>jHtGm;v+8@G+(XU3iGSRDKPY{mj8r)rG>sr&zV2KWenn zAVZxK2Cg>30CwkBcNWOJeN_Eju>2zwBRi^Ai#Z-pQc*xm<|p>Npu#FX)gPuA7$0fcJDCZ zmh~zBXK7mt?q#D5!8sQM7Go9tsb_nF9DX#A0*hx9B>rXieFO7sVTlN=-?=dJ&3D2d z+A4KZ#|J@?{id=?C+GkzA_0GpQ09k1tgf;pd)mt*Z|6YtD&ML$-(&xr^mBmFHGGmy zGlj1H%hn?TcV*^fRSM%{l)rO@dKjDmjr5L@vA$sh)##8mRU`@VH=4_Vt#+b7SQ`2Q zT$jw?T4BrHHzA*|#n&-2O2Z|Urxk2yoOzXcvg-nk#bVCW?gpHy4JuP6ylfC%DhldI z^@#c2Xy)Ce_xdUBHJgDyu^pdO-=s5gi4HJad~;s~^)}RzvJ&c|j(&@X{DFEiqCe^d zYZvn0CxXu~m0v7C`r9p2f2Uakm5B|$_?HaMroa}HuX&L9qXf{imGqtJfpJ1y_f>}iO}u0GpR1|v1DQUI@lXvJda<9{#402bBz%J}sL-1yWq-3Y0x&L44#U7nsZW@fTEEONLb z_%oR{hb+q>jME_f#P<{c&{aNnF>IjyolOs@*{88#$rwM59Kb6d>^u(2g*rWK@LH|e zkGQLPhL-Glt)(niqnxyZ65tPT4ennbuv@|Z#x(NvwX|)JYGxy;XKpSll+-DPugs`e zeA-*I5O8CeLw&^|vzpvjNVKj50K5fn7bY=sAT!NcQ+O@n&C$Y*u{-6b>CL^gxcA{_VA6#-{ z_53_To+Fqhj$ppWhWF%rpG~yrJxg-@Omw{VIhh*?+UXa!((80=&KYn0& z@cNH4C6=Bb9Y+jE;fVF;IUcKCF`pK<5n4mAZ9~topc(M*-@opRFXE}(MUN&zrP6lP zgdemNtl-5+sxP_9z%2vRz!?w4Zzxa{3#T=jGgE3Ho!SkbmY2UFVz|BB2&)R6n-VQk zd~uOA1m)CbjpiSDD|6?~&v8~n8pB}yKz-Gfvxp72?pDidlBdMf?PLIdTFz+-tFBeD zE$TUykj$y$03rrCa#@tpO)t5DaFm2jI^P>b1cWk*QsDncz(6qLz0tBNp_ZYxi)clJ!>YfbXQhgontcG2?sMdTRupI(* zO>9n2Pn)?B2s!~bZo`Z|okEn;9T#6^YF_U+Ph;+%K$Z3i6bp;!VCdDy26)*bHu(8J zq?>JF_H+rf0B>!CzdgxObnNBEmL>@&ucdToJ$zPOdh-mx*_!&qzB_%pgNPTGiBNYH zM^%}U@5sMXOc6AB>K{7~8mw=kxHM!P&DU)=$lJe&$92%I=(H%qH{k4=d7&C05P4uozs>5ftVv{cY zh^5?x^OnEo2Zke$+p2loURrx|Q};)qSt%ta@yr94(gjhPk-#DtXP{e=ljKaB{6%yJ z6994wha0;#ZYF5(`AN*%713{5;}GLNZ4fAUMg2Z*WZdT!TSC%=?y^mOdDIR>ta?XV za8LSGy=kBRJoqR4sR1fi3a5pd6|4)(Qw0>*7bLdiyf1K7WK8 z_5J-xeIrOiL8?895bJs;>7#cb%`fngN=S_`Ab2>ITz4_g*#L3yj_|X}0MfJd1 zmaJ)6DEh>li7ah7@vShz8M8ZIQPlD&rK~4UQq-u!FkUv`j;J+by8rYK4t-ntaQ|-O z4w_2f6UOS;!ItOK|I6;ZDDJ2LnyD_G&F%q}N*3?&hy#*OF4Zsq-pw8^nVAHeG+5lU@qN!0)ihX>wgo`z1951f3x0$C8S@^hPUcyx zx9XZSz}NwIJ);>k0O5stL_g);P_rSoI+kMu)=iI4LQ7@EGhyBHT5793+2!H$_s zn5NZ$5Pear%NBdr{9~-j-e3~Sph4Dj)GiFVZaEG-K0!4j1kuk47Q~X69C|$TDVU)~ z$k++V$N*bOKp_G59Lt1`H;ScO<0F3kLCt_?lv_?;OKT7M9~Qn!RGes*M*4L$VfwV5 zu2MkP=eL!h*ndQQL_3}UW{h=`kbmy}D(n7`WY1qmJgNSf zyLLl14!v4}C5$d-ly;6$N74Go8d#}YThvTDay+1v2BW5U#Fm%W}X#+|>i@^(vCd#`EYlO+OCqD{eeKxZTibAcUMAqYJkc_=< z0RAvkT(L;C#&i`P$=&oN5y6O9Mk9-^Ybn)$eMp4>01Z^IFzKST&4~2f$z=#s;-1CM zEi)0DROG8Ss;Eytf4%s6-PAgMAcP-n9n<6S+OH|q)l0n*t3@e zjCKeDe&2k{!8jg2h_P`VEbD>Bp;r&vYG|l+#E3t2@$W_=lVZbO`auhCgMfy(S8vo?pxp0o_|2KV~bA4fk=c&HEPzhddsfh z{-5i!gQ?;qjWFv(*@V~u(TZFHti?t^D*({KSX{wmr2T@)+{axZfDo_ip?xDmRoKTj zj~1{5vNLpqY9frLNs_Og26~N+7!LXs35ZW#Asf~U(ZJ?nr3LjXT+|MtHfgf#N7o%|3~N;6QRw@$tG0 zMtXHm^)wsfbL%Ua+$AWDOE>S#4oPc)y?a*|JGmfSILlw|7K@VS0rg;wcC-H+s@nT< z!yF|Fa8GXZdx3*?8Rcidi3~e;P(}tcC*;5*Ph8F8D)A1OoRXc1Tb5HknUAFO_jQaB zQMAGi+rlO|8}8Ff;FqPpPq)(`C)MeE-rxiURGsK@y1Joj;r}QX-=~^*mi(qY;fl%9 z+(40p5n91ETEW(Ar|%w7R#&%T+O2>w@9A}syz$6n<>aam-hHL0cZlK;xwvgI4{`{3 zAbBXA@u9Z|>o0%cKCq26SOy7Z`8K3ZKzNZ$TdPX=r7pUcfiV%*F5LGgxX8T)9Fa@O zfNO?7@3SS}u=bJznqVzFuXid4aNk{+4%Nb*p!EehoxUOd)%-aarty;l)&0W>VSA&_ z)Q!T=W^N=ON8om=)K^3aFg2Vi^zj}}=y5i0Lmz9hzMx?nvtD%S@V%VA&j$)NV)^jd9fIkmVS|j1gHwamMR~DZI~I4t0XW(EW~Vu~RSAkpOUSGqc4}=#7i&tL z2s+(00@wD9NCqOk<3)NsIF*&FL=S2`Ar3X(zuo3yA-7%Eak0eX^lgi2Om#9z{tm74 zH2DgZK~(rH!Kw~8z`sl|%0eQAG+pGL_yZO|VzIKg655&Q z|JEWWAi>*>`3+6k00-#mv&=>g>tip*w4ONKgcq6Y!m8s!)^b8z`L!XDhVUH7AL&Gq z)#}0qD0=xz*`y-}|B#=g$u^TW2IZKsfrlnYj>8^Y(g?#|wm?FXsNl5KOnR*Zv2%>i zOl%Ee5U4_TBlr-stPCo7ZfV!^@Jq<(TM<#7Hcm;8tl7SK)e#JR|G8XqRZ&yGKY>IexVrY%9GbO|e z{xe(Cst5Nks0*OcIuQ=c1KBf?)lnRAoZgT1hy1qNJY!f7e>+II9^3F}^Bj@#v+WAO{|)YU<(C`9^4ud@wfB zN9)lIY%B79SJO{=@idc)UEkk~9PQ|^V5N71x&~`z4hf93hoDx6>s&Dplcz&HHS?Gx zPouUKm@$NZu`?LeSoXpi`dL3gCoE%6(^rPK?l>%SR%uqoYU`=JVkZanfXK_Qi#J-f zP8N@yIO9de{;rN4-kn5&JE0S9%qzy?)hK`yx~?0MLscb2IDGQ3#Ly9o5$nZFELzlm z2(8fXB!q6~U0i-eN76MwWCut{1!DXMwwU^!?e2If30rRlbuGHJo1@{z_jdON-x5C3 zbzS2;0PEtuD7mN|=^_qn&UWV1axic7O>iih{`Bh#O71a7MqTGlgl~f+4*-~{vSxa2Uq_;AX3Uyp2xh62=)veKhzL4W*3Or zGX}ulv_};ryOMGm3gdqL*iEF%``qJ5y-kZQ@d>{~%iugf*MOY}YuF&;L-!~iwl8eI zDQ@}s(;3?O86WP2SS%K%>bGdek>fwPlbx?0+TX7AnLMesZ6N%ID-dzZRe?7CBHc^Q zvM`y(8^XFC(Eh_3l)7kJ?1HZGHn5b7(gQ!a&Li%>{SWcrLHNE?fim$ikc&UY91(R` z8!J2De^3x)?8Hh^;a5P%6n`Yf8wOpV^UMF|8{qOhD-m*G$KJj-5hXK;1sXK&V%^7b zN1@jSQiuC>ypkR9$d}qu7N}EFl+EV716z~wO}2mY_KlWI{TR5*Y-l~esM94B{Wky% zoVr4*`5Q7i*4&4AADZy$1VsV808;auGsx5Q5Z1Y`UZF6F(YIY!M4WuvgzOuXvM-%5 zQkw@PJ^vmnYeRDs-`=6uCO9H605GcBJQl483G5^g+3O#|0Rrm zn7)$b(-d&Z{=n5kj9)oewY+hC#6dMQ>Jz}|M3vV6WC|$kBk*Ewn6y82rsvQDcM%BD zN}hRXNglocRKL*TrK2D|H*&V%K@`sJgW;GOY6J<0tW&!&JCk;|=MC^i>5j=Nazn&8 zeU2d5Xwhn%y-gS$vXmu-+X0cKr#YYA?2<8vW^|j2*CMhW>&+8ZoIdwnnWwvtb!a|2 zL@ETcmpfhOPp0`H=N6OBA?|r(g}CkN&6LSw;srOO0Y_QYv2FPm;A6h$Ow@7RYRB`n zUI|9J5z$WnzBX*{>$j$^r^_%TIpwNoBBO|}+w&&RT2yb{&rSCi?JC;@1hD%GkH<>C!{iK5f)*FdBSlj{PkO1kGq*ZR4eJ_~e@y zlgROGm2oHi+qGgZTln|tEB2d&54{YvJ8WVLt`~oi%NW^Cb9bc5)T-h2gJ{<}GG=r#)Fz=NV(~t>!tW$F3qXgl;M1%1{m0 zB%nN+0>b$=@r_26f?1pDJpefSq)d(#IPnqHw$Sz!ZJ{jKm>|^rZG%E@dL!m96$6rk_N@>mCZ=wq^wV8Z(VvVq1#e<~t<5pV}(CCN9V&Pf=qtjh>&@o1N%wFP_ zF|v-jQmOElvhp|5YdhcNA>xH<%dVLwl8A#5y0P0V+rqZst(5RzU=d$-eUT;y6fOJZ{ki2A}1^H z?P!IYc2`A-5f723wemUWxZn%aD^UAu8$p{y%hd!=&v*Wz)h4*c00w_}JI3-Sxtvgw zMNqkXRWBX!8)FdG(EFcFI_JNmMyc`af!@DeFZ=Gt#(pt{fs76fvwbiqqjW20fmcy+161Nh0#dfw! zW{T{1U;e_7{_*(tNsE3A$K+=uZhz--Xe(g*p?+C^^kcBkWzEsC^{nu}EWb5qCK(P^Lp`vK4cO0=jNb4CpfswkrZh_4nbUcG&ti_A3O?9=$iAaupgNkJF0HIc=$TMWom@Fs`!RubrI@r1S;&Jqn$4!r zW+^fmFK{8>h!bRce$U#->T+58NV`S7v!gk<1_sYNWADRTt3DYb*Ylcri&J#X3WleU z5Szk#Ik57lKgV4W0#xYnsZAC@vsJ%OJ>_FKpxmrqnj>~@A=<>pWr5Z9P`ZIU2E*XL zEniJ^a|HYR=t>f#7RZlrAOyU*DUeMWRPb_-rtat~Udz4N2Gd8ji{0?~#U5}RAApInW^^f9>NWNkKYQwNWQJ-nj!=%CXtqwY` zB2Sg|kt(kpNec3GY5-;}UuuEjVsaDknd#-mq0+j?L!e*;YvJ)o0L4}Mbvj@{lK}TN z4W=`PJ74Rt{5bdRiLAeQ{kSk@W&uudb?aIGoA_y5)_Jg(_lODCaqy3#PL82}HZ1l@ zIgcU2wp-3LkB^TnhlIe!*#al?pYm*~vcl;MhfZJhRGQ!lSxPST`Z3)jkzS&Pf9%j9 zpi7B6dbF0HLirzp`Sy!Ru~YLz=tQDn4)Y}|mtAm7Hpi<=j-Q+|lXUm)$6W77+IY{k>}tRuxbEFk0W?$^@601((Kecw|pKK6U-y$0As^ zZOUa8tf~plOPQ}bHp19J{W=YZWh;kilX6QRt+36@PN^|16-VIJdL|7#*TD%tz4Zc< zWYjYkjVmuW`Z7m>FCRnXI&?gYm={|Av~0VKFGX+bF*wTyn0WN5MU4YO1m2XfM0V7Z z?LQM0x)5&hX&oV`hC5z|=wr|sIw8WF;F49P@%jsAN!nkl_(Hg6#@!6uTQ>gro^&am zEDI5P4q+3+UErOn^~_FM;CmW4C_!aX6C+J4Z5CCLyjCFbVhb_U!av6;BiB*P;OTh6 zSOYR^#f&f*L*klR{qcOHodJIJ8E!GPG&ocLQR{l>~I5wxL4R}HtvSp`x2JgWKGv~rmb zZ#5jN2XLk-zI84dYmmH=q3aH}cSDp_B`NvPeD>Z)KB0iMal7FzNUyt0oNge^x`M&T z2{*E{QAdQt8|$+p#bpspq3Cr9bR|lz>8iQ=Z|*7!3CZtg!?N9}FLb}E<*#!IIYK$9 zBGiu_n@elZsUTu8)G5H)$qD2@=@hn9#j*w7ZCP0Lg2AVpWI@`@m&^K!LPiX+s-HFy znRM$pw&sp#;&D740^wWDU+YWxg2ycrFX5ox?sWH`P(}sQ@~UY1kg}R}0HMgOeyrYC zPQ2YqBFpsCD+cb|s%TJFT?Z`Of6#|#UjMx>vD1!Z^ zHMaQq3E952Le!ZEvMGLeA^B$f%9lIvSz=1k_W^-OKfUCZj8C=zlg`4lU&081)iP$2Qr>~K!Km;nmGR#@LjJ#>@eHOyT*bnf9Tx!hoCQn zT>qW71^`gaHeL+Ae&6DwQ*jO-;>YBYkXs{6UrsYc@THq&X$R1GE1Ei*1fyL1P%64W z4A}t&wfJF>c9HSM^kCs9HX-l*VblYd{Qm|2Cyn#4*i=v5AH$8^o2L~u%9&=!W?+2D zxr~PHVwy+pGV#2wW{8s`At{I=s<=NrR_%y0`>2g{zNj?$_8KSGv2&M_rt4!sZ@^yc zYY%d>S0tubzi>y{dO)l9z4QtCWg5Zb-=zJxZ?X7oSPxDeYcGF8eY+-I?8>@G2CE60 zU0+1X4nhJx!$Oc$OhqOHNVqN%Q!4qyZ~9}B3J9)zX1KcYt|4!}i!y9)qRf=`hP;UCo<9u8)%6_^<&n5#lo)z)( znE~mmqp)6HR&jJ~)*!TJa;F<#DNpgd4-NzeGyq$4f2JxxI6aE<#l3X+ev`iR`KXCD z$=A#ve1u{?2k49T`$(FAHED z#w*3B<;$9m#a^GRw|fv0@zjVd`CC&sqFq+V(<)7sI^%i86z>PKrTii9y{6@DTn2cZ zt=1hSKdiSK*19UG&WUigBjuu=)v65pHI-9lC0}Q+k7&QN%8o~Ci@;A12->VLtC`^u zkw%~?NB>CYnQ-??@bkNFo&B58zVDh(1L>|$Eq~iVv-Xw_45cc{Kj&oP3H{e28E76X zImvz_swtgDe!sERm8cmFi)uEr+cWLE8w7HEb)I6lrVkuN4EAIVZ62y7Gc*MAXBHydgSp z#EnjMAd}1Oo}IQ*efhc1c95ourhNHl)-%Y+dEzGtwTNN9Ss4%PIK9D%Q!6HanR>nbiu|W4zq$XPAZrT32ED%1TG%_dItCk+_VvZ6WlNfn{IAV~JDfevwPlkz3GP zK)A#gViYpJLE`0 z@F1uv3dV9bX~cXlUSPy3ig#XmokpWFOv_(KfdH8oweVBDtW0$ zQ<&}l4k47f9k4fv*im;yEliLcwzhY^6yh-xzXWO@E6 z*=X3+@frU2=#)C1A~a{@UqrNvZOu}ZZ*I8N>$lV81R4+0i8g7D+gVJFYrj>!!6u)v z+-oS{g6cE^(zS&(d>}Q-H!6#9(f!N?vCT(H*5hbhnhG$x-Zd?tT51{(m(du)M!zQF zD3azPx3gf%<2!&bS!DIKuhrnS*t)$%SD0OQjME&s)XwIUHwfs&aG(p2S=bp!*Pw9A zH-LdO@feKF$nSK3*}uQQP%#(F3DA~VG>adF))o?X_q0HCXUW3{sF*E;$mB>0ru!fN zUG&m^hx~(NM3?5@8FHj=3ZEmHra}8QZ@9B-Ty`W?sPLIx^lQ||4-nHpU?X26m>RFo zmQQbi?Yc$;Jq=0Z8|4-`>u541zM}BEm-dFq~^@&17xo(z#gYmd7b+DCAOx|Lc&_x{+LH4~sQDuup|4=v8sYLcCd$4ZJiu>eS^{(VA2X=gbp zFhe$_cZ*>;%7Wh50Jw_KZnh~8h!{9Qdd7h4EQ(d8UShjYAU5qe$#uEP!VzP7)T-G3 z;M7Rh_`W6l6cxVGaUDc+iFjV2Gq08SeJ;%Dz6yTr)F97K5`tWWmET>8bs`p~t-~OV z%+Apn*iZRe7-%owHOzE*a<600DOqJHG>p@rPZFtLdG{>Mc! zUe{Bl)kuVGu`(V@499&roPjM!b;1z#6LpG5X&FzFG5cUMKf@Moq?KOIB9}7fAU|BI zWTFFgFMIXRU;S)pQKs_o}&$Pnz_~{5c--j`K53c2*g3OET3p*`emW zjJtpkH3CE!Pfm{U{e!kFp5ON7gvjCd4Ylnm&>fyS+8kXyuPG-|av)3Diy0SoeZKTo zq~g_#UCVpi_#caSQ7SI?YZ~0N4j$k;?8xunfO8eyIn6)~+RDapwH&nL(*+QEw0`)U zN-3iJ&yeEJ#`3{gQZipi`(3iRl`>Q~Ww4mP3ERLC7?j%tm2H*cwIC7ST?S3+>GcI! zhn9A!^0mo`f%xtu?5Abla5h;DJ$UPO5X_=~ex<4=kZkV&Q6n8xxy=J=s3h{Aj|rvJ zn`7GAnmtr)vhY4lrG3Ij_s!U6PrCn%-BlZnUS(56j+XuJ_S5}|%&1EVI&IL24U1r! z8X)O?Im+9mT?%YHD1=<=mL4^-(iHHA`Yit4Xq{9zUIN1SX$p#970^sF9 z>;&baIT=&e{|@h=lSSyfniPLIspx%XjVSWu#^ig6Q|BVqc#8EqdQ?KkcL>bh|5WU* zaMfd=pF!zSYCj}yi8ed+H(htszz+@L#>V4UDI_N5fCmtyaTrKin}Isf<9hW`#5D>PJu{}It2Uzf;9|2yHop6*c| W#wNR7sLindBg@OENLNXk2LB%-C!B`> literal 0 HcmV?d00001 diff --git a/.image/common/system-feature.png b/.image/common/system-feature.png new file mode 100644 index 0000000000000000000000000000000000000000..366087ce0c9061c34e60feaa30af099f99694cdd GIT binary patch literal 13584 zcmc(`Ra9I}6fW3UAOsRDK%jA#;O_43?gW>{-2#Ci4GAuR;O^GAcjE+iZCulMf=&K4 z^Dwh!-TN@>&dhl@Rj2CPXMd-5?UG&VeAQ5s$HpYV1ONcoiV8AX000Uc06^l$K>1g4 z>u7QL@4;0=MMw7j&;85Gi$;Ik)%6v8Z+Coh^6=S2>|}XmWovuu0`dFo{0z{p zw6?MS_wk{&t_})=<>cl<+S}(B7D~%X1A_wf_4T`Z`w|lq%PXosWHDG-!~{cf4$ptBF|wg>*OBcwNv|d=32OB;Z%k z@4q+mzqhki+FnkNA{Vk|AuojvFE7y2zji+NCyzn{wnEvr+m-`G+f6UuHJ=*WGuF!+ z=O2I9ZL7lEUn&E0M*dn)gq@@<9Iw5+tSw&mAHK|WA6!01cKw+>c>c43FsZnEhK=v} zjX&j-^ku!Y#=bnprp7Z6!2kemQ$-m`9lw>+#eD1m2?EsV+OuI=+UNolP1@vZ^Y~0* zj+MIrVvhez^?$z-jUH0j4(_-$-~!r*FQkWc%=qfJ645`joPJ8J#%+SbF&%Em%aZg+ zN@a{3a_}6A5ph2PmqGZi1~|rF&S=c#7B~D*-i)>EevTACO_^6nW!61@+LW-)wp6fK zDGx9p5Rcokj2YQ~AI+higF0EkWA;D3ZycyrJHip6%n3vc;l43ho88?eV!>U(xi4b} zrpoXk#jU0B9#gZfpj^ZY(|;K0W1r=K`X$gP)v<0|mCKdXO^nLN-?jGVbyUUjHbv|S zM0U|Mk0-Wp0S{?i;YE0HqaP<|O{ldw;o)MdD( z+p+JLCKS@d+1miaiar>h0U5J?M>hp*1Dah-bR;dR(xJxqj7`Oeou)eekharc(oK>A z6ckG2*$gQR)-}z5>P2edf?wV!Z~PX^fMS!=QqT-uJ+j#_+GM>|iB!Bj0ka&U+xyb7 zaCWzZ%CbT=Sri1M4!}dIamARl`?aqhPubcHQN!X8lv8%{cl4ZnzaFH|p? zCqU(rW_@Sp2oNn|L>l!vO&rqYQ-`U_$|U1xo0R(`94xP&ND==K2iI0n|M0c{XHf^s zX!C;F)xkW{yXzv9nRPz=Lg)HJzD8lWK1v6c(Za8+CbBc*$CwHuWyv!`Ow6_fG}$C> z#Cd`=8#<$EGJheU9yXJn-x=kZ3H9O789$KG(x03e`kOSrTQnBS#w?QT>w0KSzMxz= zOt$gII!6IL`e^yU4?C5glW-qT(GBgt5vJO7J1smg>aQ7N={NET>a+_`x{m=(__Fco zfv!XTWIVZXB~#gho^auvdWabR^S-6eChoWEqrVwn=c?ng)u-;(=qqq}ZFVlCH}DZR z*CCsJ5Ndw5owzICKlQ}h=Q942)dHNSWpoaIJ=%U}+}HA*4_O6dnX1d^ryu{Y{#gVM zRA`Te8p}0;=^Fs%KAPV~Iw0gc8x1BQ>7?qa#>e^0iNmSTxGSM{a&sE}yGi}lM857G za`Q~)^?+;#WFU4quUyq^HdM6QF9+-vf*!mCF&2Z##3b-*{v^+_g11|?|L^81<-N?f zuP~Q((epBm4spq;zHLlAQp+mK05HT2d&&)N3K7awOkPKmxM{L$^Rn_z&aXG|Y^cj< zw;kx^5c!O+zV{=yW#2DM$kw0eJ5_Z|OLnPMp~R0J?({YplD)lx2F?%jv1((#C!d@b zL`YPTj@|fytd<=9>!PQwjoIwS_`o5*oSl$hr= zaE_khuW%1z=!b+Cp6Woj5M0Q~f_mSV15fWnVfBXpn(Hm(eD+*roy--IP`Wo*K^~l- z54EyIk0tpm!%=bd*Q@2$YoCQsbW z6LS)AxH*(l#H<9-H|!W(ZWD;_&5IzH15MAt9ujt=XKiCWS-ejbfi9(01dcC)w|FL$jlael8Iz+ zMu4H9GVEOn&)!Qf!9kR@%lcaPzV&^=;+bZ#mQu6J=AR%`zAI<*iJf&G`A1y27Rcv>^%hu z(K;~U!CoX1D$6eq7bAI>51O8sh9p9z?M=KqdCm(FIRD>4T5G?9-Qn4XU6p6DSP9}f z?5it!wJhowK{`%1?fSXzeMP!kFJ|4Gy3FVWCa}f=9OG?cIY(KWV?t($$8-wkg!4`} zJ@>@5w^R`%Y5t#N%^1>nWZa&d<~njuqq{s$K-m}rzdJ9P)C%IyK(u4NnsQcxf;BE9 zX;DFavTTlHYag3Tf2I&(e*E}x@A@JWG3Y&$CZ&ttP?y+Z?KVHKYbyQ_%nfR&O*jd~ z!7tKAoq*8tVO>(=ta%jK+_QLFi<$kZhT*;K!#0(UraU zQwZpXjmj@JV||uXVsf3ptW+?ex-MPdBF zUP96RC~>(b+KGhvQUO0`-8gCc9G=Ni_w6r0<S3y-D|?=)f>-fW|8HvB!9qT znt(rhM{)fa6ppkCFg>LNaH2DExX=Tvhz|3pSkJ5lYX~U(z8u{90~g=NzQ^J543n*o zn4)AP4m11;h9oFW7Pc#BMdw7o`Ne_vX%>`aN$yc`sya5t{N`^+m|C(WH5g%^Ssex3 z8oc+SZWX|xPm{gAs3>w1{vWpJt_^mN^9x58+Hm=*e?AoQ)mFZBi;vT17E@5;z_}v7 zlZC13f45nelwUeb;#m*?n`6aND5$lP8?cuDA+bP1rB5b4{JCt&NY4-##4V+wg^;}L z%7~xI86u;*3lBT+-x#JkAhCxkC}=_&n^dUsgFrH{)SaHnkSD?qKy&RKA251b&b!KA zlEScN4>b%Z?4TNy2itj!E`gxCae-7cv zn(Dp5e7!vj7kpNE|2tZyEyQjLL~{;&cj+qReCBKL173w8QXxY#450^>PR~`NNPYs4@XuTC*tVf@Byy8dI#?&}-t$+4!F_xm zbAB?6{8mD)k#s+V*mkT%l5=w7-F|43hq;@yJ>j2M@(M2d0x`D*nuR?U$UdEuAn$uG z3jugxRq%e75fl%2vFm!q)YE*LU7DLT`+=EKOzKE4Cf*mz{sA(d`m-{Bdg#uXwU+Bk ze4wLhHxd48i-)oA(cR*KeIRIZg?*c;4!wPiU}jir=Ahsgc#p5+3-X#~)FT~iT`D?q z&ne0)M@DhcGR=jkpL+6#Ztu(|Y4vnH66u~G#fU9Q{n74$J}|ZcdCIOJ^6l29;y6-SW&v2-Mjr*>A7v#>=lzV z*7esM66{CKML7jV_l_c{O(^I}N|nw^DW$0>hT)E6y1JypM=pHXw0NHfc-JjiLfa9s zfDHF`chhvxK4!}iC$NVORh&TyyZq0ee0WG&JMx=f!Ct@Kqe-!mvGduEQW`X$Fq>ZW z(=yc8J}Y26ADS3G{jL;+al)O5J}HLNrh?hEMK0!VzM~ktA8Pm#*0j2$Ji10lJc4kN z`t7txMU{s!AugM^A;T8+6N3=RH@v#T9fJKmb>LYpm82QBg!?rT+RZHE*yZ4l@2x$4 z7o$(tu%sjgsjG+3eF*(m6G1$S$ypv#JFA$WI@UXTwygx>wN{_UFF21#;k)5;KvC>k zT)*ChFKM6gbh1%k`fbykL!Q)u1h7z?h!^*Ks{m%67jj|ZgI6BddPsgV2u7>{0V3&9 zUV&VTueK?)hFD)G71PfyiNRwl!5bIdU8jD`qei4K2a+>*ni;YRX=9UdELc|4SfJ9b zbnAYiMw4O^9cI`x@qrqpsJ=re*J7z0_mI-EiHep>&cmeTFpoU_Y8Lr+49q2Q6l;|-TQ&V z4d9F?=#*)An6O+qw(?}*c84u$LkDE{-BiXI1f>jtI0VRfj1|w3o?EQHCCr`=6FxoY z=Y0OY((9UCodPBb>=NRFaq!{t40yZj#c4`u3CNejl{|{?^Wm;D)vzbzUX?{B`HN{j zR-_$wJ*x?TM$agg(x*?jM+{q#GI-Z6|GU5&#;Vg#`vexeMerDYSE#@nD{;4{4!yfu>jdx^h5ae2Rnu9N zEBimRf31x%VLatN&G6g~Nr}q`ZX!sPF3k{qAcF^Q6aIKcUMyetHDw(OWs6USAZJ6P zacBj+Yw7OGEci^4%nlI_&p#2uZDFfhlGt&kGIRsCkoTbUH4-ht$4`I^*x?q`DjFF8 z17!ZiNO(v&it=Rk_bbNL8s(Es-$%<(IuDyFMU6Z0hU*LIOV<3g@liS7mcOzVfwtH*~?}N^(OU@=;5}lHC{Bvfotf~F9b7F0j&dyh4v>y!jb$`FasE_2s?u) zG6Axpj@j#J1ZrAV$Rl##CNAAKhiW8j$lC(n*(wzq3L7)%W<7Y#Q?A;Gjxzo{$E$hb zV2|J5k-_vUzM->VYU&``7kaBe6Df$+fT@f9iwiZXcT0#iYJMJs_s1LX>rc>RLmP0>`mFMW)?`yu z^Z8yK*h<|bW}qywxGjDH;d($CMq``XUk!)XU)YWN7Q-tUmG6M9ZLbx{u)w4rC5{9h zj>X?B`l_dx1BJRT`I|3bNL&81M=8x#b;a;-hnh&Z>L3Q~xofPUI~Hu@UY;po;H@J7HLC7*X0>aTqCbGOxj>LN!1ymhay zJ;DXk_bPA)YV;Y(IkVuqU%Vb0NiUvPZjJ-RK6IEpjbj&g7=PlEynx*E$jRHB0vAu; zGr1fJ2Crt!Q9m9{{l|GgqU&THo8L1$!24I_qHO(pa5Ta2ewZm6Rel=?6{Z`@=#S%~V2FChf}siMAZrbj(`cOG(cF4%;01bJU=_u3bO zkK9<3-;5xx;_MhAc;Xg4ZLz?K#PudXFB>kPCKJczVC5^lZ zbUjCvXitd!V*sv{`j4!gANT`r&3ix%1&pw6L#^4!=#(qRxL#PU5T7xo*o zeN-++vFWhmVSWgP7I4^Lk{oH#;9;c>g!pek-YwxS)I6s2eq^aI*_r*<|J%KX@^`AH zE%}pUVE9J1P0H1mX^Q9hp1@I%V#ccbXIhlHnD6-Rz=Ik0D6Js(Afw+Y$W_kcsw;m| zxs}pIP`4#61PBX)PU2JfBq~fuhd?GT`(*!+VQMNXWU9#CMaN}FsIfnP=~t6M4XXr; z`ST)+E&4Mo-hU|7G)KkYHAQkw06{FqiS+^_g`l!wVT-adn__V17LtqpSdYXLBP`=jlBwcQd;>WG7li+4IDEv-pO zxiXczG)5B^UNCYUbNxK6dLJk$yEaG>a}uxP7gZ+OA&_4Lxi2NmCW)31bq@Wy!YWCH z6AY((B0I@5gON7;K8w`cN4*rGQgj}}XGdVg?+7S_!u}?r#|{X7rbf*7O!jlEg=W50 zj$WOjEI$JQDa=wl;M}K{fWfy*P+U2|FZsy7J^+M&#WDdJKxy$76xx=TSmDEz79fk)~i;4CJ^SVld0t1qL}@=Ld$T6|Efc zb|wKBWBi_g`_szVYO8oR827^nXbZ9aaCfm89FI#p1oFO%+d`6rIShIs21NVNHj*mu z!rKBUGD2T=M0a_Bn+Ksd|F&=99z{dmjjsJ2zD&h=#yJX^h6abG{ zaGr$Cx!He^hDnsCcUH!ed#pG zk4@8(3ZjZxd3}+M^5BNo8k!AnYSb;VxYxh!cDXP$pMSS4I{au`-iH6{FR=DTL$~3j zO)TP{xH`%9x%smnm7&&OQ^(DxhQ}WzH?5`bwJf=|3jIe=pW78?lt~gpXbnGoZ%JsK zHFsJFlHl4YWOCTF;O?3qTd3rfe$_(%9jPrwg^nt{3w0?=;nglRS8AlmEuMuF^@pUm zVI4e=W#zEyuQn2F)Y^)}w(Lm%PXwOa<k+4m!_kkQ z*Zpt4ncYA2%(P7V|5zq7@F}l(c$Q!pz=~IYnWEJ@2>r0@7D&G#aN-+(iVY8dWjvcE z?c!IRqJ-8{AYn1NVl;;(_`-Mc{Ij|1)$5j8P`8k_RtFfM#QAX(vC_)Fe}CKl0_r7# zC<}!AJ{_h;-k%^2d-v9DFmVN&JXa*E9=)HHh!}!Cl8W(@K81NUjY!bw z7Pdj3l4O9XZt7KaJA|_PBF?9qrY@%G2AeG^rGBJXq*QCP&_QLBv6p+fV9Nj%Td!_3 zQz4#d6+oO&PK|7#?ZMh#a1!tk<|(!Vw93D8j`r-TNTHzysvXNKHANhip`2Mlc7&&j<;jtx6z+I{5V2s#yL5d#)(ki!!wguuE<#sm z1Gx!VqkXHipPAd>11vsO5{{S+2+{~5q!1#7d*PxG?OdrsOii4fx02nF)QfBmAE2GQj6)j-u z8aAnhkcV-_x683I(TZkZ8F~5V<}DoiZDmG29}7g$iDIFB@1tHS?+*aMzFIrxz4I20 zmspo9wfwSN2(LAVwb_5b6t1_N3h9ap(^R@$L8@S12eYsiTHaA-65UsSxn`v(`2fjl*K5#GD? zYIEbyi4OZQ^!u;QqiDVve7CqHv7YySq)Y{mHB`*Cg7If*R6a(m3)Y)0gDR=@m#-9V zk#*CF@s1}xUFG?#ZMIDz!wKbCr}kC z+x~_1XVq)Xq5E{+*!2i2&iS2F`i+NPWc-lq;#CCE2mRji(dxK2ETr`jyh0&IS8FJP zvZh9uG9;3%;bM>FaJndCD`&XC-CO-WPig;g{m%4O|?3YSw2*YgI}d zBOj;*AAGyH1gE>;Lml)kWLW3vCCmPH-)(u%90Rl_RCxdS=b(3|zQ50f9~;BvTe7LP z(%E=^Mq&*U*=3$FI#PqGMX@kB^A4v~^NCfjPFE&XC8cr@)ns9+tpN|dt5M>30dbfy z<+L`1DxLuD*7IUtd&xiR*TM!qgDmfk^-&ln{E29U;Q1ZvV$AVRH%0*o(Hd@*p244R zDQJ6XnJfCWMaf5$4AV{|au%8R)rW@HT`^9s07h?7vn2FlO z6@A_-_Vc^6|E{X2Xf{D0#YxqK*Eu|;?`f!Z^eUDab&qaGUJ1MSIye9GGU@p|1C8yb zB9kzYVM6V7Otv0hW03C&WNJz9Q~VOx*IX#~tUe<3_PD*xJIAyof3!h`Fk_Ce$15L$ z4u^pFUA$tgpw7$(?K6N*>bTFN2r-Ye&UCYxh2F@sXRYh+H)r*;gh??%&d2QwsOBP~ zTs!(U#IMLEe8bNC@KM8Gyld4w8K_fHJj6HEDO6`}%E%})0Gw2_am2NVE1Ms}%PC9^ z$C!CHI)gbZlOOmSXNShK+HsPz8a`Fby!SAoQ>YI;o%f8by+`7Ap=WLJT7yqqZWv0Z zgN04+5B)AI&{(|J&iaett5s5@NI!|bbe7&>$rMk5I00V=4V20|_s4O#8@z&&SupEF z#Qa}1jSVXq-kH}_Ha;7}3R5Ns9&?lqvB($iN4U)s6AQb&tbi9}?9B@|i{PuW1q`jw zrPjJ!(JZrMPyqFz8=1Z{l>48%adN)bfcLl20s>alo;a`$UdK_ws0pP^q68+U}b;+hex1;B&tq)YrvN{PwILtISENIHlA?Nt5D=3w2Gw zmUJAfU*+;N)i#ZNzOwf2uig-`EDqCXoXSDiTT))6W`|7F2xYSYZiG?xRP2rE^c{5Y z(?b`WKF=FROodRkdhpBE_R+WL>)n*VqI`bG~qxMWt7XI@S5V=@0ZS#&${R z!!r1Q`)boCXz^BfWDMz>2emgbesiZUA5s}jrX_9~S9o<4y+I$Qn+7dFA;Hh448hQJ zS-->?ip#}%m@qYqn$`nj9e%yg5(1-;Le`3Y-HZG%F7~}wY<{UF5#owz(U4fL2NPV& zR!xXLBex7&#^v6b^NzU4C13Wzk^m%H3c3SW2m7%thYXxWVEKN2$M#x8OOORZZx7|@ zr`E;!v)uVBK;)_b#?}G=`Bm6iDK?>GMD|2v=y~ho){EOi9*SGejj-J97f_eA%F7sK z=qfh?YS?3K<3_wF486VsURwEy{gpJ^r?7qMmVEAWZ7T#|plUi}iZkv!B|16L5bn6% ze#^1&qve>L>~MK?%GIlKF>Y*~_Vu)kfQgrFP7@dYg8g}C?2K`13M1~3_t zSbEt($t4bWetMVV(AVdByxnswK~|ACQ~msAYxkq_!!P$?&Wn)1KXYs75GHE?I+)@r z819c=c@4r><9Q`SiAm@eQQDJKSq+qX>r~C;-ufyQQ%z%JTVabs@ZdhdB=5_+yMg50 zJKWk^Q3*6L-ct+zHmx%zu8tNIJP@zUR94+uMhp9PBt7bQgtaX_Ys{@mkv?m5Dp69u z!}^oNsDJL>2kF}Kqla$GDaWAFVkYD2W)XlQ0a`_T0S0by3ijOB`dipKUAIX<6nd>| zr-ss)1O@5aq8&#-Z?r!Zh*#e4_X>0f^Ik*AyElg(`6lwe50C>U!gK}!!@G64uEO!W zf1w|=MEa7=hy5(d<)d*VT(Qn$|5hT-CBB!0$!15sL%4k*YoNsjX>JRtT+j%$Ip450 z^K}@*=Poaab+Ic7))!RoWFMNK162EMgmqv~v_Vc%c*d5MoXMa1?GIk21g0BtS_9M{ z5r%ttP5^6+1WsN+Ln&`J*hoTN0)f<2VTiRYG;Dkips^B+21(hjcgaG*4T^S3qdt_X!e4?zPNKa_`rZJTX5j0Ei7&S8h z9ZEZi!j6FJRDI=ylM|Uojg4ejyE)dBlL<0qJ77VY9|w^Aku~#&h(NKux>V31YdT2( zuG^V)Uara|LmW8?b%junrFeXnBvE>xs}?HCDidSj>(N0f_$iXmZX>YLERmDE3xa@% z^5sO!kpr&v2c+TRJ>V%&^8DUj4qxxL{6!^_VvLZ%yM#A_d=;auedwPVn6m@AWz_-h zdnOwV2yHAU@7Scbk-A}S01wPdJ$=dimh|v`TvCIYZ##a<4`G$}gBSpz-9#Frwx(2w zGIow?PZHI_Q;T)H?NbKbMrm5$lrs?BmL1t8#Ho{e>AZe8g@A?kvs-v)*sHh6l{0g= zw7v2YtFXKd@I_>mNA;?n7*7aC6k9d;?!Ab%s;YF~khMy!s|ayrJm*4!@ykh=0{gu& zDL+nSKi{MW|9~F%^K+NbG}#GrwZ?8tVkPTXj3CFaZ&qhXzRp43O0MONn25S=Ua&GY z0m)D7su>)>w?Mx4?jnir&BA1tMjzWb4A;2kJ7k#@lg6t18LCNytgEg zkV&$Iea;(+hngBDBG&#wBK~tlIihT-6nQ6}^L7b=m?1#Y0$24A=xW6~hhN*4^g>*DwJ@ z3_O7gw*NHij9{YRbLH{DyrAhHJt*O9aA&70q4ot4Yem z9927NM(hqUih9>+T?qIi`TXG<@F8xy6_FE7#L)XCg5ReCz{bsTo%A3Stptg-9#tbU z$q8LBQ2%b(Nc7qm-vsj>=ED1&NaeL|GiTj@;*)cI_-Qd#mqp)K;t)lF2!?mnIOYfW@Sz5`h!b+T=vGbZE)jJ)Z8U%mkr$%n=ug@SC-4-! zoH~((T-ZHhqp-pqLpLio$vz3dj>QTFxTP-1s5((68x0_m5R9C5)Gbo>G)I=11HKwe z4&BA(ZWGc{Xvi$kk}Tys3ds!{XFqE3z$>swoB0wsObZ=A66n~=$csoODU}@)cMbIZ z-0|}x83kll=d>!*hLgM#0!s1T!Z<(A_NJGeMSmBX7&vNIbR+2%mQAr-X{}#iW2#AT zY(M}M-+6#`kgeyuaUa2H!suYd7ZW8*gEGjtt@!b!oL3B_eXMkI?2&MRM?rW)ltr*L z?l5fro9V8fRNbM3%|Oa3`CWjSA70H;34sh~23&s;t@??KAKAf=ZFF(4G-+(X>Sn*2 zH7Q=D76^^xGnmr|Njkbz%v}zTTSrNwK>k>&r=zZ<*>^Ih>@||S8}33B^!`}10b~&` zpsS*t3_|(~_4(DL_Ne$ce>I;$$Cx$zuW=nWk6!(J-GM2wSg7QFHPh9eRLI1hN-*8Q zGs&K=+?XIsr+;`AlsIxC43gvHBOUesTatjH7=iveT$);hx(+!Arfh+m7{qTivUSSb zTjZpOm$~3A3U1c8P4m3J84lx}2t5|zpS(t|{7ds1U5Ru-qQl$Ep_7=nj>NVg{IE!Q z@a$PJ;d9fG01w<=#T73Iq1Ncpvx)XaSy%rc!~(eKX9)i)isNWp3EhBlmi#D?(6GU< zJ<~yvNE)uF*~ijn&&wLU5;-=X1Z)(8!gRTuoK(0773`qQs>olYu56`^6e7e=D1x;( zrnZWlC;=Ea$@gHuh9Hf2z~zk&UYG`;5;CR`%MIW{>O9dBASVv{-b=0SltT?M@=bgr z0?b7|^zc<}c)J;}`~tfG6djz0bR(#v8{Y!IOn?WJI`%?h^Zw1p^%t^qfVV7% z?MZ8iTYueS5T%cB(igIqop%P0FPSN!19OjVLG*ihTVxEUF9|QCCHpT4J#pqs)hGm! zmW-GYXi0lA%n9u%FW-4QcQnf){3{KqI%SYa~`Ndx3hZ*uh3(J(C zf)~+O_i_$zV}lb(MV+SfY??k(%wb-#KP9b{9KXJx->|cO~y0}v^BgU!KjHPs|onB-1n>dEid~W>afmgOR>Z1t2<`0 z*un++MR4HT0Z9k4))lm^4-pglo(~X(4ZcacPZ{YbNk!JHSyto%MDKFf1ri!*$5uyp zKCJn$ToHwZB=AChS1y8+RNMK_F0xQrIfr+-m>!2d;~2o={)m%z!pW zP+ujDo@S1mCXY|cFi{X_73PV)uvL5{pl7WlZ!)Pc-rq--j9JgueL_!lZwl}1{dAQ% zT@>cI3KItSBx;H+WpXt_wx*Lw8Rn<&mWUhlIM|#7_IOSJ3jh&hGev{l1uwPfzuu<$ zyAqoomR)lOqEAwI-7D67`$sC4wU}yeqfw5TYiD)W%I==SV(Mu>6hQq|E8bGj*algi zh_Oj~`hyk)tcbEFO640P(l>d}b88c_!8^&hs{#f!PTq97SVzV%K(%6U8nO$Z@*I>} zS(w$pdP4QrFr=k2gMpDc@t5;;c=pF7iASBTVs!5>`kygKq3GzX=&;(JGEiTQYye z=id8#P0(r>c)bf9F}RVkXWBbN;d~uId3QkPfLCH!e0eUBQ1SgzgZ>NWtHTk#^Sho_ z#LeqrD4$u$g2QV~6SFL?PX?#LtYzVZ%+_C#G$i#VSVJ)GP^%sUItd|eA{%0&t3kJP z`^A)FRCK$jWiVTw+0l@|LN*znl}7UCBSJdN_MUpQA~9sOhTkoG{C{r0_yu& z(vOk`U1p6z9`{*ag&rAt3@p9TdbOCjsn5$QKJ?ixM4~>+=Z!iyc?Li~2Z8LHFJ)WLSM3qMG?)eLzO40h zz7xvXS0_#E$}Dg4hE}nyNdHA2u3x;x drO^K6mM}P0xV$DFHT(a=DaxwJ)JR!G{BJSciA?|i literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 0d13dc75f0..bbd419574b 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,8 @@ | 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | | 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | +![功能图](/img/common/system-feature.png) + ### 工作流程 | | 功能 | 描述 | @@ -174,6 +176,8 @@ | 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 | | 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 | +![功能图](/img/common/bpm-feature.png) + ### 支付系统 | | 功能 | 描述 | @@ -209,6 +213,8 @@ | 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | | 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | +![功能图](/img/common/infra-feature.png) + ### 数据报表 | | 功能 | 描述 | From ba541fba8347329387d7ec97ed662f736d937b24 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 27 Mar 2024 21:06:06 +0800 Subject: [PATCH 33/33] =?UTF-8?q?README=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=9B=BE=EF=BC=8C=E6=96=B9=E4=BE=BF=E7=90=86?= =?UTF-8?q?=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bbd419574b..4787c4d4f0 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ | 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | | 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | -![功能图](/img/common/system-feature.png) +![功能图](/.image/common/system-feature.png) ### 工作流程 @@ -176,7 +176,7 @@ | 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 | | 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 | -![功能图](/img/common/bpm-feature.png) +![功能图](/.image/common/bpm-feature.png) ### 支付系统 @@ -213,7 +213,7 @@ | 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | | 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | -![功能图](/img/common/infra-feature.png) +![功能图](/.image/common/infra-feature.png) ### 数据报表