mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2026-07-14 08:36:11 +00:00
add: 新增工作流 LiteFlow 规则链
This commit is contained in:
@@ -245,6 +245,15 @@ warm-flow:
|
||||
# 默认Authorization,如果有多个token,用逗号分隔
|
||||
token-name: ${sa-token.token-name},clientid
|
||||
|
||||
--- # LiteFlow 业务规则编排
|
||||
liteflow:
|
||||
# 跟随工作流模块开关,避免禁用工作流时仍加载任务办理链
|
||||
enable: ${warm-flow.enabled:true}
|
||||
# 工作流模块用于编排任务办理链路
|
||||
rule-source: classpath:liteflow/*.el.xml
|
||||
# 开启虚拟线程
|
||||
enable-virtual-thread: true
|
||||
|
||||
--- # mqtt 配置
|
||||
# 具体配置还需查看文档
|
||||
# https://mica-mqtt.dreamlu.net/guide/spring/client.html
|
||||
|
||||
@@ -96,6 +96,12 @@
|
||||
<artifactId>warm-flow-plugin-ui-sb-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- LiteFlow 规则编排 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-liteflow</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.dromara.workflow.domain.context;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
||||
|
||||
/**
|
||||
* 办理任务 LiteFlow 上下文。
|
||||
* <p>
|
||||
* 链路内各节点通过该对象传递任务、实例、办理参数等中间结果,避免组件之间重复查询。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class CompleteTaskContext {
|
||||
|
||||
/**
|
||||
* 办理任务入参。
|
||||
*/
|
||||
private final CompleteTaskBo completeTaskBo;
|
||||
|
||||
/**
|
||||
* 当前待办理的运行任务,由校验节点加载。
|
||||
*/
|
||||
private FlowTask flowTask;
|
||||
|
||||
/**
|
||||
* 当前任务所属流程实例,由校验节点加载。
|
||||
*/
|
||||
private Instance instance;
|
||||
|
||||
/**
|
||||
* Warm-Flow 办理参数,由参数构建节点生成并供执行、自动审批节点复用。
|
||||
*/
|
||||
private FlowParams flowParams;
|
||||
|
||||
/**
|
||||
* 流程实例是否开启自动审批,由参数构建节点从实例变量中解析。
|
||||
*/
|
||||
private Boolean autoPass;
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package org.dromara.workflow.domain.context;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 删除流程实例 LiteFlow 上下文。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class InstanceDeleteContext {
|
||||
|
||||
/**
|
||||
* 按业务 id 删除时的业务 id 集合。
|
||||
*/
|
||||
private final List<String> businessIds;
|
||||
|
||||
/**
|
||||
* 按实例 id 删除时的实例 id 集合。
|
||||
*/
|
||||
private final Collection<Long> instanceIds;
|
||||
|
||||
/**
|
||||
* 是否删除历史实例及其历史任务数据。
|
||||
*/
|
||||
private final boolean history;
|
||||
|
||||
/**
|
||||
* 待删除流程实例。
|
||||
*/
|
||||
private List<FlowInstance> flowInstances;
|
||||
|
||||
/**
|
||||
* 实际执行删除的实例 id。
|
||||
*/
|
||||
private List<Long> deleteInstanceIds;
|
||||
|
||||
/**
|
||||
* 删除结果。
|
||||
*/
|
||||
private boolean result;
|
||||
|
||||
public static InstanceDeleteContext byBusinessIds(List<String> businessIds) {
|
||||
return new InstanceDeleteContext(businessIds, null, false);
|
||||
}
|
||||
|
||||
public static InstanceDeleteContext byInstanceIds(Collection<Long> instanceIds) {
|
||||
return new InstanceDeleteContext(null, instanceIds, false);
|
||||
}
|
||||
|
||||
public static InstanceDeleteContext byHistoryInstanceIds(Collection<Long> instanceIds) {
|
||||
return new InstanceDeleteContext(null, instanceIds, true);
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package org.dromara.workflow.domain.context;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import org.dromara.workflow.api.domain.StartProcessReturnDTO;
|
||||
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||
import org.dromara.workflow.domain.bo.StartProcessBo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 启动流程 LiteFlow 上下文。
|
||||
* <p>
|
||||
* 链路内保存启动参数、流程定义、流程实例和首个任务等中间结果。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class StartProcessContext {
|
||||
|
||||
/**
|
||||
* 启动流程入参。
|
||||
*/
|
||||
private final StartProcessBo startProcessBo;
|
||||
|
||||
/**
|
||||
* 业务唯一标识。
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 流程变量。
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 流程实例业务扩展信息。
|
||||
*/
|
||||
private FlowInstanceBizExt bizExt;
|
||||
|
||||
/**
|
||||
* 已存在的流程实例,非空时走续提交逻辑。
|
||||
*/
|
||||
private FlowInstance existingInstance;
|
||||
|
||||
/**
|
||||
* 已发布的流程定义。
|
||||
*/
|
||||
private Definition definition;
|
||||
|
||||
/**
|
||||
* 新启动的流程实例。
|
||||
*/
|
||||
private Instance instance;
|
||||
|
||||
/**
|
||||
* 当前流程实例下生成的任务列表。
|
||||
*/
|
||||
private List<Task> taskList;
|
||||
|
||||
/**
|
||||
* 启动流程返回结果。
|
||||
*/
|
||||
private StartProcessReturnDTO startProcessReturn;
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.dromara.workflow.domain.context;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.orm.entity.FlowNode;
|
||||
import org.dromara.workflow.common.enums.TaskOperationEnum;
|
||||
import org.dromara.workflow.domain.bo.TaskOperationBo;
|
||||
|
||||
/**
|
||||
* 任务操作 LiteFlow 上下文。
|
||||
* <p>
|
||||
* 用于在委派、转办、加签、减签链路中传递操作类型、任务、节点和办理参数。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@Data
|
||||
public class TaskOperationContext {
|
||||
|
||||
/**
|
||||
* 任务操作入参。
|
||||
*/
|
||||
private final TaskOperationBo taskOperationBo;
|
||||
|
||||
/**
|
||||
* 操作类型编码。
|
||||
*/
|
||||
private final String taskOperation;
|
||||
|
||||
/**
|
||||
* 解析后的操作枚举。
|
||||
*/
|
||||
private TaskOperationEnum operation;
|
||||
|
||||
/**
|
||||
* Warm-Flow 操作参数。
|
||||
*/
|
||||
private FlowParams flowParams;
|
||||
|
||||
/**
|
||||
* 当前任务。
|
||||
*/
|
||||
private Task task;
|
||||
|
||||
/**
|
||||
* 当前任务对应的流程节点。
|
||||
*/
|
||||
private FlowNode flowNode;
|
||||
|
||||
/**
|
||||
* 操作执行结果。
|
||||
*/
|
||||
private boolean result;
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package org.dromara.workflow.liteflow.complete;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.query.QueryBuilder;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.User;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.CompleteTaskContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 执行当前处理人的后续自动审批。
|
||||
* <p>
|
||||
* 仅当流程实例开启自动审批时生效,用于连续跳过同一登录人负责的后续待办任务。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("completeAutoPass")
|
||||
public class CompleteAutoPassComponent extends NodeComponent {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final FlowTaskMapper flowTaskMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
CompleteTaskContext context = getRequestData();
|
||||
FlowTask flowTask = context.getFlowTask();
|
||||
autoPass(flowTask.getId(), context.getFlowParams(), flowTask.getInstanceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归跳过当前处理人的后续任务。
|
||||
*
|
||||
* @param taskId 本轮已处理任务 id,用于避免重复跳过同一任务
|
||||
* @param flowParams 当前办理参数,会在自动审批时覆盖为自动审批消息和空抄送变量
|
||||
* @param instanceId 流程实例 id
|
||||
*/
|
||||
private void autoPass(Long taskId, FlowParams flowParams, Long instanceId) {
|
||||
List<FlowTask> flowTaskList = selectByInstId(instanceId);
|
||||
if (CollUtil.isEmpty(flowTaskList)) {
|
||||
return;
|
||||
}
|
||||
List<User> userList = FlowEngine.userService()
|
||||
.getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId));
|
||||
if (CollUtil.isEmpty(userList)) {
|
||||
return;
|
||||
}
|
||||
for (FlowTask task : flowTaskList) {
|
||||
if (task.getId().equals(taskId)) {
|
||||
continue;
|
||||
}
|
||||
// 自动审批只处理当前登录人仍是办理人的后续任务,避免替其他候选人或并行分支误审批。
|
||||
List<User> users = StreamUtils.filter(userList,
|
||||
e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr()));
|
||||
if (CollUtil.isEmpty(users)) {
|
||||
continue;
|
||||
}
|
||||
// 自动审批不继承人工办理时的抄送和消息通知,避免重复发送业务消息。
|
||||
flowParams
|
||||
.message("流程引擎自动审批!")
|
||||
.variable(Map.of(
|
||||
SUBMIT, false,
|
||||
FLOW_COPY_LIST, Collections.emptyList(),
|
||||
MESSAGE_NOTICE, StringUtils.EMPTY));
|
||||
taskService.skip(task.getId(), flowParams);
|
||||
// 跳过后可能生成新的后续任务,继续扫描直到当前登录人不再有可自动办理任务。
|
||||
autoPass(task.getId(), flowParams, instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
private List<FlowTask> selectByInstId(Long instanceId) {
|
||||
return flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class)
|
||||
.eq(FlowTask::getInstanceId, instanceId)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.dromara.workflow.liteflow.complete;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.enums.SkipType;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
||||
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
||||
import org.dromara.workflow.domain.context.CompleteTaskContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 构建办理参数并执行当前任务跳转。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("completeExecute")
|
||||
public class CompleteExecuteComponent extends NodeComponent {
|
||||
|
||||
private final TaskService taskService;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
CompleteTaskContext context = getRequestData();
|
||||
CompleteTaskBo completeTaskBo = context.getCompleteTaskBo();
|
||||
Map<String, Object> variables = completeTaskBo.getVariables();
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.handler(completeTaskBo.getHandler())
|
||||
.variable(variables)
|
||||
.ignore(Convert.toBool(variables.getOrDefault(VAR_IGNORE, false)))
|
||||
.ignoreDepute(Convert.toBool(variables.getOrDefault(VAR_IGNORE_DEPUTE, false)))
|
||||
.ignoreCooperate(Convert.toBool(variables.getOrDefault(VAR_IGNORE_COOPERATE, false)))
|
||||
.skipType(SkipType.PASS.getKey())
|
||||
.message(completeTaskBo.getMessage())
|
||||
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
||||
.hisTaskExt(completeTaskBo.getFileId());
|
||||
|
||||
context.setFlowParams(flowParams);
|
||||
context.setAutoPass(Convert.toBool(context.getInstance().getVariableMap().getOrDefault(AUTO_PASS, false)));
|
||||
taskService.skip(context.getFlowTask().getId(), flowParams);
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package org.dromara.workflow.liteflow.complete;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.CompleteTaskContext;
|
||||
|
||||
/**
|
||||
* 判断办理任务后是否进入自动审批分支。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@LiteflowComponent("completeNeedAutoPass")
|
||||
public class CompleteNeedAutoPassComponent extends NodeBooleanComponent {
|
||||
|
||||
@Override
|
||||
public boolean processBoolean() {
|
||||
CompleteTaskContext context = getRequestData();
|
||||
return Boolean.TRUE.equals(context.getAutoPass());
|
||||
}
|
||||
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package org.dromara.workflow.liteflow.complete;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
||||
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
||||
import org.dromara.workflow.domain.context.CompleteTaskContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 准备任务办理上下文。
|
||||
* <p>
|
||||
* 负责加载任务实例、补齐流程变量,并解析弹窗选择的后续办理人。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("completePrepare")
|
||||
public class CompletePrepareComponent extends NodeComponent {
|
||||
|
||||
private final FlowTaskMapper flowTaskMapper;
|
||||
private final InsService insService;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
CompleteTaskContext context = getRequestData();
|
||||
CompleteTaskBo completeTaskBo = context.getCompleteTaskBo();
|
||||
FlowTask flowTask = flowTaskMapper.selectById(completeTaskBo.getTaskId());
|
||||
if (ObjectUtil.isNull(flowTask)) {
|
||||
throw new ServiceException("流程任务不存在或任务已审批!");
|
||||
}
|
||||
Instance instance = insService.getById(flowTask.getInstanceId());
|
||||
if (ObjectUtil.isNull(instance)) {
|
||||
throw new ServiceException("流程实例不存在");
|
||||
}
|
||||
context.setFlowTask(flowTask);
|
||||
context.setInstance(instance);
|
||||
|
||||
Map<String, Object> variables = completeTaskBo.getVariables();
|
||||
variables.put(FLOW_COPY_LIST, completeTaskBo.getFlowCopyList());
|
||||
variables.put(MESSAGE_TYPE, completeTaskBo.getMessageType());
|
||||
variables.put(MESSAGE_NOTICE, completeTaskBo.getNotice());
|
||||
if (BusinessStatusEnum.isDraftOrCancelOrBack(instance.getFlowStatus())) {
|
||||
// 草稿、撤销、驳回状态再次办理时等同于重新提交,条件表达式通过 SUBMIT 识别提交分支。
|
||||
variables.put(SUBMIT, true);
|
||||
}
|
||||
Map<String, Object> assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), instance.getVariableMap());
|
||||
if (CollUtil.isNotEmpty(assigneeMap)) {
|
||||
variables.putAll(assigneeMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将弹窗处理人映射成通过/退回状态下的办理人变量。
|
||||
*/
|
||||
private Map<String, Object> setPopAssigneeMap(Map<String, Object> assigneeMap, Map<String, Object> variablesMap) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (CollUtil.isEmpty(assigneeMap)) {
|
||||
return map;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : assigneeMap.entrySet()) {
|
||||
if (variablesMap.containsKey(entry.getKey())) {
|
||||
String userIds = variablesMap.get(entry.getKey()).toString();
|
||||
if (StringUtils.isNotBlank(userIds)) {
|
||||
Set<String> hashSet = CollUtil.newHashSet();
|
||||
List<String> popUserIds = StringUtils.str2List(entry.getValue().toString(), StringUtils.SEPARATOR, true, true);
|
||||
List<String> variableUserIds = StringUtils.str2List(userIds, StringUtils.SEPARATOR, true, true);
|
||||
hashSet.addAll(popUserIds);
|
||||
hashSet.addAll(variableUserIds);
|
||||
// Warm-Flow 会按“状态:变量名”读取办理人,正向和退回都写入同一批候选人。
|
||||
map.put(TaskStatusEnum.PASS.getStatus() + StringUtils.COLON + entry.getKey(), StringUtils.joinComma(hashSet));
|
||||
map.put(TaskStatusEnum.BACK.getStatus() + StringUtils.COLON + entry.getKey(), StringUtils.joinComma(hashSet));
|
||||
}
|
||||
} else {
|
||||
map.put(TaskStatusEnum.PASS.getStatus() + StringUtils.COLON + entry.getKey(), entry.getValue());
|
||||
map.put(TaskStatusEnum.BACK.getStatus() + StringUtils.COLON + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package org.dromara.workflow.liteflow.instance;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.service.DefService;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.InstanceDeleteContext;
|
||||
import org.dromara.workflow.handler.FlowProcessEventHandler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 校验实例删除权限并发布业务删除事件。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@LiteflowComponent("instanceDeleteEvent")
|
||||
public class InstanceDeleteEventComponent extends NodeComponent {
|
||||
|
||||
private final DefService defService;
|
||||
private final FlowProcessEventHandler flowProcessEventHandler;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
InstanceDeleteContext context = getRequestData();
|
||||
String userId = LoginHelper.getUserIdStr();
|
||||
context.getFlowInstances().forEach(flowInstance -> {
|
||||
if (!LoginHelper.isSuperAdmin() && !flowInstance.getCreateBy().equals(userId)) {
|
||||
throw new ServiceException("权限不足,无法删除流程实例信息!");
|
||||
}
|
||||
});
|
||||
|
||||
Map<Long, Definition> definitionMap = StreamUtils.toMap(
|
||||
defService.getByIds(StreamUtils.toList(context.getFlowInstances(), Instance::getDefinitionId)),
|
||||
Definition::getId,
|
||||
Function.identity()
|
||||
);
|
||||
context.getFlowInstances().forEach(instance -> {
|
||||
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||
if (ObjectUtil.isNull(definition)) {
|
||||
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||
return;
|
||||
}
|
||||
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package org.dromara.workflow.liteflow.instance;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.mybatis.core.query.QueryBuilder;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowTaskMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.InstanceDeleteContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 执行流程实例删除。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("instanceDeleteExecute")
|
||||
public class InstanceDeleteExecuteComponent extends NodeComponent {
|
||||
|
||||
private final InsService insService;
|
||||
private final FlowTaskMapper flowTaskMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
InstanceDeleteContext context = getRequestData();
|
||||
if (!context.isHistory()) {
|
||||
context.setResult(insService.remove(context.getDeleteInstanceIds()));
|
||||
return;
|
||||
}
|
||||
List<FlowTask> flowTaskList = flowTaskMapper.selectList(QueryBuilder.lambda(FlowTask.class)
|
||||
.in(FlowTask::getInstanceId, context.getDeleteInstanceIds())
|
||||
.build());
|
||||
if (CollUtil.isNotEmpty(flowTaskList)) {
|
||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId));
|
||||
}
|
||||
FlowEngine.taskService().deleteByInsIds(context.getDeleteInstanceIds());
|
||||
FlowEngine.hisTaskService().deleteByInsIds(context.getDeleteInstanceIds());
|
||||
FlowEngine.insService().removeByIds(context.getDeleteInstanceIds());
|
||||
context.setResult(true);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.workflow.liteflow.instance;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.InstanceDeleteContext;
|
||||
|
||||
/**
|
||||
* 判断删除流程实例时是否存在可执行删除的数据。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@LiteflowComponent("instanceDeleteExists")
|
||||
public class InstanceDeleteExistsComponent extends NodeBooleanComponent {
|
||||
|
||||
@Override
|
||||
public boolean processBoolean() {
|
||||
InstanceDeleteContext context = getRequestData();
|
||||
return CollUtil.isNotEmpty(context.getFlowInstances());
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package org.dromara.workflow.liteflow.instance;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.mybatis.core.query.QueryBuilder;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.InstanceDeleteContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加载待删除流程实例。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@LiteflowComponent("instanceDeleteLoad")
|
||||
public class InstanceDeleteLoadComponent extends NodeComponent {
|
||||
|
||||
private final FlowInstanceMapper flowInstanceMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
InstanceDeleteContext context = getRequestData();
|
||||
List<FlowInstance> flowInstances;
|
||||
if (CollUtil.isNotEmpty(context.getBusinessIds())) {
|
||||
flowInstances = flowInstanceMapper.selectList(QueryBuilder.lambda(FlowInstance.class)
|
||||
.in(FlowInstance::getBusinessId, context.getBusinessIds())
|
||||
.build());
|
||||
context.setDeleteInstanceIds(StreamUtils.toList(flowInstances, FlowInstance::getId));
|
||||
} else {
|
||||
flowInstances = flowInstanceMapper.selectByIds(context.getInstanceIds());
|
||||
context.setDeleteInstanceIds(new ArrayList<>(context.getInstanceIds()));
|
||||
}
|
||||
if (CollUtil.isEmpty(flowInstances)) {
|
||||
log.warn("未找到对应的流程实例信息,无法执行删除操作。");
|
||||
context.setResult(false);
|
||||
return;
|
||||
}
|
||||
context.setFlowInstances(flowInstances);
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package org.dromara.workflow.liteflow.operation;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
||||
import org.dromara.workflow.domain.context.TaskOperationContext;
|
||||
|
||||
/**
|
||||
* 执行委派、转办、加签或减签。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("taskOpExecute")
|
||||
public class TaskOpExecuteComponent extends NodeComponent {
|
||||
|
||||
private final TaskService taskService;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
TaskOperationContext context = getRequestData();
|
||||
Long taskId = context.getTaskOperationBo().getTaskId();
|
||||
boolean result = false;
|
||||
switch (context.getOperation()) {
|
||||
case DELEGATE_TASK -> {
|
||||
context.getFlowParams().hisStatus(TaskStatusEnum.DEPUTE.getStatus());
|
||||
result = taskService.depute(taskId, context.getFlowParams());
|
||||
}
|
||||
case TRANSFER_TASK -> {
|
||||
context.getFlowParams().hisStatus(TaskStatusEnum.TRANSFER.getStatus());
|
||||
result = taskService.transfer(taskId, context.getFlowParams());
|
||||
}
|
||||
case ADD_SIGNATURE -> {
|
||||
context.getFlowParams().hisStatus(TaskStatusEnum.SIGN.getStatus());
|
||||
result = taskService.addSignature(taskId, context.getFlowParams());
|
||||
}
|
||||
case REDUCTION_SIGNATURE -> {
|
||||
context.getFlowParams().hisStatus(TaskStatusEnum.SIGN_OFF.getStatus());
|
||||
result = taskService.reductionSignature(taskId, context.getFlowParams());
|
||||
}
|
||||
}
|
||||
context.setResult(result);
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.dromara.workflow.liteflow.operation;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.mybatis.core.query.QueryBuilder;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.enums.CooperateType;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowNode;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.TaskOperationEnum;
|
||||
import org.dromara.workflow.domain.context.TaskOperationContext;
|
||||
|
||||
/**
|
||||
* 加载任务节点并校验操作约束。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("taskOpLoad")
|
||||
public class TaskOpLoadComponent extends NodeComponent {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final FlowNodeMapper flowNodeMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
TaskOperationContext context = getRequestData();
|
||||
Task task = taskService.getById(context.getTaskOperationBo().getTaskId());
|
||||
if (ObjectUtil.isNull(task)) {
|
||||
throw new ServiceException("任务不存在!");
|
||||
}
|
||||
FlowNode flowNode = flowNodeMapper.selectOne(QueryBuilder.lambda(FlowNode.class)
|
||||
.eq(FlowNode::getNodeCode, task.getNodeCode())
|
||||
.eq(FlowNode::getDefinitionId, task.getDefinitionId())
|
||||
.build());
|
||||
if (ObjectUtil.isNull(flowNode)) {
|
||||
throw new ServiceException("流程节点不存在");
|
||||
}
|
||||
if ((context.getOperation() == TaskOperationEnum.ADD_SIGNATURE || context.getOperation() == TaskOperationEnum.REDUCTION_SIGNATURE)
|
||||
&& CooperateType.isOrSign(flowNode.getNodeRatio())) {
|
||||
throw new ServiceException(task.getNodeName() + "不是会签或票签节点!");
|
||||
}
|
||||
context.setTask(task);
|
||||
context.setFlowNode(flowNode);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.workflow.liteflow.operation;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.TaskOperationContext;
|
||||
|
||||
/**
|
||||
* 判断任务操作后是否进入消息通知分支。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@LiteflowComponent("taskOpNeedNotify")
|
||||
public class TaskOpNeedNotifyComponent extends NodeBooleanComponent {
|
||||
|
||||
@Override
|
||||
public boolean processBoolean() {
|
||||
TaskOperationContext context = getRequestData();
|
||||
return context.isResult() && CollUtil.isNotEmpty(context.getTaskOperationBo().getMessageType());
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.dromara.workflow.liteflow.operation;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.system.api.UserService;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.bo.TaskOperationBo;
|
||||
import org.dromara.workflow.domain.context.TaskOperationContext;
|
||||
import org.dromara.workflow.service.IFlwCommonService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.PATH_TASK_WAITING;
|
||||
|
||||
/**
|
||||
* 任务操作成功后发送待办消息。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("taskOpNotify")
|
||||
public class TaskOpNotifyComponent extends NodeComponent {
|
||||
|
||||
private final IFlwCommonService flwCommonService;
|
||||
private final UserService userService;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
TaskOperationContext context = getRequestData();
|
||||
TaskOperationBo bo = context.getTaskOperationBo();
|
||||
List<Long> userIdList = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(bo.getUserId())) {
|
||||
userIdList.add(Convert.toLong(bo.getUserId()));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(bo.getUserIds())) {
|
||||
userIdList.addAll(bo.getUserIds().stream().map(Convert::toLong).toList());
|
||||
}
|
||||
if (CollUtil.isEmpty(userIdList)) {
|
||||
return;
|
||||
}
|
||||
// 转办、委托、加减签等运行时操作,消息接收人统一从“我的待办”进入处理。
|
||||
flwCommonService.sendMessage(
|
||||
bo.getMessageType(),
|
||||
StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + context.getOperation().getDesc() + "」通知",
|
||||
"单据「" + context.getOperation().getDesc() + "」提醒",
|
||||
userService.selectListByIds(userIdList),
|
||||
PATH_TASK_WAITING
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.dromara.workflow.liteflow.operation;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.ValidatorUtils;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.TaskOperationEnum;
|
||||
import org.dromara.workflow.domain.bo.TaskOperationBo;
|
||||
import org.dromara.workflow.domain.context.TaskOperationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 准备任务操作参数。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@LiteflowComponent("taskOpPrepare")
|
||||
public class TaskOpPrepareComponent extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
TaskOperationContext context = getRequestData();
|
||||
TaskOperationEnum op = TaskOperationEnum.getByCode(context.getTaskOperation());
|
||||
if (op == null) {
|
||||
log.error("Invalid operation type:{} ", context.getTaskOperation());
|
||||
throw new ServiceException("Invalid operation type " + context.getTaskOperation());
|
||||
}
|
||||
context.setOperation(op);
|
||||
|
||||
TaskOperationBo bo = context.getTaskOperationBo();
|
||||
switch (op) {
|
||||
case DELEGATE_TASK, TRANSFER_TASK -> ValidatorUtils.validate(bo, AddGroup.class);
|
||||
case ADD_SIGNATURE, REDUCTION_SIGNATURE -> ValidatorUtils.validate(bo, EditGroup.class);
|
||||
}
|
||||
|
||||
FlowParams flowParams = FlowParams.build().message(bo.getMessage());
|
||||
if (LoginHelper.isSuperAdmin()) {
|
||||
flowParams.ignore(true);
|
||||
}
|
||||
switch (op) {
|
||||
case DELEGATE_TASK, TRANSFER_TASK -> flowParams.addHandlers(Collections.singletonList(bo.getUserId()));
|
||||
case ADD_SIGNATURE -> flowParams.addHandlers(bo.getUserIds());
|
||||
case REDUCTION_SIGNATURE -> flowParams.reductionHandlers(bo.getUserIds());
|
||||
}
|
||||
context.setFlowParams(flowParams);
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.dromara.workflow.liteflow.start;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||
import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.workflow.api.domain.StartProcessReturnDTO;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||
import org.dromara.workflow.domain.context.StartProcessContext;
|
||||
import org.dromara.workflow.mapper.FlwInstanceBizExtMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 启动流程实例并构建返回结果。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("startExecute")
|
||||
public class StartExecuteComponent extends NodeComponent {
|
||||
|
||||
private final InsService insService;
|
||||
private final TaskService taskService;
|
||||
private final FlwInstanceBizExtMapper flwInstanceBizExtMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
StartProcessContext context = getRequestData();
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.handler(context.getStartProcessBo().getHandler())
|
||||
.flowCode(context.getStartProcessBo().getFlowCode())
|
||||
.variable(context.getVariables())
|
||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
Instance instance = insService.start(context.getBusinessId(), flowParams);
|
||||
context.setInstance(instance);
|
||||
saveBizExt(context, instance);
|
||||
|
||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
|
||||
if (CollUtil.isEmpty(taskList)) {
|
||||
throw new ServiceException("流程启动失败,未生成任务");
|
||||
}
|
||||
if (taskList.size() > 1) {
|
||||
throw new ServiceException("请检查流程第一个环节是否为申请人!");
|
||||
}
|
||||
context.setTaskList(taskList);
|
||||
context.setStartProcessReturn(new StartProcessReturnDTO(instance.getId(), taskList.getFirst().getId()));
|
||||
}
|
||||
|
||||
private void saveBizExt(StartProcessContext context, Instance instance) {
|
||||
FlowInstanceBizExt bizExt = context.getBizExt();
|
||||
bizExt.setInstanceId(instance.getId());
|
||||
bizExt.setBusinessId(instance.getBusinessId());
|
||||
flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.workflow.liteflow.start;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeBooleanComponent;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.StartProcessContext;
|
||||
|
||||
/**
|
||||
* 判断启动流程时是否走已有实例续提交分支。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@LiteflowComponent("startExists")
|
||||
public class StartExistsComponent extends NodeBooleanComponent {
|
||||
|
||||
@Override
|
||||
public boolean processBoolean() {
|
||||
StartProcessContext context = getRequestData();
|
||||
return ObjectUtil.isNotNull(context.getExistingInstance());
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.dromara.workflow.liteflow.start;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.entity.Definition;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||
import org.dromara.workflow.domain.context.StartProcessContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 加载流程定义并补齐启动变量。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@LiteflowComponent("startPrepareInstance")
|
||||
public class StartPrepareInstanceComponent extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
StartProcessContext context = getRequestData();
|
||||
Definition definition = FlowEngine.defService().getPublishByFlowCode(context.getStartProcessBo().getFlowCode());
|
||||
if (ObjectUtil.isNull(definition)) {
|
||||
throw new ServiceException("流程【" + context.getStartProcessBo().getFlowCode() + "】未发布,请先在流程设计器中发布流程定义");
|
||||
}
|
||||
context.setDefinition(definition);
|
||||
|
||||
Map<String, Object> variables = context.getVariables();
|
||||
Dict dict = JsonUtils.parseMap(definition.getExt());
|
||||
boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(AUTO_PASS);
|
||||
variables.put(AUTO_PASS, autoPass);
|
||||
variables.put(BUSINESS_CODE, generateBusinessCode(context.getBizExt()));
|
||||
}
|
||||
|
||||
private String generateBusinessCode(FlowInstanceBizExt bizExt) {
|
||||
if (ObjectUtil.isNull(bizExt.getBusinessCode()) || bizExt.getBusinessCode().isBlank()) {
|
||||
// TODO: 按照自己业务规则生成编号
|
||||
String businessCode = Convert.toStr(System.currentTimeMillis());
|
||||
bizExt.setBusinessCode(businessCode);
|
||||
return businessCode;
|
||||
}
|
||||
return bizExt.getBusinessCode();
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.dromara.workflow.liteflow.start;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.query.QueryBuilder;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||
import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.context.StartProcessContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||
|
||||
/**
|
||||
* 准备流程启动请求。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("startPrepareRequest")
|
||||
public class StartPrepareRequestComponent extends NodeComponent {
|
||||
|
||||
private final FlowInstanceMapper flowInstanceMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
StartProcessContext context = getRequestData();
|
||||
String businessId = context.getStartProcessBo().getBusinessId();
|
||||
if (StringUtils.isBlank(businessId)) {
|
||||
throw new ServiceException("启动工作流时必须包含业务ID");
|
||||
}
|
||||
context.setBusinessId(businessId);
|
||||
context.setVariables(context.getStartProcessBo().getVariables());
|
||||
context.setBizExt(context.getStartProcessBo().getBizExt());
|
||||
|
||||
Map<String, Object> variables = context.getVariables();
|
||||
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
||||
variables.put(INITIATOR_DEPT_ID, LoginHelper.getDeptId());
|
||||
variables.put(BUSINESS_ID, businessId);
|
||||
|
||||
FlowInstance flowInstance = flowInstanceMapper.selectOne(QueryBuilder.lambda(FlowInstance.class)
|
||||
.eq(FlowInstance::getBusinessId, businessId)
|
||||
.build());
|
||||
context.setExistingInstance(flowInstance);
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package org.dromara.workflow.liteflow.start;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.warm.flow.core.entity.Task;
|
||||
import org.dromara.warm.flow.core.service.InsService;
|
||||
import org.dromara.warm.flow.core.service.TaskService;
|
||||
import org.dromara.warm.flow.orm.entity.FlowTask;
|
||||
import org.dromara.workflow.api.domain.StartProcessReturnDTO;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||
import org.dromara.workflow.domain.context.StartProcessContext;
|
||||
import org.dromara.workflow.mapper.FlwInstanceBizExtMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 已存在流程实例时执行续提交。
|
||||
*
|
||||
* @author may
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@RequiredArgsConstructor
|
||||
@LiteflowComponent("startResume")
|
||||
public class StartResumeComponent extends NodeComponent {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final InsService insService;
|
||||
private final FlwInstanceBizExtMapper flwInstanceBizExtMapper;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
StartProcessContext context = getRequestData();
|
||||
BusinessStatusEnum.checkStartStatus(context.getExistingInstance().getFlowStatus());
|
||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(context.getExistingInstance().getId()));
|
||||
if (CollUtil.isEmpty(taskList)) {
|
||||
throw new ServiceException("流程实例缺少任务,请检查流程定义配置");
|
||||
}
|
||||
taskService.mergeVariable(context.getExistingInstance(), context.getVariables());
|
||||
insService.updateById(context.getExistingInstance());
|
||||
saveBizExt(context);
|
||||
context.setStartProcessReturn(new StartProcessReturnDTO(taskList.getFirst().getInstanceId(), taskList.getFirst().getId()));
|
||||
}
|
||||
|
||||
private void saveBizExt(StartProcessContext context) {
|
||||
FlowInstanceBizExt bizExt = context.getBizExt();
|
||||
bizExt.setInstanceId(context.getExistingInstance().getId());
|
||||
bizExt.setBusinessId(context.getExistingInstance().getBusinessId());
|
||||
flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
删除流程实例链路:
|
||||
1. 按业务 id 或实例 id 加载待删除实例
|
||||
2. 存在待删除实例时校验权限并发布业务删除事件
|
||||
3. 按运行实例或历史实例模式执行删除;不存在实例时直接返回 false
|
||||
-->
|
||||
<chain name="deleteInstanceChain">
|
||||
THEN(
|
||||
instanceDeleteLoad,
|
||||
IF(
|
||||
instanceDeleteExists,
|
||||
THEN(
|
||||
instanceDeleteEvent,
|
||||
instanceDeleteExecute
|
||||
),
|
||||
noop
|
||||
)
|
||||
);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
启动流程链路:
|
||||
1. 初始化请求并查询已有实例
|
||||
2. 已存在实例时走续提交并返回当前任务
|
||||
3. 不存在实例时加载流程定义并补齐变量
|
||||
4. 新启动实例、保存业务扩展并构建返回结果
|
||||
-->
|
||||
<chain name="startProcessChain">
|
||||
THEN(
|
||||
startPrepareRequest,
|
||||
IF(
|
||||
startExists,
|
||||
startResume,
|
||||
THEN(
|
||||
startPrepareInstance,
|
||||
startExecute
|
||||
)
|
||||
)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!--
|
||||
办理任务链路:
|
||||
1. 加载任务实例、补齐变量并解析办理人
|
||||
2. 构建参数并执行当前任务跳转
|
||||
3. 开启自动审批时继续办理当前处理人的后续任务
|
||||
-->
|
||||
<chain name="completeTaskChain">
|
||||
THEN(
|
||||
completePrepare,
|
||||
completeExecute,
|
||||
IF(
|
||||
completeNeedAutoPass,
|
||||
completeAutoPass,
|
||||
noop
|
||||
)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!--
|
||||
任务操作链路:
|
||||
1. 解析操作类型、校验入参并构建参数
|
||||
2. 加载任务节点并校验操作约束
|
||||
3. 执行任务操作
|
||||
4. 操作成功且配置消息类型时发送通知
|
||||
-->
|
||||
<chain name="taskOperationChain">
|
||||
THEN(
|
||||
taskOpPrepare,
|
||||
taskOpLoad,
|
||||
taskOpExecute,
|
||||
IF(
|
||||
taskOpNeedNotify,
|
||||
taskOpNotify,
|
||||
noop
|
||||
)
|
||||
);
|
||||
</chain>
|
||||
</flow>
|
||||
Reference in New Issue
Block a user