仿钉钉流程设计- 增加流程进度接口第一版 (用于查询审批记录)

This commit is contained in:
jason 2024-09-01 23:12:04 +08:00
parent ff6bee964b
commit f03e26bc86
26 changed files with 590 additions and 39 deletions

View File

@ -4,3 +4,8 @@
ALTER TABLE `pro-test`.`bpm_process_instance_copy`
ADD COLUMN `activity_id` varchar(64) NULL COMMENT '流程活动编号' AFTER `category`,
MODIFY COLUMN `task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务编号' AFTER `category`;
ALTER TABLE `pro-test`.`bpm_process_definition_info`
ADD COLUMN `model_type` tinyint NOT NULL DEFAULT 10 COMMENT '流程模型的类型' AFTER `model_id`,
ADD COLUMN `simple_model` json NULL COMMENT 'SIMPLE 设计器模型数据' AFTER `form_custom_view_path`,
ADD COLUMN `visible` bit(1) NOT NULL DEFAULT 1 COMMENT '是否可见' AFTER `simple_model`;

View File

@ -0,0 +1,67 @@
package cn.iocoder.yudao.module.bpm.enums.definition;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 流程节点进度的枚举
*
* @author jason
*/
@Getter
@AllArgsConstructor
public enum BpmProcessNodeProgressEnum {
// 0 未开始
NOT_START(0,"未开始"),
// 1 ~ 20 进行中
RUNNING(1, "进行中"), // 节点的进行
// 特殊的进行中状态
USER_TASK_DELEGATE(10, "委派中"), // 审批节点
USER_TASK_APPROVING(11, "向后加签审批通过中"), //向后加签 审批通过中.
USER_TASK_WAIT(12, "待审批"), // 一般用于先前加签
// 30 ~ 50 已经结束
// 30 ~ 40 审批节点的结束状态
USER_TASK_APPROVE(30, "审批通过"), // 审批节点
USER_TASK_REJECT(31, "审批不通过"), // 审批节点
USER_TASK_RETURN(32, "已退回"), // 审批节点
USER_TASK_CANCEL(34, "已取消"), // 审批节点
// 40 ~ 50 一般节点的接榫状态
FINISHED(41, "已结束"), // 一般节点的节点的结束状态
SKIP(42, "跳过"); // 未执行跳过的节点
private final Integer status;
private final String name;
public static Integer convertBpmnTaskStatus(Integer taskStatus) {
Integer convertStatus = null;
if (BpmTaskStatusEnum.RUNNING.getStatus().equals(taskStatus)) {
convertStatus = RUNNING.getStatus();
} else if (BpmTaskStatusEnum.REJECT.getStatus().equals(taskStatus)) {
convertStatus = USER_TASK_REJECT.getStatus();
} else if( BpmTaskStatusEnum.APPROVE.getStatus().equals(taskStatus) ) {
convertStatus = USER_TASK_APPROVE.getStatus();
} else if (BpmTaskStatusEnum.DELEGATE.getStatus().equals(taskStatus)) {
convertStatus = USER_TASK_DELEGATE.getStatus();
} else if (BpmTaskStatusEnum.APPROVING.getStatus().equals(taskStatus)) {
convertStatus = USER_TASK_APPROVE.getStatus();
} else if (BpmTaskStatusEnum.CANCEL.getStatus().equals(taskStatus)) {
convertStatus = USER_TASK_CANCEL.getStatus();
} else if (BpmTaskStatusEnum.WAIT.getStatus().equals(taskStatus)) {
convertStatus = USER_TASK_WAIT.getStatus();
}
return convertStatus;
}
/**
* 判断用户节点是不是未通过
*
* @param status 状态
*/
public static boolean isUserTaskNotApproved(Integer status) {
return ObjectUtils.equalsAny(status,
USER_TASK_REJECT.getStatus(), USER_TASK_RETURN.getStatus(), USER_TASK_CANCEL.getStatus());
}
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.enums.task;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -36,4 +37,9 @@ public enum BpmProcessInstanceStatusEnum implements IntArrayValuable {
return ARRAYS;
}
public static boolean isProcessEndStatus(Integer status) {
return ObjectUtils.equalsAny(status,
APPROVE.getStatus(), REJECT.getStatus(), CANCEL.getStatus());
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO;
import cn.iocoder.yudao.module.bpm.convert.task.BpmActivityConvert;
import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
@ -34,6 +35,6 @@ public class BpmActivityController {
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<List<BpmActivityRespVO>> getActivityList(
@RequestParam("processInstanceId") String processInstanceId) {
return success(activityService.getActivityListByProcessInstanceId(processInstanceId));
return success(BpmActivityConvert.INSTANCE.convertList(activityService.getActivityListByProcessInstanceId(processInstanceId)));
}
}

View File

@ -47,6 +47,7 @@ public class BpmProcessInstanceController {
private BpmProcessInstanceService processInstanceService;
@Resource
private BpmTaskService taskService;
@Resource
private BpmProcessDefinitionService processDefinitionService;
@Resource
@ -158,11 +159,19 @@ public class BpmProcessInstanceController {
}
@GetMapping("/get-form-fields-permission")
@Operation(summary = "获得流程实例表单字段权限", description = "在【我的流程】菜单中,进行调用")
@Operation(summary = "获得流程实例表单字段权限")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<Map<String, String>> getProcessInstanceFormFieldsPermission(
@Valid BpmProcessInstanceFormFieldsPermissionReqVO reqVO){
@Valid BpmProcessInstanceFormFieldsPermissionReqVO reqVO) {
return success(processInstanceService.getProcessInstanceFormFieldsPermission(reqVO));
}
@GetMapping("/get-progress")
@Operation(summary = "获得流程实例的进度")
@Parameter(name = "id", description = "流程实例的编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<BpmProcessInstanceProgressRespVO> getProcessInstanceProgress(@RequestParam("id") String id) {
return success(processInstanceService.getProcessInstanceProgress(id));
}
}

View File

@ -0,0 +1,60 @@
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;
@Schema(description = "管理后台 - 流程实例的进度 Response VO")
@Data
public class BpmProcessInstanceProgressRespVO {
@Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举
private List<ProcessNodeProgress> nodeProgressList;
@Schema(description = "节点进度信息")
@Data
public static class ProcessNodeProgress {
@Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartUserNode")
private String id; // Bpmn XML 节点 Id
@Schema(description = "节点名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "发起人")
private String name;
private String displayText;
@Schema(description = "节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer nodeType; // 参见 BpmSimpleModelNodeType 枚举
@Schema(description = "节点状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status; // 参见 BpmProcessNodeProgressEnum 枚举
@Schema(description = "节点的开始时间")
private LocalDateTime startTime;
@Schema(description = "节点的结束时间")
private LocalDateTime endTime;
@Schema(description = "用户列表")
private List<User> userList;
@Schema(description = "分支节点")
private List<ProcessNodeProgress> branchNodes; // 有且仅有条件并行包容节点才会有分支节点
// TODO 用户意见评论
}
@Schema(description = "用户信息")
@Data
public static class User {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
private String nickname;
@Schema(description = "用户头像", example = "芋艿")
private String avatar;
@Schema(description = "是否已处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean processed;
@Schema(description = "用户任务的处理状态", example = "1")
private Integer userTaskStatus;
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -48,7 +49,7 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
/**
* 流程模型的类型
*
* 枚举 {@link BpmModelFormTypeEnum}
* 枚举 {@link BpmModelTypeEnum}
*/
private Integer modelType;
@ -105,6 +106,12 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
*/
private String formCustomViewPath;
/**
* SIMPLE 设计器模型数据 json 格式
*
* 目的当使用仿钉钉设计器时流程模型发布的时候需要保存流程模型设计器的快照数据
*/
private String simpleModel;
/**
* 是否可见
*

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> {
@ -18,4 +20,7 @@ public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInst
.orderByDesc(BpmProcessInstanceCopyDO::getId));
}
default List<BpmProcessInstanceCopyDO> selectListByProcInstIdAndActId(String processInstanceId, String activityId) {
return selectList(BpmProcessInstanceCopyDO::getProcessInstanceId, processInstanceId, BpmProcessInstanceCopyDO::getActivityId, activityId);
}
}

View File

@ -150,7 +150,7 @@ public class BpmTaskCandidateInvoker {
assigneeUserIds.remove(Long.valueOf(processInstance.getStartUserId()));
}
private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
public BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);
BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum);

View File

@ -3,6 +3,7 @@ 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.Collections;
import java.util.Set;
/**
@ -36,6 +37,18 @@ public interface BpmTaskCandidateStrategy {
*/
Set<Long> calculateUsers(DelegateExecution execution, String param);
/**
* 基于流程实例获得任务的候选用户们 用于获取未执行节点的候选用户们
*
* @param processInstanceId 流程实例
* @param param 节点的参数
* @return 用户编号集合
*/
default Set<Long> calculateUsers(String processInstanceId, String param) {
return Collections.emptySet();
}
/**
* 是否一定要输入参数
*

View File

@ -41,6 +41,16 @@ public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrat
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
return calculateUsersByParam(param);
}
@Override
public Set<Long> calculateUsers(String processInstanceId, String param) {
return calculateUsersByParam(param);
}
private Set<Long> calculateUsersByParam(String param) {
Set<Long> deptIds = StrUtils.splitToLongSet(param);
List<AdminUserRespDTO> users = adminUserApi.getUserListByDeptIds(deptIds);
return convertSet(users, AdminUserRespDTO::getId);

View File

@ -37,6 +37,15 @@ public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy {
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
return calculateUsersByParam(param);
}
@Override
public Set<Long> calculateUsers(String processInstanceId, String param) {
return calculateUsersByParam(param);
}
private Set<Long> calculateUsersByParam(String param) {
Set<Long> roleIds = StrUtils.splitToLongSet(param);
return permissionApi.getUserRoleIdListByRoleIds(roleIds);
}

View File

@ -35,8 +35,7 @@ public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrate
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
String startUserId = processInstanceService.getProcessInstance(execution.getProcessInstanceId()).getStartUserId();
return SetUtils.asSet(Long.valueOf(startUserId));
return getStartUserOfProcessInstance(execution.getProcessInstanceId());
}
@Override
@ -44,4 +43,14 @@ public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrate
return false;
}
@Override
public Set<Long> calculateUsers(String processInstanceId, String param) {
return getStartUserOfProcessInstance(processInstanceId);
}
private Set<Long> getStartUserOfProcessInstance(String processInstanceId) {
String startUserId = processInstanceService.getProcessInstance(processInstanceId).getStartUserId();
return SetUtils.asSet(Long.valueOf(startUserId));
}
}

View File

@ -36,4 +36,9 @@ public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy {
return StrUtils.splitToLongSet(param);
}
@Override
public Set<Long> calculateUsers(String processInstanceId, String param) {
return StrUtils.splitToLongSet(param);
}
}

View File

@ -7,24 +7,30 @@ import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
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.spring.SpringUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.RejectHandler;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceProgressRespVO.ProcessNodeProgress;
import cn.iocoder.yudao.module.bpm.enums.definition.*;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simplemodel.SimpleModelConditionGroups;
import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.OperationButtonSetting;
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveMethodEnum.RANDOM;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveMethodEnum.RATIO;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveTypeEnum.USER;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum.REMINDER;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum.START_USER;
@ -361,7 +367,7 @@ public class SimpleModelUtils {
/**
* 添加 UserTask 用户的审批超时 BoundaryEvent 事件
*
* @param userTask 审批任务
* @param userTask 审批任务
* @param timeoutHandler 超时处理器
* @return BoundaryEvent 超时事件
*/
@ -463,7 +469,7 @@ public class SimpleModelUtils {
// 如果不是审批人节点则直接返回
addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, StrUtil.toStringOrNull(node.getApproveType()));
if (ObjectUtil.notEqual(node.getApproveType(), BpmUserTaskApproveTypeEnum.USER.getType())) {
if (ObjectUtil.notEqual(node.getApproveType(), USER.getType())) {
return userTask;
}
@ -513,7 +519,7 @@ public class SimpleModelUtils {
private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
BpmUserTaskApproveMethodEnum approveMethodEnum = BpmUserTaskApproveMethodEnum.valueOf(approveMethod);
if (approveMethodEnum == null || approveMethodEnum == BpmUserTaskApproveMethodEnum.RANDOM) {
if (approveMethodEnum == null || approveMethodEnum == RANDOM) {
return;
}
// 添加审批方式的扩展属性
@ -531,7 +537,7 @@ public class SimpleModelUtils {
multiInstanceCharacteristics.setSequential(true);
multiInstanceCharacteristics.setLoopCardinality("1");
userTask.setLoopCharacteristics(multiInstanceCharacteristics);
} else if (approveMethodEnum == BpmUserTaskApproveMethodEnum.RATIO) {
} else if (approveMethodEnum == RATIO) {
Assert.notNull(approveRatio, "通过比例不能为空");
multiInstanceCharacteristics.setCompletionCondition(
String.format(APPROVE_BY_RATIO_COMPLETE_EXPRESSION, String.format("%.2f", approveRatio / (double) 100)));
@ -607,9 +613,9 @@ public class SimpleModelUtils {
userTask.setId(node.getId());
userTask.setName(node.getName());
// 人工审批
addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, BpmUserTaskApproveTypeEnum.USER.getType().toString());
addExtensionElement(userTask, USER_TASK_APPROVE_TYPE, USER.getType().toString());
// 候选人策略为发起人自己
addCandidateElements(START_USER.getStrategy(),null, userTask);
addCandidateElements(START_USER.getStrategy(), null, userTask);
// 添加表单字段权限属性元素
addFormFieldsPermission(node.getFieldsPermission(), userTask);
// 添加操作按钮配置属性元素
@ -628,4 +634,114 @@ public class SimpleModelUtils {
return endEvent;
}
/**
* 遍历简单模型, 构建节点的进度 TODO 回退节点暂未处理
*
* @param processInstance 流程实例
* @param simpleModel 简单模型
* @param historicActivityList 流程实例的活力列表
* @param activityInstanceMap 流程实例的活力 Map key: activityId
* @param nodeProgresses 节点的进度列表
* @param returnNodePosition 回退节点的位置 TODO 处理回退节点还未处理还没想好
*/
public static void traverseNodeToBuildNodeProgress(HistoricProcessInstance processInstance, BpmSimpleModelNodeVO simpleModel
, List<HistoricActivityInstance> historicActivityList, Map<String, HistoricActivityInstance> activityInstanceMap
, List<ProcessNodeProgress> nodeProgresses, List<Integer> returnNodePosition) {
// 判断是否有效节点
if (!isValidNode(simpleModel)) {
return;
}
buildNodeProgress(processInstance, simpleModel, nodeProgresses, historicActivityList, activityInstanceMap, returnNodePosition);
// 如果有节点则递归处理子节点
traverseNodeToBuildNodeProgress(processInstance, simpleModel.getChildNode(), historicActivityList, activityInstanceMap, nodeProgresses, returnNodePosition);
}
private static void buildNodeProgress(HistoricProcessInstance processInstance, BpmSimpleModelNodeVO node, List<ProcessNodeProgress> nodeProgresses,
List<HistoricActivityInstance> historicActivityList, Map<String, HistoricActivityInstance> activityInstanceMap, List<Integer> returnNodePosition) {
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
Assert.notNull(nodeType, "模型节点类型不支持");
ProcessNodeProgress nodeProgress = new ProcessNodeProgress();
nodeProgress.setNodeType(nodeType.getType());
nodeProgress.setName(node.getName());
nodeProgress.setDisplayText(node.getShowText());
BpmActivityService activityService = SpringUtils.getBean(BpmActivityService.class);
if (!activityInstanceMap.containsKey(node.getId())) { // 说明这些节点没有执行过
// 1. 得到流程状态
Integer processInstanceStatus = FlowableUtils.getProcessInstanceStatus(processInstance);
// 2. 设置节点状态
nodeProgress.setStatus(activityService.getNotRunActivityProgressStatus(processInstanceStatus));
// 3. 抄送节点, 审批节点设置用户列表
if (COPY_NODE.getType().equals(node.getType()) ||
(APPROVE_NODE.getType().equals(node.getType()) && USER.getType().equals(node.getApproveType()))) {
nodeProgress.setUserList(activityService.getNotRunActivityUserList(processInstance.getId()
, processInstanceStatus, node.getCandidateStrategy(), node.getCandidateParam()));
}
} else {
nodeProgress.setStatus(BpmProcessNodeProgressEnum.FINISHED.getStatus()); // 默认设置成结束状态
HistoricActivityInstance historicActivity = activityInstanceMap.get(node.getId());
nodeProgress.setStartTime(DateUtils.of(historicActivity.getStartTime()));
nodeProgress.setEndTime(DateUtils.of(historicActivity.getEndTime()));
nodeProgress.setId(historicActivity.getId());
switch (nodeType) {
case START_USER_NODE: { // 发起人节点
nodeProgress.setDisplayText(""); // 发起人节点不需要显示 displayText
// 1. 设置节点的状态
nodeProgress.setStatus(activityService.getHistoricActivityProgressStatus(historicActivity, false, historicActivityList));
// 2. 设置用户信息
nodeProgress.setUserList(activityService.getHistoricActivityUserList(historicActivity, false, historicActivityList));
break;
}
case APPROVE_NODE: { // 审批节点
if (USER.getType().equals(node.getApproveType())) { // 人工审批
// 1. 判断是否多人审批
boolean isMultiInstance = !RANDOM.getMethod().equals(node.getApproveMethod());
// 2. 设置节点的状态
nodeProgress.setStatus(activityService.getHistoricActivityProgressStatus(historicActivity, isMultiInstance, historicActivityList));
// 3. 设置用户信息
nodeProgress.setUserList(activityService.getHistoricActivityUserList(historicActivity, isMultiInstance, historicActivityList));
} else {
nodeProgress.setStatus(activityService.getHistoricActivityProgressStatus(historicActivity, false, historicActivityList));
}
break;
}
case COPY_NODE: { // 抄送节点
// 1. 设置节点的状态
nodeProgress.setStatus(activityService.getHistoricActivityProgressStatus(historicActivity, false, historicActivityList));
// 2. 设置用户信息
nodeProgress.setUserList(activityService.getHistoricActivityUserList(historicActivity, false, historicActivityList));
break;
}
default: {
// TODO 其它节点类型的实现
}
}
}
// 如果是分支节点
if (BpmSimpleModelNodeType.isBranchNode(node.getType())
&& ArrayUtil.isNotEmpty(node.getConditionNodes())) {
// 网关是否执行了 执行了只包含运行的分支 未执行包含所有的分支
final boolean executed = activityInstanceMap.containsKey(node.getId());
LinkedList<ProcessNodeProgress> branchNodeList = new LinkedList<>();
node.getConditionNodes().forEach(item -> {
// 如果条件节点执行了 ACT_HI_ACTINST 表会记录
if (executed) {
if (activityInstanceMap.containsKey(item.getId())) {
List<Integer> branchReturnNodePosition = new ArrayList<>();
traverseNodeToBuildNodeProgress(processInstance, item, historicActivityList, activityInstanceMap, branchNodeList, branchReturnNodePosition);
// TODO 处理回退节点
}
} else {
List<Integer> branchReturnNodePosition = new ArrayList<>();
traverseNodeToBuildNodeProgress(processInstance, item, historicActivityList, activityInstanceMap, branchNodeList, branchReturnNodePosition);
// TODO 处理回退节点
}
});
nodeProgress.setBranchNodes(branchNodeList);
}
nodeProgresses.add(nodeProgress);
}
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelSaveReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
@ -17,7 +18,6 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand
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.framework.flowable.core.util.SimpleModelUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
@ -143,9 +143,11 @@ public class BpmModelServiceImpl implements BpmModelService {
BpmFormDO form = validateFormConfig(metaInfo);
// 1.4 校验任务分配规则已配置
taskCandidateInvoker.validateBpmnConfig(bpmnBytes);
// 1.5 获取仿钉钉流程设计器模型数据
byte[] simpleBytes = getModelSimpleJson(model.getId());
// 2.1 创建流程定义
String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form);
String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, simpleBytes, form);
// 2.2 将老的流程定义进行挂起也就是说只有最新部署的流程定义才可以发起任务
updateProcessDefinitionSuspended(model.getDeploymentId());
@ -276,7 +278,7 @@ public class BpmModelServiceImpl implements BpmModelService {
/**
* 挂起 deploymentId 对应的流程定义
*
* <p>
* 注意这里一个 deploymentId 只关联一个流程定义
*
* @param deploymentId 流程发布Id

View File

@ -48,10 +48,11 @@ public interface BpmProcessDefinitionService {
* @param model 流程模型
* @param modelMetaInfo 流程模型元信息
* @param bpmnBytes BPMN XML 字节数组
* @param simpleBytes simple model json 字节数组
* @param form 表单
* @return 流程编号
*/
String createProcessDefinition(Model model, BpmModelMetaInfoVO modelMetaInfo, byte[] bpmnBytes, BpmFormDO form);
String createProcessDefinition(Model model, BpmModelMetaInfoVO modelMetaInfo, byte[] bpmnBytes, byte[] simpleBytes, BpmFormDO form);
/**
* 更新流程定义状态

View File

@ -5,13 +5,13 @@ 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.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
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.dal.mysql.definition.BpmProcessDefinitionInfoMapper;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
@ -24,6 +24,7 @@ import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -106,7 +107,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
@Override
public String createProcessDefinition(Model model, BpmModelMetaInfoVO modelMetaInfo,
byte[] bpmnBytes, BpmFormDO form) {
byte[] bpmnBytes, byte[] simpleBytes, BpmFormDO form) {
// 创建 Deployment 部署
Deployment deploy = repositoryService.createDeployment()
.key(model.getKey()).name(model.getName()).category(model.getCategory())
@ -131,7 +132,9 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
// 插入拓展表
BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class)
.setModelId(model.getId()).setProcessDefinitionId(definition.getId());
.setModelId(model.getId()).setProcessDefinitionId(definition.getId()).setModelType(modelMetaInfo.getType())
.setSimpleModel(StrUtil.str(simpleBytes, StandardCharsets.UTF_8));
if (form != null) {
definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf());
}

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceProgressRespVO;
import org.flowable.engine.history.HistoricActivityInstance;
import java.util.List;
@ -18,7 +18,7 @@ public interface BpmActivityService {
* @param processInstanceId 流程实例的编号
* @return 活动实例列表
*/
List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId);
List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId);
/**
* 获得执行编号对应的活动实例
@ -28,4 +28,31 @@ public interface BpmActivityService {
*/
List<HistoricActivityInstance> getHistoricActivityListByExecutionId(String executionId);
/**
* 获取活动的用户列表 例如抄送人列表 审批人列表
*
* @param historicActivity 活动
* @param isMultiInstance 是否多实例 (会签或签 )
* @param historicActivityList 某个流程实例的所有活动列表
* @return 用户列表
*/
List<BpmProcessInstanceProgressRespVO.User> getHistoricActivityUserList(HistoricActivityInstance historicActivity,
Boolean isMultiInstance, List<HistoricActivityInstance> historicActivityList);
/**
* 获取活动的进度状态
*
* @param historicActivity 活动
* @param isMultiInstance 是否多实例 (会签或签 )
* @param historicActivityList 某个流程实例的所有活动列表
* @return 活动的进度状态
*/
Integer getHistoricActivityProgressStatus(HistoricActivityInstance historicActivity,
Boolean isMultiInstance, List<HistoricActivityInstance> historicActivityList);
Integer getNotRunActivityProgressStatus(Integer processInstanceStatus);
List<BpmProcessInstanceProgressRespVO.User> getNotRunActivityUserList(String processInstanceId, Integer processInstanceStatus
, Integer candidateStrategy, String candidateParam);
}

View File

@ -1,15 +1,33 @@
package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO;
import cn.iocoder.yudao.module.bpm.convert.task.BpmActivityConvert;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceProgressRespVO.User;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessNodeProgressEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
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.util.FlowableUtils;
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.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmProcessNodeProgressEnum.*;
/**
@ -22,14 +40,31 @@ import java.util.List;
@Validated
public class BpmActivityServiceImpl implements BpmActivityService {
/**
* 抄送节点活动类型
*/
private static final String COPY_NODE_ACTIVITY_TYPE = "serviceTask";
/**
* 审批节点活动类型
*/
private static final String APPROVE_NODE_ACTIVITY_TYPE = "userTask";
@Resource
private HistoryService historyService;
@Resource
@Lazy
private BpmTaskService bpmTaskService;
@Resource
private BpmProcessInstanceCopyService bpmProcessInstanceCopyService;
@Resource
private AdminUserApi adminUserApi;
@Resource
private BpmTaskCandidateInvoker bpmTaskCandidateInvoker;
@Override
public List<BpmActivityRespVO> getActivityListByProcessInstanceId(String processInstanceId) {
List<HistoricActivityInstance> activityList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).list();
return BpmActivityConvert.INSTANCE.convertList(activityList);
public List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId) {
return historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc().list();
}
@Override
@ -37,4 +72,129 @@ public class BpmActivityServiceImpl implements BpmActivityService {
return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list();
}
@Override
public List<User> getHistoricActivityUserList(HistoricActivityInstance historicActivity
, Boolean isMultiInstance, List<HistoricActivityInstance> historicActivityList) {
Assert.notNull(historicActivity, "historicActivity 不能为 null ");
List<User> returnUserList = Collections.emptyList();
if (COPY_NODE_ACTIVITY_TYPE.equals(historicActivity.getActivityType())) {
Set<Long> copyUserIds = bpmProcessInstanceCopyService.getCopyUserIds(historicActivity.getProcessInstanceId(),
historicActivity.getActivityId());
List<AdminUserRespDTO> userList = adminUserApi.getUserList(copyUserIds);
returnUserList = CollectionUtils.convertList(userList, item -> {
User user = BeanUtils.toBean(item, User.class);
user.setProcessed(Boolean.TRUE);
return user;
});
} else if (APPROVE_NODE_ACTIVITY_TYPE.equals(historicActivity.getActivityType())) {
if (isMultiInstance) { // 多人 (会签 或签 // TODO 依次审批可能要特殊处理一下
// 多个任务列表
List<HistoricActivityInstance> taskList = CollectionUtils.filterList(historicActivityList,
item -> historicActivity.getActivityId().equals(item.getActivityId()));
List<Long> userIds = CollectionUtils.convertList(taskList, item -> NumberUtil.parseLong(item.getAssignee(), null));
List<String> taskIds = CollectionUtils.convertList(taskList, HistoricActivityInstance::getTaskId);
Map<Long, AdminUserRespDTO> adminUserMap = CollectionUtils.convertMap(adminUserApi.getUserList(userIds), AdminUserRespDTO::getId);
Map<String, HistoricTaskInstance> historicTaskInstanceMap = CollectionUtils.convertMap(bpmTaskService.getHistoricTasks(taskIds), HistoricTaskInstance::getId);
returnUserList = CollectionUtils.convertList(taskList, item -> {
AdminUserRespDTO adminUser = adminUserMap.get(NumberUtil.parseLong(item.getAssignee(), null));
User user = BeanUtils.toBean(adminUser, User.class);
if (user != null) {
HistoricTaskInstance taskInstance = historicTaskInstanceMap.get(item.getTaskId());
if (taskInstance != null) {
user.setProcessed(taskInstance.getEndTime() != null);
user.setUserTaskStatus(FlowableUtils.getTaskStatus(taskInstance));
}
}
return user;
});
} else {
AdminUserRespDTO adminUserResp = adminUserApi.getUser(Long.valueOf(historicActivity.getAssignee()));
if (adminUserResp != null) {
User user = BeanUtils.toBean(adminUserResp, User.class);
// TODO 需要处理加签
// 查询任务状态
HistoricTaskInstance historicTask = bpmTaskService.getHistoricTask(historicActivity.getTaskId());
if (historicTask != null) {
Integer taskStatus = FlowableUtils.getTaskStatus(historicTask);
user.setProcessed(historicTask.getEndTime() != null);
user.setUserTaskStatus(taskStatus);
}
returnUserList = ListUtil.of(user);
}
}
}
return returnUserList;
}
@Override
public Integer getHistoricActivityProgressStatus(HistoricActivityInstance historicActivity
, Boolean isMultiInstance, List<HistoricActivityInstance> historicActivityList) {
Assert.notNull(historicActivity, "historicActivity 不能为 null ");
Integer progressStatus = null;
if (APPROVE_NODE_ACTIVITY_TYPE.equals(historicActivity.getActivityType())) {
if (isMultiInstance) { // 多人 (会签 或签
// 多个任务列表
List<HistoricActivityInstance> taskList = CollectionUtils.filterList(historicActivityList,
item -> historicActivity.getActivityId().equals(item.getActivityId()));
List<String> taskIds = CollectionUtils.convertList(taskList, HistoricActivityInstance::getTaskId);
Map<String, HistoricTaskInstance> historicTaskMap = CollectionUtils.convertMap(bpmTaskService.getHistoricTasks(taskIds), HistoricTaskInstance::getId);
for (HistoricActivityInstance activity : taskList) {
if (activity.getEndTime() == null) {
progressStatus = RUNNING.getStatus();
} else {
HistoricTaskInstance task = historicTaskMap.get(activity.getTaskId());
if (task != null) {
Integer taskStatus = FlowableUtils.getTaskStatus(task);
progressStatus = BpmProcessNodeProgressEnum.convertBpmnTaskStatus(taskStatus);
}
}
// 运行中或者未通过状态退出循环 (会签可能需要多人通过
if (RUNNING.getStatus().equals(progressStatus) || isUserTaskNotApproved(progressStatus)) {
break;
}
}
} else {
HistoricTaskInstance historicTask = bpmTaskService.getHistoricTask(historicActivity.getTaskId());
if (historicTask != null) {
Integer taskStatus = FlowableUtils.getTaskStatus(historicTask);
progressStatus = BpmProcessNodeProgressEnum.convertBpmnTaskStatus(taskStatus);
}
}
} else {
if (historicActivity.getEndTime() == null) {
progressStatus = RUNNING.getStatus();
}else {
progressStatus = BpmProcessNodeProgressEnum.FINISHED.getStatus();
}
}
return progressStatus;
}
@Override
public Integer getNotRunActivityProgressStatus(Integer processInstanceStatus) {
if(BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)){
return SKIP.getStatus();
}else {
return NOT_START.getStatus();
}
}
@Override
public List<User> getNotRunActivityUserList(String processInstanceId, Integer processInstanceStatus, Integer candidateStrategy, String candidateParam) {
if(BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)){
// 跳过节点返回空
return Collections.emptyList();
}else {
BpmTaskCandidateStrategy taskCandidateStrategy = bpmTaskCandidateInvoker.getCandidateStrategy(candidateStrategy);
Set<Long> userIds = taskCandidateStrategy.calculateUsers(processInstanceId, candidateParam);
List<AdminUserRespDTO> userList = adminUserApi.getUserList(userIds);
return CollectionUtils.convertList(userList, item -> {
User user = BeanUtils.toBean(item, User.class);
user.setProcessed(Boolean.FALSE);
return user;
});
}
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO;
import java.util.Collection;
import java.util.Set;
/**
* 流程抄送 Service 接口
@ -42,5 +43,13 @@ public interface BpmProcessInstanceCopyService {
*/
PageResult<BpmProcessInstanceCopyDO> getProcessInstanceCopyPage(Long userId,
BpmProcessInstanceCopyPageReqVO pageReqVO);
/**
* 通过流程实例和流程活动编号获取抄送人的 Id
*
* @param processInstanceId 流程实例 Id
* @param activityId 流程活动编号 Id
* @return 抄送人 Ids
*/
Set<Long> getCopyUserIds(String processInstanceId, String activityId);
}

View File

@ -2,6 +2,7 @@ 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.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceCopyMapper;
@ -18,6 +19,7 @@ import org.springframework.validation.annotation.Validated;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -85,4 +87,10 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
return processInstanceCopyMapper.selectPage(userId, pageReqVO);
}
@Override
public Set<Long> getCopyUserIds(String processInstanceId, String activityId) {
return CollectionUtils.convertSet(processInstanceCopyMapper.selectListByProcInstIdAndActId(processInstanceId, activityId),
BpmProcessInstanceCopyDO::getUserId);
}
}

View File

@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
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.BpmProcessInstanceFormFieldsPermissionReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
import jakarta.validation.Valid;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
@ -95,6 +92,14 @@ public interface BpmProcessInstanceService {
*/
Map<String, String> getProcessInstanceFormFieldsPermission(@Valid BpmProcessInstanceFormFieldsPermissionReqVO reqVO);
/**
* 获取流程实例的进度
*
* @param id 流程 Id
* @return 流程实例的进度
*/
BpmProcessInstanceProgressRespVO getProcessInstanceProgress(String id);
// ========== Update 写入相关方法 ==========
/**
@ -148,4 +153,5 @@ public interface BpmProcessInstanceService {
*/
void processProcessInstanceCompleted(ProcessInstance instance);
}

View File

@ -93,6 +93,14 @@ public interface BpmTaskService {
*/
HistoricTaskInstance getHistoricTask(String id);
/**
* 获取历史任务列表
*
* @param taskIds 任务编号集合
* @return 历史任务列表
*/
List<HistoricTaskInstance> getHistoricTasks(Collection<String> taskIds);
/**
* 根据条件查询正在进行中的任务
*

View File

@ -217,6 +217,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult();
}
@Override
public List<HistoricTaskInstance> getHistoricTasks(Collection<String> taskIds) {
return historyService.createHistoricTaskInstanceQuery().taskIds(taskIds).includeTaskLocalVariables().list();
}
@Override
public List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId, Boolean assigned, String defineKey) {
Assert.notNull(processInstanceId, "processInstanceId 不能为空");