BPM:新增【流程实例】菜单,用于全部流程实例的查询

This commit is contained in:
YunaiV 2024-03-22 08:26:19 +08:00
parent e5444c5d47
commit ba4b3701bf
13 changed files with 97 additions and 38 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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<PageResult<BpmProcessInstanceRespVO>> getMyProcessInstancePage(
@Valid BpmProcessInstanceMyPageReqVO pageReqVO) {
PageResult<HistoricProcessInstance> pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO);
public CommonResult<PageResult<BpmProcessInstanceRespVO>> getProcessInstanceMyPage(
@Valid BpmProcessInstancePageReqVO pageReqVO) {
PageResult<HistoricProcessInstance> 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<String, BpmCategoryDO> 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<PageResult<BpmProcessInstanceRespVO>> getProcessInstanceManagerPage(
@Valid BpmProcessInstancePageReqVO pageReqVO) {
PageResult<HistoricProcessInstance> pageResult = processInstanceService.getProcessInstancePage(
null, pageReqVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
// 拼接返回
Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(
convertList(pageResult.getList(), HistoricProcessInstance::getId));
Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap(
convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap(
convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
// 发起人信息
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId())));
Map<Long, DeptRespDTO> 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<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO);
public CommonResult<Boolean> 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<Boolean> cancelProcessInstanceByManager(
@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
processInstanceService.cancelProcessInstanceByAdmin(getLoginUserId(), cancelReqVO);
return success(true);
}

View File

@ -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; // 注意只有在流程实例菜单才使用该参数
}

View File

@ -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<String, Object> formVariables;

View File

@ -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")

View File

@ -36,10 +36,12 @@ public interface BpmProcessInstanceConvert {
BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
default PageResult<BpmProcessInstanceRespVO> buildMyProcessInstancePage(PageResult<HistoricProcessInstance> pageResult,
Map<String, ProcessDefinition> processDefinitionMap,
Map<String, BpmCategoryDO> categoryMap,
Map<String, List<Task>> taskMap) {
default PageResult<BpmProcessInstanceRespVO> buildProcessInstancePage(PageResult<HistoricProcessInstance> pageResult,
Map<String, ProcessDefinition> processDefinitionMap,
Map<String, BpmCategoryDO> categoryMap,
Map<String, List<Task>> taskMap,
Map<Long, AdminUserRespDTO> userMap,
Map<Long, DeptRespDTO> deptMap) {
PageResult<BpmProcessInstanceRespVO> 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;
}

View File

@ -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));
});

View File

@ -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);
}
}

View File

@ -14,7 +14,7 @@ import jakarta.validation.Valid;
*/
@AllArgsConstructor
@Validated
public class BpmProcessInstanceResultEventPublisher {
public class BpmProcessInstanceEventPublisher {
private final ApplicationEventPublisher publisher;

View File

@ -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<HistoricProcessInstance> getMyProcessInstancePage(Long userId,
@Valid BpmProcessInstanceMyPageReqVO pageReqVO);
PageResult<HistoricProcessInstance> 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 拓展记录为取消

View File

@ -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 添加理由所以无法存储具体的取消理由
}