Commit 7967a2a195f93e153e320ac08176dfa2e1298254
1 parent
a1defeb4
BPM:流程实例的 `status` 状态实现,使用 Flowable 的 `variables` 存储,移除 `bpm_process_instance_ext` 表
Showing
17 changed files
with
150 additions
and
242 deletions
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; |
| 4 | 4 | import lombok.Getter; |
| 5 | 5 | |
| 6 | 6 | /** |
| 7 | - * 流程实例的状态 | |
| 7 | + * 流程实例 ProcessInstance 的状态 | |
| 8 | 8 | * |
| 9 | 9 | * @author 芋道源码 |
| 10 | 10 | */ |
| ... | ... | @@ -13,7 +13,9 @@ import lombok.Getter; |
| 13 | 13 | public enum BpmProcessInstanceStatusEnum { |
| 14 | 14 | |
| 15 | 15 | RUNNING(1, "进行中"), |
| 16 | - FINISH(2, "已完成"); | |
| 16 | + APPROVE(2, "通过"), | |
| 17 | + REJECT(3, "不通过"), | |
| 18 | + CANCEL(4, "已取消"); | |
| 17 | 19 | |
| 18 | 20 | /** |
| 19 | 21 | * 状态 | ... | ... |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusOldEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.enums.task; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 流程实例的状态 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +@Deprecated | |
| 12 | +@Getter | |
| 13 | +@AllArgsConstructor | |
| 14 | +public enum BpmProcessInstanceStatusOldEnum { | |
| 15 | + | |
| 16 | + RUNNING(1, "进行中"), | |
| 17 | + FINISH(2, "已完成"); | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 状态 | |
| 21 | + */ | |
| 22 | + private final Integer status; | |
| 23 | + /** | |
| 24 | + * 描述 | |
| 25 | + */ | |
| 26 | + private final String desc; | |
| 27 | + | |
| 28 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import jakarta.validation.constraints.NotNull; | |
| 5 | -import lombok.Data; | |
| 6 | - | |
| 7 | -import java.util.Set; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 11 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 12 | - */ | |
| 13 | -@Data | |
| 14 | -public class BpmTaskCandidateRuleVO { | |
| 15 | - | |
| 16 | - @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type") | |
| 17 | - @NotNull(message = "规则类型不能为空") | |
| 18 | - private Integer type; | |
| 19 | - | |
| 20 | - @Schema(description = "规则值数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") | |
| 21 | - @NotNull(message = "规则值数组不能为空") | |
| 22 | - private Set<Long> options; | |
| 23 | - | |
| 24 | -} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.controller.admin.task; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; |
| 7 | +import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; | |
| 8 | +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; | |
| 6 | 9 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 10 | +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; | |
| 7 | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 8 | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 9 | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 10 | 14 | import jakarta.annotation.Resource; |
| 11 | 15 | import jakarta.validation.Valid; |
| 16 | +import org.flowable.engine.history.HistoricProcessInstance; | |
| 17 | +import org.flowable.engine.repository.ProcessDefinition; | |
| 18 | +import org.flowable.task.api.Task; | |
| 12 | 19 | import org.springframework.security.access.prepost.PreAuthorize; |
| 13 | 20 | import org.springframework.validation.annotation.Validated; |
| 14 | 21 | import org.springframework.web.bind.annotation.*; |
| 15 | 22 | |
| 23 | +import java.util.List; | |
| 24 | +import java.util.Map; | |
| 25 | + | |
| 16 | 26 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 27 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 28 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 17 | 29 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 18 | 30 | |
| 19 | 31 | @Tag(name = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” |
| ... | ... | @@ -24,13 +36,27 @@ public class BpmProcessInstanceController { |
| 24 | 36 | |
| 25 | 37 | @Resource |
| 26 | 38 | private BpmProcessInstanceService processInstanceService; |
| 39 | + @Resource | |
| 40 | + private BpmTaskService taskService; | |
| 41 | + @Resource | |
| 42 | + private BpmProcessDefinitionService processDefinitionService; | |
| 27 | 43 | |
| 28 | 44 | @GetMapping("/my-page") |
| 29 | 45 | @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") |
| 30 | 46 | @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") |
| 31 | 47 | public CommonResult<PageResult<BpmProcessInstancePageItemRespVO>> getMyProcessInstancePage( |
| 32 | 48 | @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { |
| 33 | - return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO)); | |
| 49 | + PageResult<HistoricProcessInstance> pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO); | |
| 50 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 51 | + return success(PageResult.empty(pageResult.getTotal())); | |
| 52 | + } | |
| 53 | + | |
| 54 | + // 拼接返回 | |
| 55 | + Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds( | |
| 56 | + convertList(pageResult.getList(), HistoricProcessInstance::getId)); | |
| 57 | + Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap( | |
| 58 | + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); | |
| 59 | + return success(BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, processDefinitionMap, taskMap)); | |
| 34 | 60 | } |
| 35 | 61 | |
| 36 | 62 | @PostMapping("/create") | ... | ... |
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 { |
| 23 | 23 | private String category; |
| 24 | 24 | |
| 25 | 25 | @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 26 | - private Integer status; | |
| 27 | - | |
| 28 | - @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 29 | - private Integer result; | |
| 26 | + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 | |
| 30 | 27 | |
| 31 | 28 | @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 32 | - private LocalDateTime createTime; | |
| 29 | + private LocalDateTime startTime; | |
| 33 | 30 | |
| 34 | 31 | @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 35 | 32 | private LocalDateTime endTime; | ... | ... |
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 { |
| 20 | 20 | @Schema(description = "流程分类-参见 bpm_model_category 数据字典", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 21 | 21 | private String category; |
| 22 | 22 | |
| 23 | - @Schema(description = "流程实例的状态-参见 bpm_process_instance_status", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 24 | - private Integer status; | |
| 23 | + @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 24 | + private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 | |
| 25 | 25 | |
| 26 | 26 | @Schema(description = "流程实例的结果-参见 bpm_process_instance_result", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 27 | 27 | private Integer result; | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.convert.task; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | 8 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; |
| 7 | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; |
| 8 | 10 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; |
| 9 | -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; | |
| 10 | 11 | import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; |
| 12 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; | |
| 11 | 13 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; |
| 12 | 14 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; |
| 13 | 15 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| ... | ... | @@ -34,25 +36,26 @@ public interface BpmProcessInstanceConvert { |
| 34 | 36 | |
| 35 | 37 | BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); |
| 36 | 38 | |
| 37 | - default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<BpmProcessInstanceExtDO> page, | |
| 39 | + default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<HistoricProcessInstance> pageResult, | |
| 40 | + Map<String, ProcessDefinition> processDefinitionMap, | |
| 38 | 41 | Map<String, List<Task>> taskMap) { |
| 39 | - List<BpmProcessInstancePageItemRespVO> list = convertList(page.getList()); | |
| 40 | - list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId())))); | |
| 41 | - return new PageResult<>(list, page.getTotal()); | |
| 42 | + PageResult<BpmProcessInstancePageItemRespVO> vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstancePageItemRespVO.class); | |
| 43 | + for (int i = 0; i < pageResult.getList().size(); i++) { | |
| 44 | + BpmProcessInstancePageItemRespVO respVO = vpPageResult.getList().get(i); | |
| 45 | + respVO.setStatus((Integer) pageResult.getList().get(i).getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); | |
| 46 | + MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(), | |
| 47 | + processDefinition -> respVO.setCategory(processDefinition.getCategory())); | |
| 48 | + respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstancePageItemRespVO.Task.class)); | |
| 49 | + } | |
| 50 | + return vpPageResult; | |
| 42 | 51 | } |
| 43 | 52 | |
| 44 | - List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list); | |
| 45 | - | |
| 46 | - @Mapping(source = "processInstanceId", target = "id") | |
| 47 | - BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean); | |
| 48 | - | |
| 49 | - List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks); | |
| 50 | - | |
| 51 | - default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt, | |
| 53 | + default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, | |
| 52 | 54 | ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt, |
| 53 | 55 | String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { |
| 54 | 56 | BpmProcessInstanceRespVO respVO = convert2(processInstance); |
| 55 | - copyTo(processInstanceExt, respVO); | |
| 57 | + respVO.setStatus((Integer) processInstance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS)); | |
| 58 | + respVO.setFormVariables(processInstance.getProcessVariables()); // TODO 芋艿:真的这么搞么???formVariable 要不要换个 key 之类的 | |
| 56 | 59 | // definition |
| 57 | 60 | respVO.setProcessDefinition(convert2(processDefinition)); |
| 58 | 61 | copyTo(processDefinitionExt, respVO.getProcessDefinition()); |
| ... | ... | @@ -69,9 +72,6 @@ public interface BpmProcessInstanceConvert { |
| 69 | 72 | |
| 70 | 73 | BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean); |
| 71 | 74 | |
| 72 | - @Mapping(source = "from.id", target = "to.id", ignore = true) | |
| 73 | - void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to); | |
| 74 | - | |
| 75 | 75 | BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); |
| 76 | 76 | |
| 77 | 77 | @Mapping(source = "from.id", target = "to.id", ignore = true) |
| ... | ... | @@ -88,6 +88,7 @@ public interface BpmProcessInstanceConvert { |
| 88 | 88 | return event; |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | + // TODO @芋艿:需要改下 key! | |
| 91 | 92 | default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { |
| 92 | 93 | BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); |
| 93 | 94 | event.setId(instance.getId()); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.dal.dataobject.task; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; | |
| 5 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; | |
| 6 | -import com.baomidou.mybatisplus.annotation.TableField; | |
| 7 | -import com.baomidou.mybatisplus.annotation.TableId; | |
| 8 | -import com.baomidou.mybatisplus.annotation.TableName; | |
| 9 | -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | |
| 10 | -import lombok.Data; | |
| 11 | -import lombok.EqualsAndHashCode; | |
| 12 | -import lombok.ToString; | |
| 13 | - | |
| 14 | -import java.time.LocalDateTime; | |
| 15 | -import java.util.List; | |
| 16 | -import java.util.Map; | |
| 17 | - | |
| 18 | -/** | |
| 19 | - * Bpm 流程实例的拓展表 | |
| 20 | - * 主要解决 Activiti ProcessInstance 和 HistoricProcessInstance 不支持拓展字段,所以新建拓展表 | |
| 21 | - * | |
| 22 | - * @author 芋道源码 | |
| 23 | - */ | |
| 24 | -@TableName(value = "bpm_process_instance_ext", autoResultMap = true) | |
| 25 | -@Data | |
| 26 | -@EqualsAndHashCode(callSuper = true) | |
| 27 | -@ToString(callSuper = true) | |
| 28 | -public class BpmProcessInstanceExtDO extends BaseDO { | |
| 29 | - | |
| 30 | - /** | |
| 31 | - * 编号,自增 | |
| 32 | - */ | |
| 33 | - @TableId | |
| 34 | - private Long id; | |
| 35 | - /** | |
| 36 | - * 发起流程的用户编号 | |
| 37 | - * | |
| 38 | - * 冗余 HistoricProcessInstance 的 startUserId 属性 | |
| 39 | - */ | |
| 40 | - private Long startUserId; | |
| 41 | - /** | |
| 42 | - * 流程实例的名字 | |
| 43 | - * | |
| 44 | - * 冗余 ProcessInstance 的 name 属性,用于筛选 | |
| 45 | - */ | |
| 46 | - private String name; | |
| 47 | - /** | |
| 48 | - * 流程实例的编号 | |
| 49 | - * | |
| 50 | - * 关联 ProcessInstance 的 id 属性 | |
| 51 | - */ | |
| 52 | - private String processInstanceId; | |
| 53 | - /** | |
| 54 | - * 流程定义的编号 | |
| 55 | - * | |
| 56 | - * 关联 ProcessDefinition 的 id 属性 | |
| 57 | - */ | |
| 58 | - private String processDefinitionId; | |
| 59 | - /** | |
| 60 | - * 流程分类 | |
| 61 | - * | |
| 62 | - * 冗余 ProcessDefinition 的 category 属性 | |
| 63 | - * 数据字典 bpm_model_category | |
| 64 | - */ | |
| 65 | - private String category; | |
| 66 | - /** | |
| 67 | - * 流程实例的状态 | |
| 68 | - * | |
| 69 | - * 枚举 {@link BpmProcessInstanceStatusEnum} | |
| 70 | - */ | |
| 71 | - private Integer status; | |
| 72 | - /** | |
| 73 | - * 流程实例的结果 | |
| 74 | - * | |
| 75 | - * 枚举 {@link BpmProcessInstanceResultEnum} | |
| 76 | - */ | |
| 77 | - private Integer result; | |
| 78 | - /** | |
| 79 | - * 结束时间 | |
| 80 | - * | |
| 81 | - * 冗余 HistoricProcessInstance 的 endTime 属性 | |
| 82 | - */ | |
| 83 | - private LocalDateTime endTime; | |
| 84 | - | |
| 85 | - /** | |
| 86 | - * 提交的表单值 | |
| 87 | - */ | |
| 88 | - @TableField(typeHandler = JacksonTypeHandler.class) | |
| 89 | - private Map<String, Object> formVariables; | |
| 90 | - | |
| 91 | - // TODO @hai:assignees 复数 | |
| 92 | - /** | |
| 93 | - * 提前设定好的审批人 | |
| 94 | - */ | |
| 95 | - @TableField(typeHandler = JacksonTypeHandler.class, exist = false) // TODO 芋艿:临时 exist = false,避免 db 报错; | |
| 96 | - private Map<String, List<Long>> assignee; | |
| 97 | - | |
| 98 | -} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.dal.mysql.task; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; | |
| 7 | -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; | |
| 8 | -import org.apache.ibatis.annotations.Mapper; | |
| 9 | - | |
| 10 | -@Mapper | |
| 11 | -public interface BpmProcessInstanceExtMapper extends BaseMapperX<BpmProcessInstanceExtDO> { | |
| 12 | - | |
| 13 | - default PageResult<BpmProcessInstanceExtDO> selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) { | |
| 14 | - return selectPage(reqVO, new LambdaQueryWrapperX<BpmProcessInstanceExtDO>() | |
| 15 | - .eqIfPresent(BpmProcessInstanceExtDO::getStartUserId, userId) | |
| 16 | - .likeIfPresent(BpmProcessInstanceExtDO::getName, reqVO.getName()) | |
| 17 | - .eqIfPresent(BpmProcessInstanceExtDO::getProcessDefinitionId, reqVO.getProcessDefinitionId()) | |
| 18 | - .eqIfPresent(BpmProcessInstanceExtDO::getCategory, reqVO.getCategory()) | |
| 19 | - .eqIfPresent(BpmProcessInstanceExtDO::getStatus, reqVO.getStatus()) | |
| 20 | - .eqIfPresent(BpmProcessInstanceExtDO::getResult, reqVO.getResult()) | |
| 21 | - .betweenIfPresent(BpmProcessInstanceExtDO::getCreateTime, reqVO.getCreateTime()) | |
| 22 | - .orderByDesc(BpmProcessInstanceExtDO::getId)); | |
| 23 | - } | |
| 24 | - | |
| 25 | - default BpmProcessInstanceExtDO selectByProcessInstanceId(String processInstanceId) { | |
| 26 | - return selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, processInstanceId); | |
| 27 | - } | |
| 28 | - | |
| 29 | - default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) { | |
| 30 | - update(updateObj, new LambdaQueryWrapperX<BpmProcessInstanceExtDO>() | |
| 31 | - .eq(BpmProcessInstanceExtDO::getProcessInstanceId, updateObj.getProcessInstanceId())); | |
| 32 | - } | |
| 33 | - | |
| 34 | -} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmConstants.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; | |
| 2 | + | |
| 3 | +import org.flowable.engine.runtime.ProcessInstance; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * BPM 通用常量 | |
| 7 | + * | |
| 8 | + * @author 芋道源码 | |
| 9 | + */ | |
| 10 | +public class BpmConstants { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * 流程实例的变量 - 状态 | |
| 14 | + * | |
| 15 | + * @see ProcessInstance#getProcessVariables() | |
| 16 | + */ | |
| 17 | + public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS"; | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; | |
| 4 | 3 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 5 | 4 | import com.google.common.collect.ImmutableSet; |
| 5 | +import jakarta.annotation.Resource; | |
| 6 | 6 | import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; |
| 7 | 7 | import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; |
| 8 | 8 | import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; |
| ... | ... | @@ -11,11 +11,10 @@ import org.flowable.engine.runtime.ProcessInstance; |
| 11 | 11 | import org.springframework.context.annotation.Lazy; |
| 12 | 12 | import org.springframework.stereotype.Component; |
| 13 | 13 | |
| 14 | -import jakarta.annotation.Resource; | |
| 15 | 14 | import java.util.Set; |
| 16 | 15 | |
| 17 | 16 | /** |
| 18 | - * 监听 {@link ProcessInstance} 的开始与完成,创建与更新对应的 {@link BpmProcessInstanceExtDO} 记录 | |
| 17 | + * 监听 {@link ProcessInstance} 的状态变更,更新其对应的 status 状态 | |
| 19 | 18 | * |
| 20 | 19 | * @author jason |
| 21 | 20 | */ |
| ... | ... | @@ -27,7 +26,6 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent |
| 27 | 26 | private BpmProcessInstanceService processInstanceService; |
| 28 | 27 | |
| 29 | 28 | public static final Set<FlowableEngineEventType> PROCESS_INSTANCE_EVENTS = ImmutableSet.<FlowableEngineEventType>builder() |
| 30 | - .add(FlowableEngineEventType.PROCESS_CREATED) | |
| 31 | 29 | .add(FlowableEngineEventType.PROCESS_CANCELLED) |
| 32 | 30 | .add(FlowableEngineEventType.PROCESS_COMPLETED) |
| 33 | 31 | .build(); |
| ... | ... | @@ -37,11 +35,6 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent |
| 37 | 35 | } |
| 38 | 36 | |
| 39 | 37 | @Override |
| 40 | - protected void processCreated(FlowableEngineEntityEvent event) { | |
| 41 | - processInstanceService.createProcessInstanceExt((ProcessInstance)event.getEntity()); | |
| 42 | - } | |
| 43 | - | |
| 44 | - @Override | |
| 45 | 38 | protected void processCancelled(FlowableCancelledEvent event) { |
| 46 | 39 | processInstanceService.updateProcessInstanceExtCancel(event); |
| 47 | 40 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.service.definition; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | 4 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; |
| 6 | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; |
| 7 | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; |
| 8 | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; |
| 9 | 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; |
| 10 | 9 | import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; |
| 10 | +import jakarta.validation.Valid; | |
| 11 | 11 | import org.flowable.bpmn.model.BpmnModel; |
| 12 | 12 | import org.flowable.engine.repository.Deployment; |
| 13 | 13 | import org.flowable.engine.repository.ProcessDefinition; |
| 14 | 14 | |
| 15 | -import jakarta.validation.Valid; | |
| 16 | 15 | import java.util.List; |
| 17 | 16 | import java.util.Map; |
| 18 | 17 | import java.util.Set; |
| 18 | + | |
| 19 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 20 | + | |
| 19 | 21 | /** |
| 20 | 22 | * Flowable流程定义接口 |
| 21 | 23 | * |
| ... | ... | @@ -90,14 +92,16 @@ public interface BpmProcessDefinitionService { |
| 90 | 92 | ProcessDefinition getProcessDefinition(String id); |
| 91 | 93 | |
| 92 | 94 | /** |
| 93 | - * 获得编号对应的 ProcessDefinition | |
| 94 | - * | |
| 95 | - * 相比 {@link #getProcessDefinition(String)} 方法,category 的取值是正确 | |
| 95 | + * 获得 ids 对应的 ProcessDefinition 数组 | |
| 96 | 96 | * |
| 97 | - * @param id 编号 | |
| 98 | - * @return 流程定义 | |
| 97 | + * @param ids 编号的数组 | |
| 98 | + * @return 流程定义的数组 | |
| 99 | 99 | */ |
| 100 | - ProcessDefinition getProcessDefinition2(String id); | |
| 100 | + List<ProcessDefinition> getProcessDefinitionList(Set<String> ids); | |
| 101 | + | |
| 102 | + default Map<String, ProcessDefinition> getProcessDefinitionMap(Set<String> ids) { | |
| 103 | + return convertMap(getProcessDefinitionList(ids), ProcessDefinition::getId); | |
| 104 | + } | |
| 101 | 105 | |
| 102 | 106 | /** |
| 103 | 107 | * 获得 deploymentId 对应的 ProcessDefinition |
| ... | ... | @@ -130,7 +134,7 @@ public interface BpmProcessDefinitionService { |
| 130 | 134 | * @return 流程部署 Map |
| 131 | 135 | */ |
| 132 | 136 | default Map<String, Deployment> getDeploymentMap(Set<String> ids) { |
| 133 | - return CollectionUtils.convertMap(getDeployments(ids), Deployment::getId); | |
| 137 | + return convertMap(getDeployments(ids), Deployment::getId); | |
| 134 | 138 | } |
| 135 | 139 | |
| 136 | 140 | /** | ... | ... |
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 |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | @Override |
| 69 | - public ProcessDefinition getProcessDefinition2(String id) { | |
| 70 | - return repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult(); | |
| 69 | + public List<ProcessDefinition> getProcessDefinitionList(Set<String> ids) { | |
| 70 | + return repositoryService.createProcessDefinitionQuery().processDefinitionIds(ids).list(); | |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | 73 | @Override | ... | ... |
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; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | 5 | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| 6 | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; |
| 7 | +import jakarta.validation.Valid; | |
| 7 | 8 | import org.flowable.engine.delegate.event.FlowableCancelledEvent; |
| 8 | 9 | import org.flowable.engine.history.HistoricProcessInstance; |
| 9 | 10 | import org.flowable.engine.runtime.ProcessInstance; |
| 10 | 11 | |
| 11 | -import jakarta.validation.Valid; | |
| 12 | 12 | import java.util.List; |
| 13 | 13 | import java.util.Map; |
| 14 | 14 | import java.util.Set; |
| ... | ... | @@ -58,14 +58,40 @@ public interface BpmProcessInstanceService { |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | /** |
| 61 | + * 获得历史的流程实例 | |
| 62 | + * | |
| 63 | + * @param id 流程实例的编号 | |
| 64 | + * @return 历史的流程实例 | |
| 65 | + */ | |
| 66 | + HistoricProcessInstance getHistoricProcessInstance(String id); | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * 获得历史的流程实例列表 | |
| 70 | + * | |
| 71 | + * @param ids 流程实例的编号集合 | |
| 72 | + * @return 历史的流程实例列表 | |
| 73 | + */ | |
| 74 | + List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids); | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 获得历史的流程实例 Map | |
| 78 | + * | |
| 79 | + * @param ids 流程实例的编号集合 | |
| 80 | + * @return 历史的流程实例列表 Map | |
| 81 | + */ | |
| 82 | + default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) { | |
| 83 | + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 61 | 87 | * 获得流程实例的分页 |
| 62 | 88 | * |
| 63 | 89 | * @param userId 用户编号 |
| 64 | 90 | * @param pageReqVO 分页请求 |
| 65 | 91 | * @return 流程实例的分页 |
| 66 | 92 | */ |
| 67 | - PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, | |
| 68 | - @Valid BpmProcessInstanceMyPageReqVO pageReqVO); | |
| 93 | + PageResult<HistoricProcessInstance> getMyProcessInstancePage(Long userId, | |
| 94 | + @Valid BpmProcessInstanceMyPageReqVO pageReqVO); | |
| 69 | 95 | |
| 70 | 96 | /** |
| 71 | 97 | * 创建流程实例(提供给前端) |
| ... | ... | @@ -102,39 +128,6 @@ public interface BpmProcessInstanceService { |
| 102 | 128 | void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); |
| 103 | 129 | |
| 104 | 130 | /** |
| 105 | - * 获得历史的流程实例 | |
| 106 | - * | |
| 107 | - * @param id 流程实例的编号 | |
| 108 | - * @return 历史的流程实例 | |
| 109 | - */ | |
| 110 | - HistoricProcessInstance getHistoricProcessInstance(String id); | |
| 111 | - | |
| 112 | - /** | |
| 113 | - * 获得历史的流程实例列表 | |
| 114 | - * | |
| 115 | - * @param ids 流程实例的编号集合 | |
| 116 | - * @return 历史的流程实例列表 | |
| 117 | - */ | |
| 118 | - List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids); | |
| 119 | - | |
| 120 | - /** | |
| 121 | - * 获得历史的流程实例 Map | |
| 122 | - * | |
| 123 | - * @param ids 流程实例的编号集合 | |
| 124 | - * @return 历史的流程实例列表 Map | |
| 125 | - */ | |
| 126 | - default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) { | |
| 127 | - return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); | |
| 128 | - } | |
| 129 | - | |
| 130 | - /** | |
| 131 | - * 创建 ProcessInstance 拓展记录 | |
| 132 | - * | |
| 133 | - * @param instance 流程任务 | |
| 134 | - */ | |
| 135 | - void createProcessInstanceExt(ProcessInstance instance); | |
| 136 | - | |
| 137 | - /** | |
| 138 | 131 | * 更新 ProcessInstance 拓展记录为取消 |
| 139 | 132 | * |
| 140 | 133 | * @param event 流程取消事件 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| 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 实现类 * <p> * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * <p> * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * <p> * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @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<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> 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<HistoricProcessInstance> getHistoricProcessInstances(Set<String> 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<String, Object> variables, String businessKey, Map<String, List<Long>> 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<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> 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(); } } | |
| 2 | 1 | \ No newline at end of file |
| 2 | +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. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @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<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> 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<HistoricProcessInstance> 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<String, Object> variables, String businessKey, Map<String, List<Long>> 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<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> 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(); } } | |
| 3 | 3 | \ No newline at end of file | ... | ... |