Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

This commit is contained in:
jason 2025-02-16 08:47:31 +08:00
commit 1f2222cf83
9 changed files with 75 additions and 14 deletions

View File

@ -25,6 +25,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> {
START_USER_NODE(10, "发起人", "userTask"), // 发起人节点前端的开始节点Id 固定
APPROVE_NODE(11, "审批人", "userTask"),
COPY_NODE(12, "抄送人", "serviceTask"),
TRANSACTOR_NODE(13, "办理人", "userTask"),
DELAY_TIMER_NODE(14, "延迟器", "receiveTask"),
TRIGGER_NODE(15, "触发器", "serviceTask"),

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmAutoApproveTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
@ -27,8 +26,7 @@ import java.util.List;
@Data
public class BpmModelMetaInfoVO {
@Schema(description = "流程图标", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg")
@NotEmpty(message = "流程图标不能为空")
@Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg")
@URL(message = "流程图标格式不正确")
private String icon;

View File

@ -85,6 +85,9 @@ public class BpmTaskRespVO {
@Schema(description = "是否填写审批意见", example = "false")
private Boolean reasonRequire;
@Schema(description = "节点类型", example = "10")
private Integer nodeType; // 参见 BpmSimpleModelNodeTypeEnum 枚举
@Data
@Schema(description = "流程实例")
public static class ProcessInstance {

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
/**
* BPMN XML 常量信息
*
@ -129,4 +131,11 @@ public interface BpmnModelConstants {
*/
String REASON_REQUIRE = "reasonRequire";
/**
* 节点类型
*
* 目前只有 {@link BpmModelTypeEnum#SIMPLE} UserTask 节点会设置该属性用于区分是审批节点还是办理节点
*/
String NODE_TYPE = "nodeType";
}

View File

@ -410,6 +410,26 @@ public class BpmnModelUtils {
return parseExtensionElement(flowElement, TRIGGER_PARAM);
}
/**
* 给节点添加节点类型
*
* @param nodeType 节点类型
* @param flowElement 节点
*/
public static void addNodeType(Integer nodeType, FlowElement flowElement) {
addExtensionElement(flowElement, BpmnModelConstants.NODE_TYPE, nodeType);
}
/**
* 解析节点类型
*
* @param flowElement 节点
* @return 节点类型
*/
public static Integer parseNodeType(FlowElement flowElement) {
return NumberUtils.parseInt(parseExtensionElement(flowElement, BpmnModelConstants.NODE_TYPE));
}
// ========== BPM 简单查找相关的方法 ==========
/**

View File

@ -40,7 +40,7 @@ public class SimpleModelUtils {
static {
List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(),
new DelayTimerNodeConvert(), new TriggerNodeConvert(),
new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert());
converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
@ -445,6 +445,8 @@ public class SimpleModelUtils {
addSignEnable(node.getSignEnable(), userTask);
// 审批意见
addReasonRequire(node.getReasonRequire(), userTask);
// 节点类型
addNodeType(node.getType(), userTask);
return userTask;
}
@ -514,6 +516,15 @@ public class SimpleModelUtils {
}
private static class TransactorNodeConvert extends ApproveNodeConvert {
@Override
public BpmSimpleModelNodeTypeEnum getType() {
return BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE;
}
}
private static class CopyNodeConvert implements NodeConvert {
@Override
@ -785,10 +796,11 @@ public class SimpleModelUtils {
BpmSimpleModelNodeTypeEnum nodeType = BpmSimpleModelNodeTypeEnum.valueOf(currentNode.getType());
Assert.notNull(nodeType, "模型节点类型不支持");
// 情况START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE
// 情况START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE/TRANSACTOR_NODE
if (nodeType == BpmSimpleModelNodeTypeEnum.START_NODE
|| nodeType == BpmSimpleModelNodeTypeEnum.START_USER_NODE
|| nodeType == BpmSimpleModelNodeTypeEnum.APPROVE_NODE
|| nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE
|| nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE
|| nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) {
// 添加元素

View File

@ -28,8 +28,7 @@ import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static java.util.Collections.emptyList;
/**
@ -156,16 +155,25 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
@Override
public void updateProcessDefinitionState(String id, Integer state) {
ProcessDefinition processDefinition = repositoryService.getProcessDefinition(id);
if (processDefinition == null) {
throw exception(PROCESS_DEFINITION_NOT_EXISTS);
}
// 激活
if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
repositoryService.activateProcessDefinitionById(id, false, null);
if (processDefinition.isSuspended()) {
repositoryService.activateProcessDefinitionById(id, false, null);
}
return;
}
// 挂起
if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
// suspendProcessInstances = false进行中的任务不进行挂起
// 原因只要新的流程不允许发起即可老流程继续可以执行
repositoryService.suspendProcessDefinitionById(id, false, null);
if (!processDefinition.isSuspended()) {
repositoryService.suspendProcessDefinitionById(id, false, null);
}
return;
}
log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);

View File

@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -67,6 +68,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseNodeType;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
@ -325,7 +327,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName())
.setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey())
? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()
: BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
: ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的解决办理节点的识别
BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()))
.setStatus(FlowableUtils.getTaskStatus(task))
.setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
.setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime()))
@ -402,7 +405,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务会签/或签的任务开始时间相同
ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId())
.setName(firstActivity.getActivityName())
.setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
.setNodeType(ObjUtil.defaultIfNull(parseNodeType(flowNode), // 目的解决办理节点的识别
BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()))
.setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
.setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
.setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime()))
@ -479,7 +483,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// 1. 开始节点/审批节点
if (ObjectUtils.equalsAny(node.getType(),
BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType(),
BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())) {
BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType(),
BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE.getType())) {
List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables);
activityNode.setCandidateUserIds(candidateUserIds);

View File

@ -61,6 +61,7 @@ import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
@ -162,6 +163,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
bpmnModel, todoTask.getTaskDefinitionKey());
Boolean signEnable = parseSignEnable(bpmnModel, todoTask.getTaskDefinitionKey());
Boolean reasonRequire = parseReasonRequire(bpmnModel, todoTask.getTaskDefinitionKey());
Integer nodeType = parseNodeType(BpmnModelUtils.getFlowElementById(bpmnModel, todoTask.getTaskDefinitionKey()));
// 4. 任务表单
BpmFormDO taskForm = null;
@ -170,8 +172,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm)
.setSignEnable(signEnable)
.setReasonRequire(reasonRequire);
.setNodeType(nodeType).setSignEnable(signEnable).setReasonRequire(reasonRequire);
}
@Override
@ -194,6 +195,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return PageResult.empty();
}
List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
// 特殊强制移除自动完成的发起人节点
// 补充说明由于 taskQuery 无法方面的过滤所以暂时通过内存过滤
tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID));
return new PageResult<>(tasks, count);
}