1
1
package pers.acp.admin.workflow.domain
2
2
3
+ import org.flowable.bpmn.model.BpmnModel
3
4
import org.flowable.bpmn.model.FlowElement
4
5
import org.flowable.bpmn.model.FlowNode
6
+ import org.flowable.bpmn.model.SequenceFlow
5
7
import org.flowable.engine.*
6
- import org.flowable.engine.history.*
8
+ import org.flowable.engine.history.HistoricActivityInstance
9
+ import org.flowable.engine.history.HistoricVariableUpdate
7
10
import org.flowable.task.api.TaskInfo
8
11
import org.springframework.beans.factory.annotation.Autowired
9
12
import org.springframework.beans.factory.annotation.Qualifier
@@ -16,7 +19,6 @@ import pers.acp.admin.workflow.constant.WorkFlowParamKey
16
19
import pers.acp.core.CommonTools
17
20
import pers.acp.spring.boot.exceptions.ServerException
18
21
import pers.acp.spring.boot.interfaces.LogAdapter
19
-
20
22
import java.io.InputStream
21
23
22
24
/* *
@@ -247,21 +249,24 @@ constructor(private val logAdapter: LogAdapter,
247
249
fun generateDiagram (processInstanceId : String ): InputStream =
248
250
try {
249
251
val processDefinitionId = if (isFinished(processInstanceId)) {
250
- val pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult()
251
- pi.processDefinitionId
252
+ historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().processDefinitionId
252
253
} else {
253
- val pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult()
254
- pi.processDefinitionId
254
+ runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().processDefinitionId
255
255
}
256
- val activityIdList: MutableList <String > = mutableListOf ()
257
- val historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list()
258
- historicActivityInstanceList.forEach { activityIdList.add(it.activityId) }
259
- val flows: MutableList <String > = mutableListOf ()
256
+
257
+ // 将已经执行的节点ID放入高亮显示节点集合
258
+ val historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
259
+ .orderByHistoricActivityInstanceStartTime().asc().list()
260
+ val highLightedActivityIdList: MutableList <String > = mutableListOf ()
261
+ historicActivityInstanceList.forEach { highLightedActivityIdList.add(it.activityId) }
262
+
260
263
// 获取流程图
261
264
val model = repositoryService.getBpmnModel(processDefinitionId)
265
+ // 获取已流经的流程线,需要高亮显示高亮流程已发生流转的线id集合
266
+ val flows: MutableList <String > = getHighLightedFlows(model, historicActivityInstanceList)
262
267
val engineConfiguration = processEngine.processEngineConfiguration
263
268
val diagramGenerator = engineConfiguration.processDiagramGenerator
264
- diagramGenerator.generateDiagram(model, " bmp" , activityIdList , flows,
269
+ diagramGenerator.generateDiagram(model, " bmp" , highLightedActivityIdList , flows,
265
270
engineConfiguration.activityFontName, engineConfiguration.labelFontName, engineConfiguration.annotationFontName,
266
271
engineConfiguration.classLoader, 1.0 , true )
267
272
} catch (e: Exception ) {
@@ -279,4 +284,101 @@ constructor(private val logAdapter: LogAdapter,
279
284
return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId).count() > 0
280
285
}
281
286
287
+ /* *
288
+ * 获取已流经的流程线,需要高亮显示高亮流程已发生流转的线id集合
289
+ * @param model
290
+ * @param historicActivityInstanceList
291
+ */
292
+ private fun getHighLightedFlows (model : BpmnModel , historicActivityInstanceList : List <HistoricActivityInstance >): MutableList <String > {
293
+ // 已流经的流程线,需要高亮显示
294
+ val highLightedFlowIdList: MutableList <String > = mutableListOf ()
295
+ // 全部活动节点
296
+ val allHistoricActivityNodeList: MutableList <FlowNode > = mutableListOf ()
297
+ // 已完成的历史活动节点
298
+ val finishedActivityInstanceList: MutableList <HistoricActivityInstance > = mutableListOf ()
299
+ historicActivityInstanceList.forEach {
300
+ // 获取流程节点
301
+ val flowNode = model.mainProcess.getFlowElement(it.activityId, true ) as FlowNode
302
+ allHistoricActivityNodeList.add(flowNode)
303
+ // 结束时间不为空,当前节点则已经完成
304
+ it.endTime?.apply { finishedActivityInstanceList.add(it) }
305
+ }
306
+ // 当前流程节点
307
+ var currentFlowNode: FlowNode ?
308
+ // 目标流程节点
309
+ var targetFlowNode: FlowNode ?
310
+ // 当前活动实例
311
+ var currentActivityInstance: HistoricActivityInstance
312
+ // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
313
+ for (k in finishedActivityInstanceList.indices) {
314
+ currentActivityInstance = finishedActivityInstanceList[k]
315
+ currentFlowNode = model.mainProcess.getFlowElement(currentActivityInstance
316
+ .activityId, true ) as FlowNode
317
+ // 当前节点的所有流出线
318
+ val outgoingFlowList: List <SequenceFlow > = currentFlowNode.outgoingFlows
319
+ /* *
320
+ * 遍历outgoingFlows并找到已流转的 满足如下条件认为已流转:
321
+ * 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
322
+ * 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
323
+ * (第2点有问题,有过驳回的,会只绘制驳回的流程线,通过走向下一级的流程线没有高亮显示)
324
+ */
325
+ if (" parallelGateway" == currentActivityInstance.activityType || " inclusiveGateway" == currentActivityInstance.activityType) {
326
+ // 遍历历史活动节点,找到匹配流程目标节点的
327
+ outgoingFlowList.forEach {
328
+ // 获取当前节点流程线对应的下级节点
329
+ targetFlowNode = model.mainProcess.getFlowElement(it.targetRef,
330
+ true ) as FlowNode
331
+ // 如果下级节点包含在所有历史节点中,则将当前节点的流出线高亮显示
332
+ targetFlowNode?.apply {
333
+ if (allHistoricActivityNodeList.contains(this )) {
334
+ highLightedFlowIdList.add(it.id)
335
+ }
336
+ }
337
+ }
338
+ } else {
339
+ /* *
340
+ * 2、当前节点不是并行网关或兼容网关
341
+ * 【已解决-问题】如果当前节点有驳回功能,驳回到申请节点,
342
+ * 则因为申请节点在历史节点中,导致当前节点驳回到申请节点的流程线被高亮显示,但实际并没有进行驳回操作
343
+ */
344
+ // 当前节点ID
345
+ val currentActivityId: String = currentActivityInstance.activityId
346
+ var ifStartFind = false
347
+ var ifFinded = false
348
+ var historicActivityInstance: HistoricActivityInstance
349
+ // 循环当前节点的所有流出线
350
+ // 循环所有历史节点
351
+ for (i in historicActivityInstanceList.indices) {
352
+ // 如果当前节点流程线对应的下级节点在历史节点中,则该条流程线进行高亮显示(【问题】有驳回流程线时,即使没有进行驳回操作,因为申请节点在历史节点中,也会将驳回流程线高亮显示-_-||)
353
+ // 历史节点
354
+ historicActivityInstance = historicActivityInstanceList[i]
355
+ // 如果循环历史节点中的id等于当前节点id,从当前历史节点继续先后查找是否有当前节点流程线等于的节点
356
+ // 历史节点的序号需要大于等于已完成历史节点的序号,防止驳回重审一个节点经过两次是只取第一次的流出线高亮显示,第二次的不显示
357
+ if (i >= k && historicActivityInstance.activityId == currentActivityId) {
358
+ ifStartFind = true
359
+ // 跳过当前节点继续查找下一个节点
360
+ continue
361
+ }
362
+ if (ifStartFind) {
363
+ ifFinded = false
364
+ for (sequenceFlow in outgoingFlowList) {
365
+ // 如果当前节点流程线对应的下级节点在其后面的历史节点中,则该条流程线进行高亮显示
366
+ if (historicActivityInstance.activityId == sequenceFlow.targetRef) {
367
+ highLightedFlowIdList.add(sequenceFlow.id)
368
+ // 暂时默认找到离当前节点最近的下一级节点即退出循环,否则有多条流出线时将全部被高亮显示
369
+ ifFinded = true
370
+ break
371
+ }
372
+ }
373
+ }
374
+ if (ifFinded) {
375
+ // 暂时默认找到离当前节点最近的下一级节点即退出历史节点循环,否则有多条流出线时将全部被高亮显示
376
+ break
377
+ }
378
+ }
379
+ }
380
+ }
381
+ return highLightedFlowIdList
382
+ }
383
+
282
384
}
0 commit comments