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.dom4j.Document; 019import org.dromara.warm.flow.core.FlowFactory; 020import org.dromara.warm.flow.core.chart.*; 021import org.dromara.warm.flow.core.constant.ExceptionCons; 022import org.dromara.warm.flow.core.dao.FlowDefinitionDao; 023import org.dromara.warm.flow.core.dto.FlowCombine; 024import org.dromara.warm.flow.core.entity.*; 025import org.dromara.warm.flow.core.enums.ActivityStatus; 026import org.dromara.warm.flow.core.enums.NodeType; 027import org.dromara.warm.flow.core.enums.PublishStatus; 028import org.dromara.warm.flow.core.enums.SkipType; 029import org.dromara.warm.flow.core.exception.FlowException; 030import org.dromara.warm.flow.core.orm.service.impl.WarmServiceImpl; 031import org.dromara.warm.flow.core.service.DefService; 032import org.dromara.warm.flow.core.utils.Base64; 033import org.dromara.warm.flow.core.utils.*; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037import javax.imageio.ImageIO; 038import java.awt.*; 039import java.awt.image.BufferedImage; 040import java.io.ByteArrayInputStream; 041import java.io.ByteArrayOutputStream; 042import java.io.IOException; 043import java.io.InputStream; 044import java.nio.charset.StandardCharsets; 045import java.util.List; 046import java.util.*; 047import java.util.stream.Collectors; 048 049/** 050 * 流程定义Service业务层处理 051 * 052 * @author warm 053 * @since 2023-03-29 054 */ 055public class DefServiceImpl extends WarmServiceImpl<FlowDefinitionDao<Definition>, Definition> implements DefService { 056 057 private static final Logger log = LoggerFactory.getLogger(DefServiceImpl.class); 058 059 @Override 060 public DefService setDao(FlowDefinitionDao<Definition> warmDao) { 061 this.warmDao = warmDao; 062 return this; 063 } 064 065 @Override 066 public Definition importXml(InputStream is) throws Exception { 067 if (ObjectUtil.isNull(is)) { 068 return null; 069 } 070 FlowCombine combine = FlowConfigUtil.readConfig(is); 071 // 流程定义 072 Definition definition = combine.getDefinition(); 073 // 所有的流程节点 074 List<Node> allNodes = combine.getAllNodes(); 075 // 所有的流程连线 076 List<Skip> allSkips = combine.getAllSkips(); 077 // 根据不同策略进行新增 078 insertFlow(definition, allNodes, allSkips); 079 return definition; 080 } 081 082 @Override 083 public void saveXml(Definition def) throws Exception { 084 saveXml(def.getId(), def.getXmlString()); 085 } 086 087 @Override 088 public void saveXml(Long id, String xmlString) throws Exception { 089 if (ObjectUtil.isNull(id) || StringUtils.isEmpty(xmlString)) { 090 return; 091 } 092 FlowCombine combine = FlowConfigUtil.readConfig(new ByteArrayInputStream 093 (xmlString.getBytes(StandardCharsets.UTF_8))); 094 // 所有的流程节点 095 List<Node> allNodes = combine.getAllNodes(); 096 // 所有的流程连线 097 List<Skip> allSkips = combine.getAllSkips(); 098 099 FlowFactory.nodeService().remove(FlowFactory.newNode().setDefinitionId(id)); 100 FlowFactory.skipService().remove(FlowFactory.newSkip().setDefinitionId(id)); 101 allNodes.forEach(node -> node.setDefinitionId(id)); 102 allSkips.forEach(skip -> skip.setDefinitionId(id)); 103 // 保存节点,流程连线,权利人 104 FlowFactory.nodeService().saveBatch(allNodes); 105 FlowFactory.skipService().saveBatch(allSkips); 106 } 107 108 @Override 109 public Document exportXml(Long id) { 110 Definition definition = getAllDataDefinition(id); 111 return FlowConfigUtil.createDocument(definition); 112 } 113 114 @Override 115 public String xmlString(Long id) { 116 Definition definition = getAllDataDefinition(id); 117 Document document = FlowConfigUtil.createDocument(definition); 118 return document.asXML(); 119 } 120 121 @Override 122 public List<Definition> queryByCodeList(List<String> flowCodeList) { 123 return getDao().queryByCodeList(flowCodeList); 124 } 125 126 @Override 127 public void closeFlowByCodeList(List<String> flowCodeList) { 128 getDao().closeFlowByCodeList(flowCodeList); 129 } 130 131 @Override 132 public boolean checkAndSave(Definition definition) { 133 String version = getNewVersion(definition); 134 definition.setVersion(version); 135 return save(definition); 136 } 137 138 /** 139 * 删除流程定义 140 * 141 * @param ids 142 */ 143 @Override 144 public boolean removeDef(List<Long> ids) { 145 FlowFactory.nodeService().deleteNodeByDefIds(ids); 146 FlowFactory.skipService().deleteSkipByDefIds(ids); 147 return removeByIds(ids); 148 } 149 150 @Override 151 public boolean publish(Long id) { 152 Definition definition = getById(id); 153 List<String> flowCodeList = Collections.singletonList(definition.getFlowCode()); 154 // 把之前的流程定义改为已失效 155 closeFlowByCodeList(flowCodeList); 156 157 Definition flowDefinition = FlowFactory.newDef(); 158 flowDefinition.setId(id); 159 flowDefinition.setIsPublish(PublishStatus.PUBLISHED.getKey()); 160 return updateById(flowDefinition); 161 } 162 163 @Override 164 public boolean unPublish(Long id) { 165 List<Task> tasks = FlowFactory.taskService().list(FlowFactory.newTask().setDefinitionId(id)); 166 AssertUtil.isNotEmpty(tasks, ExceptionCons.NOT_PUBLISH_TASK); 167 Definition definition = FlowFactory.newDef().setId(id); 168 definition.setIsPublish(PublishStatus.UNPUBLISHED.getKey()); 169 return updateById(definition); 170 } 171 172 @Override 173 public boolean copyDef(Long id) { 174 Definition definition = getById(id).copy(); 175 AssertUtil.isNull(definition, ExceptionCons.NOT_FOUNT_DEF); 176 177 List<Node> nodeList = FlowFactory.nodeService().list(FlowFactory.newNode().setDefinitionId(id)) 178 .stream().map(Node::copy).collect(Collectors.toList()); 179 List<Skip> skipList = FlowFactory.skipService().list(FlowFactory.newSkip().setDefinitionId(id)) 180 .stream().map(Skip::copy).collect(Collectors.toList()); 181 FlowFactory.dataFillHandler().idFill(definition.setId(null)); 182 definition.setVersion(definition.getVersion() + "_copy") 183 .setIsPublish(PublishStatus.UNPUBLISHED.getKey()) 184 .setCreateTime(null) 185 .setUpdateTime(null); 186 187 nodeList.forEach(node -> node.setId(null) 188 .setDefinitionId(definition.getId()) 189 .setVersion(definition.getVersion()) 190 .setCreateTime(null) 191 .setUpdateTime(null)); 192 FlowFactory.nodeService().saveBatch(nodeList); 193 194 skipList.forEach(skip -> skip.setId(null) 195 .setDefinitionId(definition.getId()) 196 .setCreateTime(null) 197 .setUpdateTime(null)); 198 FlowFactory.skipService().saveBatch(skipList); 199 return save(definition); 200 } 201 202 @Override 203 public boolean active(Long id) { 204 Definition definition = getById(id); 205 AssertUtil.isTrue(definition.getActivityStatus().equals(ActivityStatus.ACTIVITY.getKey()), ExceptionCons.DEFINITION_ALREADY_ACTIVITY); 206 definition.setActivityStatus(ActivityStatus.ACTIVITY.getKey()); 207 return updateById(definition); 208 } 209 210 @Override 211 public boolean unActive(Long id) { 212 Definition definition = getById(id); 213 AssertUtil.isTrue(definition.getActivityStatus().equals(ActivityStatus.SUSPENDED.getKey()), ExceptionCons.DEFINITION_ALREADY_SUSPENDED); 214 definition.setActivityStatus(ActivityStatus.SUSPENDED.getKey()); 215 return updateById(definition); 216 } 217 218 @Override 219 public String flowChart(Long instanceId) { 220 Long definitionId = FlowFactory.insService().getById(instanceId).getDefinitionId(); 221 return basicFlowChart(instanceId, definitionId); 222 } 223 224 @Override 225 public List<FlowChart> flowChartData(Long instanceId) { 226 Long definitionId = FlowFactory.insService().getById(instanceId).getDefinitionId(); 227 FlowChartChain flowChartChain = new FlowChartChain(); 228 basicFlowChart(instanceId, definitionId, flowChartChain); 229 return flowChartChain.getFlowChartList(); 230 } 231 232 @Override 233 public String flowChartNoColor(Long definitionId) { 234 return basicFlowChart(null, definitionId); 235 } 236 237 @Override 238 public List<FlowChart> flowChartNoColorData(Long definitionId) { 239 FlowChartChain flowChartChain = new FlowChartChain(); 240 basicFlowChart(null, definitionId, flowChartChain); 241 return flowChartChain.getFlowChartList(); 242 } 243 244 /** 245 * DefService 根据流程实例ID获取流程图的图片流(渲染颜色) 246 * @param instanceId 实例id 247 * @param definitionId 流程定义id 248 * @return 流程图base64字符串 249 */ 250 public String basicFlowChart(Long instanceId, Long definitionId) { 251 252 try { 253 FlowChartChain flowChartChain = new FlowChartChain(); 254 Map<String, Integer> nodeXY = basicFlowChart(instanceId, definitionId, flowChartChain); 255 256 // 清晰度 257 int n = 2; 258 int width = (nodeXY.get("maxX") + nodeXY.get("minX")) * n; 259 int height = (nodeXY.get("maxY") + nodeXY.get("minY")) * n; 260 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 261 262 // 获取图形上下文,graphics想象成一个画笔 263 Graphics2D graphics = image.createGraphics(); 264 graphics.setStroke(new BasicStroke((2 * n) + 1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); 265 Font font = new Font("宋体", Font.BOLD, 12 * n); 266 graphics.setFont(font); 267 // 消除线条锯齿 268 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 269 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 270 graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 271 272 // 对指定的矩形区域填充颜色: GREEN:绿色; 红色:RED; 灰色:GRAY 273 graphics.setColor(Color.WHITE); 274 graphics.fillRect(0, 0, width, height); 275 276 flowChartChain.draw(graphics, n); 277 graphics.setPaintMode(); 278 graphics.dispose();// 释放此图形的上下文并释放它所使用的所有系统资源 279 280 ByteArrayOutputStream os = new ByteArrayOutputStream(); 281 ImageIO.write(image, "png", os); 282 return Base64.encode(os.toByteArray()); 283 } catch (IOException e) { 284 log.error("获取流程图异常", e); 285 throw new FlowException("获取流程图异常"); 286 } 287 288 } 289 290 291 /** 292 * 获取流程图基本元数据 293 * @param instanceId 实例id 294 * @param definitionId 流程定义id 295 * @param flowChartChain 存储流程图基本元数据 296 * @return Map<String, Integer> 节点坐标信息 297 */ 298 public Map<String, Integer> basicFlowChart(Long instanceId, Long definitionId, FlowChartChain flowChartChain) { 299 Instance instance; 300 if (ObjectUtil.isNotNull(instanceId)) { 301 instance = FlowFactory.insService().getById(instanceId); 302 } else { 303 instance = null; 304 } 305 Map<String, Color> colorMap = new HashMap<>(); 306 Map<String, Integer> nodeXY = addNodeChart(colorMap, instance, definitionId, flowChartChain); 307 addSkipChart(colorMap, instance, definitionId, flowChartChain); 308 309 return nodeXY; 310 } 311 /** 312 * 添加跳转流程图 313 * 314 * @param colorMap 颜色映射 315 * @param instance 流程实例 316 * @param flowChartChain 流程图链 317 */ 318 private void addSkipChart(Map<String, Color> colorMap, Instance instance, Long definitionId, FlowChartChain flowChartChain) { 319 List<Skip> skipList = FlowFactory.skipService().list(FlowFactory.newSkip().setDefinitionId(definitionId)); 320 for (Skip skip : skipList) { 321 if (StringUtils.isNotEmpty(skip.getCoordinate())) { 322 String[] coordinateSplit = skip.getCoordinate().split("\\|"); 323 String[] skipSplit = coordinateSplit[0].split(";"); 324 int[] skipX = new int[skipSplit.length]; 325 int[] skipY = new int[skipSplit.length]; 326 TextChart textChart = null; 327 if (coordinateSplit.length > 1) { 328 String[] textSplit = coordinateSplit[1].split(","); 329 int textX = Integer.parseInt(textSplit[0].split("\\.")[0]); 330 int textY = Integer.parseInt(textSplit[1].split("\\.")[0]); 331 textChart = new TextChart(textX, textY, skip.getSkipName()); 332 } 333 334 for (int i = 0; i < skipSplit.length; i++) { 335 skipX[i] = Integer.parseInt(skipSplit[i].split(",")[0].split("\\.")[0]); 336 skipY[i] = Integer.parseInt(skipSplit[i].split(",")[1].split("\\.")[0]); 337 } 338 Color c; 339 if (ObjectUtil.isNotNull(instance)) { 340 c = colorGet(colorMap, "skip:" + skip.getId().toString()); 341 } else { 342 c = Color.BLACK; 343 } 344 flowChartChain.addFlowChart(new SkipChart(skipX, skipY, c, textChart)); 345 } 346 } 347 } 348 349 /** 350 * 添加节点流程图 351 * 352 * @param instance 流程实例 353 * @param flowChartChain 流程图链 354 */ 355 private Map<String, Integer> addNodeChart(Map<String, Color> colorMap, Instance instance, Long definitionId 356 , FlowChartChain flowChartChain) { 357 List<Node> nodeList = FlowFactory.nodeService().list(FlowFactory.newNode().setDefinitionId(definitionId)); 358 List<Skip> allSkips = FlowFactory.skipService().list(FlowFactory.newSkip() 359 .setDefinitionId(definitionId).setSkipType(SkipType.PASS.getKey())); 360 if (ObjectUtil.isNotNull(instance)) { 361 // 流程图渲染,过滤掉所有后置节点 362 List<Node> needChartNodes = filterNodes(instance, allSkips, nodeList); 363 setColorMap(colorMap, instance, allSkips, needChartNodes); 364 } 365 366 Map<String, Integer> maxR = new HashMap<>(); 367 maxR.put("minX", 5000); 368 maxR.put("minY", 5000); 369 maxR.put("maxX", 0); 370 maxR.put("maxY", 0); 371 372 for (Node node : nodeList) { 373 if (StringUtils.isNotEmpty(node.getCoordinate())) { 374 String[] coordinateSplit = node.getCoordinate().split("\\|"); 375 String[] nodeSplit = coordinateSplit[0].split(","); 376 int nodeX = Integer.parseInt(nodeSplit[0].split("\\.")[0]); 377 int nodeY = Integer.parseInt(nodeSplit[1].split("\\.")[0]); 378 if (nodeX > maxR.get("maxX")) { 379 maxR.put("maxX", nodeX); 380 } 381 if (nodeX < maxR.get("minX")) { 382 maxR.put("minX", nodeX); 383 } 384 if (nodeY > maxR.get("maxY")) { 385 maxR.put("maxY", nodeY); 386 } 387 if (nodeY < maxR.get("minY")) { 388 maxR.put("minY", nodeY); 389 } 390 TextChart textChart = null; 391 if (coordinateSplit.length > 1) { 392 String[] textSplit = coordinateSplit[1].split(","); 393 int textX = Integer.parseInt(textSplit[0].split("\\.")[0]); 394 int textY = Integer.parseInt(textSplit[1].split("\\.")[0]); 395 textChart = new TextChart(textX, textY, node.getNodeName()); 396 } 397 Color c; 398 if (ObjectUtil.isNotNull(instance)) { 399 c = colorGet(colorMap, "node:" + node.getNodeCode()); 400 } else { 401 c = Color.BLACK; 402 } 403 if (NodeType.isStart(node.getNodeType())) { 404 flowChartChain.addFlowChart(new OvalChart(nodeX, nodeY, ObjectUtil.isNotNull(instance) ? Color.GREEN : Color.BLACK, textChart)); 405 } else if (NodeType.isBetween(node.getNodeType())) { 406 flowChartChain.addFlowChart(new BetweenChart(nodeX, nodeY, c, textChart)); 407 } else if (NodeType.isGateWaySerial(node.getNodeType())) { 408 flowChartChain.addFlowChart(new SerialChart(nodeX, nodeY, c)); 409 } else if (NodeType.isGateWayParallel(node.getNodeType())) { 410 flowChartChain.addFlowChart(new ParallelChart(nodeX, nodeY, c)); 411 } else if (NodeType.isEnd(node.getNodeType())) { 412 flowChartChain.addFlowChart(new OvalChart(nodeX, nodeY, c, textChart)); 413 } 414 } 415 } 416 return maxR; 417 } 418 419 /** 420 * 流程图渲染,过滤掉当前任务后的节点 421 * 422 * @param instance 流程实例 423 * @param allSkips 所有跳转 424 * @param nodeList 节点集合 425 * @return 过滤后的节点列表 426 */ 427 private List<Node> filterNodes(Instance instance, List<Skip> allSkips, List<Node> nodeList) { 428 List<String> allNextNode = new ArrayList<>(); 429 Map<String, List<Skip>> skipNextMap = StreamUtils.groupByKey(allSkips, Skip::getNowNodeCode); 430 if (NodeType.isEnd(instance.getNodeType())) { 431 return nodeList; 432 } 433 List<Task> curTasks = FlowFactory.taskService().list(FlowFactory.newTask().setInstanceId(instance.getId())); 434 for (Task curTask : curTasks) { 435 List<Skip> nextSkips = skipNextMap.get(curTask.getNodeCode()); 436 getAllNextNode(nextSkips, allNextNode, skipNextMap); 437 } 438 return StreamUtils.filter(nodeList, node -> !allNextNode.contains(node.getNodeCode())); 439 } 440 441 /** 442 * 获取待办任务节点后的所有节点 443 * 444 * @param nextSkips 当前节点对应的所有跳转 445 * @param allNextNode 所有下个任务节点 446 */ 447 private void getAllNextNode(List<Skip> nextSkips, List<String> allNextNode, Map<String, List<Skip>> skipMap) { 448 if (CollUtil.isNotEmpty(nextSkips)) { 449 for (Skip nextSkip : nextSkips) { 450 allNextNode.add(nextSkip.getNextNodeCode()); 451 List<Skip> nextNextSkips = skipMap.get(nextSkip.getNextNodeCode()); 452 getAllNextNode(nextNextSkips, allNextNode, skipMap); 453 } 454 } 455 } 456 457 /** 458 * 设置节点和跳转对应的颜色 459 * 460 * @param colorMap 颜色map 461 * @param instance 流程实例 462 * @param allSkips 所有跳转 463 * @param nodeList 节点集合 464 */ 465 public void setColorMap(Map<String, Color> colorMap, Instance instance, List<Skip> allSkips 466 , List<Node> nodeList) { 467 final Color color = Color.PINK; 468 Map<String, List<Skip>> skipLastMap = StreamUtils.groupByKey(allSkips, Skip::getNextNodeCode); 469 Map<String, List<Skip>> skipNextMap = StreamUtils.groupByKey(allSkips, Skip::getNowNodeCode); 470 List<HisTask> hisTaskList = FlowFactory.hisTaskService().getNoReject(instance.getId()); 471 for (Node node : nodeList) { 472 List<Skip> oneNextSkips = skipNextMap.get(node.getNodeCode()); 473 List<Skip> oneLastSkips = skipLastMap.get(node.getNodeCode()); 474 if (NodeType.isStart(node.getNodeType())) { 475 colorPut(colorMap, "node:" + node.getNodeCode(), Color.GREEN); 476 if (CollUtil.isNotEmpty(oneNextSkips)) { 477 oneNextSkips.forEach(oneNextSkip -> colorPut(colorMap, "skip:" + oneNextSkip.getId().toString(), Color.GREEN)); 478 } 479 continue; 480 } 481 if (NodeType.isGateWay(node.getNodeType())) { 482 continue; 483 } 484 Task task = FlowFactory.taskService() 485 .getOne(FlowFactory.newTask().setNodeCode(node.getNodeCode()).setInstanceId(instance.getId())); 486 HisTask curHisTask = FlowFactory.hisTaskService() 487 .getNoReject(node.getNodeCode(), null, hisTaskList); 488 489 if (CollUtil.isNotEmpty(oneLastSkips)) { 490 for (Skip oneLastSkip : oneLastSkips) { 491 Color c = null; 492 if (NodeType.isStart(oneLastSkip.getNowNodeType()) && task == null) { 493 colorPut(colorMap, "node:" + node.getNodeCode(), Color.GREEN); 494 setNextColorMap(colorMap, oneNextSkips, Color.GREEN); 495 } else if (NodeType.isGateWay(oneLastSkip.getNowNodeType())) { 496 // 如果前置节点是网关,那网关前任意一个任务完成就算完成 497 List<Skip> twoLastSkips = skipLastMap.get(oneLastSkip.getNowNodeCode()); 498 for (Skip twoLastSkip : twoLastSkips) { 499 HisTask twoLastHisTask = FlowFactory.hisTaskService() 500 .getNoReject(twoLastSkip.getNowNodeCode(), node.getNodeCode(), hisTaskList); 501 502 // 前前置节点完成时间是否早于前置节点,如果是串行网关,那前前置节点必须只有一个完成,如果是并行网关都要完成 503 if (task != null) { 504 c = color; 505 if (ObjectUtil.isNotNull(twoLastHisTask)) { 506 colorPut(colorMap, "skip:" + oneLastSkip.getId().toString(), Color.GREEN); 507 colorPut(colorMap, "node:" + oneLastSkip.getNowNodeCode(), Color.GREEN); 508 } 509 } else { 510 if (NodeType.isEnd(node.getNodeType()) && NodeType.isEnd(instance.getNodeType())) { 511 HisTask curHisTaskN = FlowFactory.hisTaskService() 512 .getNoReject(null, node.getNodeCode(), hisTaskList); 513 if (ObjectUtil.isNotNull(curHisTaskN)) { 514 c = Color.GREEN; 515 curHisTaskN = FlowFactory.hisTaskService() 516 .getNoReject(twoLastSkip.getNowNodeCode(), node.getNodeCode(), hisTaskList); 517 if (ObjectUtil.isNotNull(curHisTaskN)) { 518 colorPut(colorMap, "skip:" + oneLastSkip.getId().toString(), c); 519 colorPut(colorMap, "node:" + oneLastSkip.getNowNodeCode(), c); 520 } 521 } 522 } else if (curHisTask != null && ObjectUtil.isNotNull(twoLastHisTask) && (twoLastHisTask.getUpdateTime() 523 .before(curHisTask.getUpdateTime()) || twoLastHisTask.getUpdateTime() 524 .equals(curHisTask.getUpdateTime()))) { 525 c = Color.GREEN; 526 colorPut(colorMap, "node:" + oneLastSkip.getNowNodeCode(), c); 527 } else { 528 c = Color.BLACK; 529 } 530 if (ObjectUtil.isNotNull(twoLastHisTask)) { 531 colorPut(colorMap, "skip:" + oneLastSkip.getId().toString(), c); 532 } 533 } 534 colorPut(colorMap, "node:" + node.getNodeCode(), c); 535 setNextColorMap(colorMap, oneNextSkips, c); 536 } 537 } else if (NodeType.isEnd(node.getNodeType()) && NodeType.isEnd(instance.getNodeType())) { 538 HisTask curHisTaskN = FlowFactory.hisTaskService() 539 .getNoReject(null, node.getNodeCode(), hisTaskList); 540 if (ObjectUtil.isNotNull(curHisTaskN)) { 541 colorPut(colorMap, "node:" + node.getNodeCode(), Color.GREEN); 542 curHisTaskN = FlowFactory.hisTaskService() 543 .getNoReject(oneLastSkip.getNowNodeCode(), node.getNodeCode(), hisTaskList); 544 if (ObjectUtil.isNotNull(curHisTaskN)) { 545 colorPut(colorMap, "skip:" + oneLastSkip.getId().toString(), Color.GREEN); 546 } 547 } 548 } else { 549 HisTask oneLastHisTask = FlowFactory.hisTaskService() 550 .getNoReject(oneLastSkip.getNowNodeCode(), node.getNodeCode(), hisTaskList); 551 // 前前置节点完成时间是否早于前置节点,如果是串行网关,那前前置节点必须只有一个完成,如果是并行网关都要完成 552 if (task != null) { 553 c = color; 554 } else if (curHisTask != null && ObjectUtil.isNotNull(oneLastHisTask) && (oneLastHisTask.getUpdateTime() 555 .before(curHisTask.getUpdateTime()) || oneLastHisTask.getUpdateTime() 556 .equals(curHisTask.getUpdateTime()))) { 557 c = Color.GREEN; 558 } else { 559 c = Color.BLACK; 560 } 561 562 if (ObjectUtil.isNotNull(oneLastHisTask)) { 563 colorPut(colorMap, "skip:" + oneLastSkip.getId().toString(), c); 564 } 565 colorPut(colorMap, "node:" + node.getNodeCode(), c); 566 setNextColorMap(colorMap, oneNextSkips, c); 567 } 568 } 569 } 570 } 571 } 572 573 /** 574 * 设置下个节点的颜色 575 * 576 * @param colorMap 颜色map 577 * @param oneNextSkips 下一个跳转 578 * @param c 颜色 579 */ 580 private void setNextColorMap(Map<String, Color> colorMap, List<Skip> oneNextSkips, Color c) { 581 if (CollUtil.isNotEmpty(oneNextSkips)) { 582 oneNextSkips.forEach(oneNextSkip -> { 583 colorPut(colorMap, "skip:" + oneNextSkip.getId().toString(), c); 584 if (NodeType.isGateWay(oneNextSkip.getNextNodeType()) && (c == Color.GREEN || c == Color.BLACK)) { 585 colorPut(colorMap, "node:" + oneNextSkip.getNextNodeCode(), c); 586 } 587 }); 588 } 589 } 590 591 /** 592 * 优先绿色 593 * 594 * @param colorMap 颜色map 595 * @param key key 596 * @param c color 597 */ 598 private void colorPut(Map<String, Color> colorMap, String key, Color c) { 599 Color color = colorMap.get(key); 600 if (c == Color.GREEN) { 601 colorMap.put(key, c); 602 } else if (color == null || color == Color.BLACK) { 603 colorMap.put(key, c); 604 } 605 } 606 607 private Color colorGet(Map<String, Color> colorMap, String key) { 608 Color color = colorMap.get(key); 609 if (color == null) { 610 color = Color.BLACK; 611 } 612 return color; 613 } 614 615 public Definition getAllDataDefinition(Long id) { 616 Definition definition = getDao().selectById(id); 617 List<Node> nodeList = FlowFactory.nodeService().list(FlowFactory.newNode().setDefinitionId(id)); 618 definition.setNodeList(nodeList); 619 List<Skip> skips = FlowFactory.skipService().list(FlowFactory.newSkip().setDefinitionId(id)); 620 Map<String, List<Skip>> flowSkipMap = skips.stream() 621 .collect(Collectors.groupingBy(Skip::getNowNodeCode)); 622 nodeList.forEach(flowNode -> flowNode.setSkipList(flowSkipMap.get(flowNode.getNodeCode()))); 623 return definition; 624 } 625 626 /** 627 * 每次只做新增操作,保证新增的flowCode+version是唯一的 628 * 629 * @param definition 流程定义 630 * @param allNodes 所有节点 631 * @param allSkips 所有跳转 632 */ 633 private void insertFlow(Definition definition, List<Node> allNodes, List<Skip> allSkips) { 634 String version = getNewVersion(definition); 635 definition.setVersion(version); 636 for (Node node : allNodes) { 637 node.setVersion(version); 638 } 639 FlowFactory.defService().save(definition); 640 FlowFactory.nodeService().saveBatch(allNodes); 641 FlowFactory.skipService().saveBatch(allSkips); 642 } 643 644 private String getNewVersion(Definition definition) { 645 List<String> flowCodeList = Collections.singletonList(definition.getFlowCode()); 646 List<Definition> definitions = getDao().queryByCodeList(flowCodeList); 647 int highestVersion = 0; 648 String latestNonPositiveVersion = null; 649 long latestTimestamp = Long.MIN_VALUE; 650 651 for (Definition otherDef : definitions) { 652 if (definition.getVersion() != null && definition.getFlowCode().equals(otherDef.getFlowCode()) 653 && definition.getVersion().equals(otherDef.getVersion())) { 654 throw new FlowException(definition.getFlowCode() + "(" + definition.getVersion() + ")" + ExceptionCons.ALREADY_EXIST); 655 } 656 if (definition.getFlowCode().equals(otherDef.getFlowCode())) { 657 try { 658 int version = Integer.parseInt(otherDef.getVersion()); 659 if (version > highestVersion) { 660 highestVersion = version; 661 } 662 } catch (NumberFormatException e) { 663 long timestamp = otherDef.getCreateTime().getTime(); 664 if (timestamp > latestTimestamp) { 665 latestTimestamp = timestamp; 666 latestNonPositiveVersion = otherDef.getVersion(); 667 } 668 } 669 } 670 } 671 String version = definition.getVersion(); 672 if (version == null || version.isEmpty()) { 673 if (highestVersion > 0) { 674 version = String.valueOf(highestVersion + 1); 675 } else if (latestNonPositiveVersion != null) { 676 version = latestNonPositiveVersion + "_1"; 677 } else { 678 version = "1"; 679 } 680 } 681 682 return version; 683 } 684 685}