001/* 002 * Copyright 2024-2025, Warm-Flow (290631660@qq.com). 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.dromara.warm.flow.core.service.impl; 017 018import org.dromara.warm.flow.core.FlowFactory; 019import org.dromara.warm.flow.core.constant.ExceptionCons; 020import org.dromara.warm.flow.core.dao.FlowInstanceDao; 021import org.dromara.warm.flow.core.dto.FlowParams; 022import org.dromara.warm.flow.core.entity.*; 023import org.dromara.warm.flow.core.enums.ActivityStatus; 024import org.dromara.warm.flow.core.enums.FlowStatus; 025import org.dromara.warm.flow.core.enums.NodeType; 026import org.dromara.warm.flow.core.listener.Listener; 027import org.dromara.warm.flow.core.listener.ListenerVariable; 028import org.dromara.warm.flow.core.orm.service.impl.WarmServiceImpl; 029import org.dromara.warm.flow.core.service.InsService; 030import org.dromara.warm.flow.core.utils.*; 031 032import java.util.ArrayList; 033import java.util.Date; 034import java.util.List; 035import java.util.stream.Collectors; 036 037/** 038 * 流程实例Service业务层处理 039 * 040 * @author warm 041 * @since 2023-03-29 042 */ 043public class InsServiceImpl extends WarmServiceImpl<FlowInstanceDao<Instance>, Instance> implements InsService { 044 045 @Override 046 public InsService setDao(FlowInstanceDao<Instance> warmDao) { 047 this.warmDao = warmDao; 048 return this; 049 } 050 051 @Override 052 public Instance start(String businessId, FlowParams flowParams) { 053 AssertUtil.isNull(flowParams.getFlowCode(), ExceptionCons.NULL_FLOW_CODE); 054 AssertUtil.isEmpty(businessId, ExceptionCons.NULL_BUSINESS_ID); 055 // 获取已发布的流程节点 056 List<Node> nodes = FlowFactory.nodeService().getByFlowCode(flowParams.getFlowCode()); 057 AssertUtil.isEmpty(nodes, String.format(ExceptionCons.NOT_PUBLISH_NODE, flowParams.getFlowCode())); 058 // 获取开始节点 059 Node startNode = nodes.stream().filter(t -> NodeType.isStart(t.getNodeType())).findFirst().orElse(null); 060 AssertUtil.isNull(startNode, ExceptionCons.LOST_START_NODE); 061 // 获取下一个节点,如果是网关节点,则重新获取后续节点 062 List<Node> nextNodes = FlowFactory.nodeService().getNextByCheckGateway(flowParams.getVariable() 063 , getFirstBetween(startNode)); 064 065 // 判断流程定义是否激活状态 066 Definition definition = FlowFactory.defService().getById(nextNodes.get(0).getDefinitionId()); 067 AssertUtil.isTrue(definition.getActivityStatus().equals(ActivityStatus.SUSPENDED.getKey()) 068 , ExceptionCons.NOT_DEFINITION_ACTIVITY); 069 070 // 执行开始监听器 071 ListenerUtil.executeListener(new ListenerVariable(definition, null, startNode, flowParams.getVariable()) 072 .setFlowParams(flowParams), Listener.LISTENER_START); 073 074 // 设置流程实例对象 075 Instance instance = setStartInstance(nextNodes.get(0), businessId, flowParams); 076 077 // 判断开始结点和下一结点是否有权限监听器,有执行权限监听器node.setPermissionFlag,无走数据库的权限标识符 078 ListenerUtil.executeGetNodePermission(new ListenerVariable(definition, instance, startNode, flowParams.getVariable() 079 , null, nextNodes).setFlowParams(flowParams)); 080 081 // 设置历史任务 082 List<HisTask> hisTasks = setHisTask(nextNodes, flowParams, startNode, instance.getId()); 083 084 List<Task> addTasks = StreamUtils.toList(nextNodes, node -> FlowFactory.taskService() 085 .addTask(node, instance, definition, flowParams)); 086 087 // 办理人变量替换 088 if (CollUtil.isNotEmpty(addTasks)) { 089 addTasks.forEach(addTask -> addTask.getPermissionList().replaceAll(s -> VariableUtil.eval(s, flowParams.getVariable()))); 090 } 091 092 // 执行分派监听器 093 ListenerUtil.executeListener(new ListenerVariable(definition, instance, startNode, flowParams.getVariable() 094 , null, nextNodes, addTasks).setFlowParams(flowParams), Listener.LISTENER_ASSIGNMENT); 095 096 097 // 开启流程,保存流程信息 098 saveFlowInfo(instance, addTasks, hisTasks); 099 100 // 执行结束监听器和下一节点的节点开始监听器 101 ListenerUtil.endCreateListener(new ListenerVariable(definition, instance, startNode, flowParams.getVariable() 102 , null, nextNodes, addTasks).setFlowParams(flowParams)); 103 104 return instance; 105 } 106 107 @Override 108 public Instance skipByInsId(Long instanceId, FlowParams flowParams) { 109 AssertUtil.isTrue(StringUtils.isNotEmpty(flowParams.getMessage()) 110 && flowParams.getMessage().length() > 500, ExceptionCons.MSG_OVER_LENGTH); 111 // 获取待办任务 112 List<Task> taskList = FlowFactory.taskService().list(FlowFactory.newTask().setInstanceId(instanceId)); 113 AssertUtil.isEmpty(taskList, ExceptionCons.NOT_FOUNT_TASK); 114 AssertUtil.isTrue(taskList.size() > 1, ExceptionCons.TASK_NOT_ONE); 115 Task task = taskList.get(0); 116 return FlowFactory.taskService().skip(flowParams, task); 117 } 118 119 @Override 120 public Instance termination(Long instanceId, FlowParams flowParams) { 121 // 获取待办任务 122 List<Task> taskList = FlowFactory.taskService().list(FlowFactory.newTask().setInstanceId(instanceId)); 123 AssertUtil.isEmpty(taskList, ExceptionCons.NOT_FOUNT_TASK); 124 Task task = taskList.get(0); 125 return FlowFactory.taskService().termination(task, flowParams); 126 } 127 128 @Override 129 public boolean remove(List<Long> instanceIds) { 130 return toRemoveTask(instanceIds); 131 } 132 133 134 /** 135 * 设置历史任务 136 * 137 * @param nextNodes 下一节点集合 138 * @param flowParams 流程参数 139 * @param startNode 开始节点 140 * @param instanceId 流程实例id 141 */ 142 private List<HisTask> setHisTask(List<Node> nextNodes, FlowParams flowParams, Node startNode, Long instanceId) { 143 Task startTask = FlowFactory.newTask() 144 .setInstanceId(instanceId) 145 .setDefinitionId(startNode.getDefinitionId()) 146 .setNodeCode(startNode.getNodeCode()) 147 .setNodeName(startNode.getNodeName()) 148 .setNodeType(startNode.getNodeType()); 149 FlowFactory.dataFillHandler().idFill(startTask); 150 // 开始任务转历史任务 151 return FlowFactory.hisTaskService().setSkipInsHis(startTask, nextNodes, flowParams); 152 } 153 154 /** 155 * 开启流程,保存流程信息 156 * 157 * @param instance 流程实例 158 * @param addTasks 新增任务 159 * @param hisTasks 历史任务 160 */ 161 private void saveFlowInfo(Instance instance, List<Task> addTasks, List<HisTask> hisTasks) { 162 // 待办任务设置处理人 163 List<User> users = FlowFactory.userService().taskAddUsers(addTasks); 164 FlowFactory.hisTaskService().saveBatch(hisTasks); 165 FlowFactory.taskService().saveBatch(addTasks); 166 FlowFactory.userService().saveBatch(users); 167 save(instance); 168 } 169 170 /** 171 * 设置流程实例对象 172 * 173 * @param firstBetweenNode 第一个中间节点 174 * @param businessId 业务id 175 * @return Instance 176 */ 177 private Instance setStartInstance(Node firstBetweenNode, String businessId 178 , FlowParams flowParams) { 179 Instance instance = FlowFactory.newIns(); 180 Date now = new Date(); 181 FlowFactory.dataFillHandler().idFill(instance); 182 // 关联业务id,起始后面可以不用到业务id,传业务id目前来看只是为了批量创建流程的时候能创建出有区别化的流程,也是为了后期需要用到businessId。 183 instance.setDefinitionId(firstBetweenNode.getDefinitionId()) 184 .setBusinessId(businessId) 185 .setNodeType(firstBetweenNode.getNodeType()) 186 .setNodeCode(firstBetweenNode.getNodeCode()) 187 .setNodeName(firstBetweenNode.getNodeName()) 188 .setFlowStatus(ObjectUtil.isNotNull(flowParams.getFlowStatus())? flowParams.getFlowStatus() 189 : FlowStatus.TOBESUBMIT.getKey()) 190 .setActivityStatus(ActivityStatus.ACTIVITY.getKey()) 191 .setVariable(FlowFactory.jsonConvert.mapToStr(flowParams.getVariable())) 192 .setCreateTime(now) 193 .setUpdateTime(now) 194 .setCreateBy(flowParams.getHandler()) 195 .setExt(flowParams.getExt()); 196 return instance; 197 } 198 199 /** 200 * 有且只能有一个开始节点 201 * 202 * @param startNode 开始节点 203 * @return Node 204 */ 205 private Node getFirstBetween(Node startNode) { 206 List<Skip> skips = FlowFactory.skipService().list(FlowFactory.newSkip() 207 .setDefinitionId(startNode.getDefinitionId()).setNowNodeCode(startNode.getNodeCode())); 208 Skip skip = skips.get(0); 209 return FlowFactory.nodeService().getOne(FlowFactory.newNode().setDefinitionId(startNode.getDefinitionId()) 210 .setNodeCode(skip.getNextNodeCode())); 211 } 212 213 private boolean toRemoveTask(List<Long> instanceIds) { 214 AssertUtil.isEmpty(instanceIds, ExceptionCons.NULL_INSTANCE_ID); 215 216 List<Long> taskIds = new ArrayList<>(); 217 instanceIds.forEach(instanceId -> taskIds.addAll( 218 FlowFactory.taskService() 219 .list(FlowFactory.newTask().setInstanceId(instanceId)) 220 .stream() 221 .map(Task::getId) 222 .collect(Collectors.toList()))); 223 224 FlowFactory.userService().deleteByTaskIds(taskIds); 225 226 boolean success = FlowFactory.taskService().deleteByInsIds(instanceIds); 227 if (success) { 228 FlowFactory.hisTaskService().deleteByInsIds(instanceIds); 229 return FlowFactory.insService().removeByIds(instanceIds); 230 } 231 return false; 232 } 233 234 @Override 235 public boolean active(Long id) { 236 Instance instance = getById(id); 237 AssertUtil.isTrue(instance.getActivityStatus().equals(ActivityStatus.ACTIVITY.getKey()), ExceptionCons.INSTANCE_ALREADY_ACTIVITY); 238 instance.setActivityStatus(ActivityStatus.ACTIVITY.getKey()); 239 return updateById(instance); 240 } 241 242 @Override 243 public boolean unActive(Long id) { 244 Instance instance = getById(id); 245 AssertUtil.isTrue(instance.getActivityStatus().equals(ActivityStatus.SUSPENDED.getKey()), ExceptionCons.INSTANCE_ALREADY_SUSPENDED); 246 instance.setActivityStatus(ActivityStatus.SUSPENDED.getKey()); 247 return updateById(instance); 248 } 249}