1. bpmn-js
Download: https://bpmn.io/toolkit/bpmn-js/
The purpose of this article is not to write bpmn-js, but to directly copy a pre-made one as follows:
2. Business access address
http://localhost:8080/bpmnjs/dist/index.html?type=lookBpmn &instanceId=180001
& amp;deploymentFileUUID=8 & amp;deploymentName=qingjia.bpmn & amp;AssigneeName=zhangsan
3. The main logic code for JavaScript display is as follows:
//Example https://blog.csdn.net/qq_35664308/article/details/110469247 //Set color https://github.com/bpmn-io/bpmn-js-examples/tree/master/colors $.ajax({<!-- --> //Get highlight url: publicurl + 'activitiHistory/gethighLine', type: 'GET', data: param1, dataType:'json', success: function (result) {<!-- --> //Get the color fill to ColorJson // [{"name": "xx usertask name", // "stroke":"gray", // "fill":"#eae9e9"}...] var ColorJson=tools.getByColor(result.obj) $.ajax({<!-- --> //Get process definition url: publicurl + 'processDefinition/getDefinitionXML', type: 'GET', data: param, dataType:'text', success: function (result) {<!-- --> var newXmlData = result tools.createDiagram(newXmlData, bpmnModeler, container); setTimeout(function () {<!-- --> for (var i in ColorJson) {<!-- --> //Set flow chart color /** var modeling = bpmnModeler.get('modeling'); var elementRegistry = bpmnModeler.get('elementRegistry') var elementToColor = elementRegistry.get(json.name); if(elementToColor){ modeling.setColor([elementToColor], { stroke: json.stroke, fill: json.fill }); } **/ tools.setColor(ColorJson[i],bpmnModeler) } }, 200) }, error: function (err) {<!-- --> console.log(err) } }); },
task’s html color filling code
<rect x="0" y="0" width="85" height="55" rx="10" ry="10" style="stroke: green; stroke-width: 2px; fill: yellow; fill-opacity: 0.95;"></rect>
4. Java interface implementation, according to the business execution path, query the history table act_hi_procinst, node-node connection, node mark and mark node are currently passed to the executor.
/** *index.js * AssigneeName parameter is the handler * deploymentName act_ge_bytearray table name field xml name * deploymentFileUUID ID of the act_re_deployment table * instanceId instance ID * * http://localhost:8080/bpmnjs/dist/index.html?type=lookBpmn & amp;instanceId=10823123-92ac-11eb-9909-dc7196b7d4a6 & amp;deploymentFileUUID=z3d6aeda-91d0-11eb-95aa-dc7196b7d4a6 & amp ;deploymentName=springboot02.bpmn & amp;AssigneeName=salaboy */ @RestController @RequestMapping("/activitiHistory") public class ActivitiHistoryController {<!-- --> @Autowired private RepositoryService repositoryService; @Autowired private HistoryService historyService; //Get process definition XML @GetMapping(value = "/getDefinitionXML") public void getProcessDefineXML(HttpServletResponse response, @RequestParam("deploymentId") String deploymentId, @RequestParam("resourceName") String resourceName) {<!-- --> try {<!-- --> InputStream inputStream = repositoryService.getResourceAsStream(deploymentId,resourceName); int count = inputStream.available(); byte[] bytes = new byte[count]; response.setContentType("text/xml"); OutputStream outputStream = response.getOutputStream(); while (inputStream.read(bytes) != -1) {<!-- --> outputStream.write(bytes); } inputStream.close(); } catch (Exception e) {<!-- --> e.toString(); } } //task instance history @GetMapping(value = "/getInstancesByPiID") public AjaxResponse getInstancesByPiID(@RequestParam("piID") String piID) {<!-- --> try {<!-- --> //------------------------------------------------another way of writing -------------------------- List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery() .orderByHistoricTaskInstanceEndTime().asc() .processInstanceId(piID) .list(); return AjaxResponse.AjaxData(GlobalConfig.ResponseCode.SUCCESS.getCode(), GlobalConfig.ResponseCode.SUCCESS.getDesc(), historicTaskInstances); } catch (Exception e) {<!-- --> return AjaxResponse.AjaxData(GlobalConfig.ResponseCode.ERROR.getCode(), "Failed to obtain historical task", e.toString()); } } //Flowchart highlight @GetMapping("/gethighLine") public AjaxResponse gethighLine(@RequestParam("instanceId") String instanceId, String AssigneeName) {<!-- --> try {<!-- --> HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(instanceId).singleResult(); //Get bpmnModel object BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId()); //Because we only define one Process here, just get the first one in the collection Process process = bpmnModel.getProcesses().get(0); //Get all FlowElement information Collection<FlowElement> flowElements = process.getFlowElements(); Map<String, String> map = new HashMap<>(); for (FlowElement flowElement : flowElements) {<!-- --> //Determine whether it is connected if (flowElement instanceof SequenceFlow) {<!-- --> SequenceFlow sequenceFlow = (SequenceFlow) flowElement; String ref = sequenceFlow.getSourceRef(); String targetRef = sequenceFlow.getTargetRef(); map.put(ref + targetRef, sequenceFlow.getId()); } } //Get process instance historical nodes (all) List<HistoricActivityInstance> list1 = historyService.createHistoricActivityInstanceQuery() .processInstanceId(instanceId) .list(); //Remove delete reason data. Currently, there is no problem with jump, but there is a problem with execution. List<HistoricActivityInstance> list= new ArrayList<>(); for (HistoricActivityInstance h:list1) {<!-- --> if(StringUtils.isBlank(h.getDeleteReason())){<!-- --> list.add(h); } } //Pairwise combination key of each historical node Set<String> keyList = new HashSet<>(); for (HistoricActivityInstance i : list) {<!-- --> for (HistoricActivityInstance j : list) {<!-- --> if (i != j) {<!-- --> keyList.add(i.getActivityId() + j.getActivityId()); } } } //Highlight connection ID Set<String> highLine = new HashSet<>(); keyList.forEach(s -> highLine.add(map.get(s))); //Get process instance historical node (completed) List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery() .processInstanceId(instanceId) .finished() .list(); //Highlight node ID Set<String> highPoint = new HashSet<>(); listFinished.forEach(s -> highPoint.add(s.getActivityId())); //Get process instance historical node (to-do node) List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery() .processInstanceId(instanceId) .unfinished() .list(); //Highlighted connections that need to be removed Set<String> set = new HashSet<>(); //To-do highlighted node Set<String> waitingToDo = new HashSet<>(); listUnFinished.forEach(s -> {<!-- --> waitingToDo.add(s.getActivityId()); for (FlowElement flowElement : flowElements) {<!-- --> //Determine whether it is a user node if (flowElement instanceof UserTask) {<!-- --> UserTask userTask = (UserTask) flowElement; if (userTask.getId().equals(s.getActivityId())) {<!-- --> List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows(); //Because the highlighted connection query is all nodes combined in pairs, and the connections sent out after the to-do node are also included, so the connections immediately after the highlighted to-do node must be removed. if (outgoingFlows != null & amp; & amp; outgoingFlows.size() > 0) {<!-- --> outgoingFlows.forEach(a -> {<!-- --> if (a.getSourceRef().equals(s.getActivityId())) {<!-- --> set.add(a.getId()); } }); } } } } }); highLine.removeAll(set); //Get the current user //User sysUser = getSysUser(); Set<String> iDo = new HashSet<>(); //Save and highlight my management node //Tasks completed by the current user List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery() .taskAssignee(AssigneeName) .finished() .processInstanceId(instanceId).list(); taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey())); Map<String, Object> reMap = new HashMap<>(); reMap.put("highPoint", highPoint); reMap.put("highLine", highLine); reMap.put("waitingToDo", waitingToDo); reMap.put("iDo", iDo); return AjaxResponse.AjaxData(GlobalConfig.ResponseCode.SUCCESS.getCode(), GlobalConfig.ResponseCode.SUCCESS.getDesc(), reMap); } catch (Exception e) {<!-- --> return AjaxResponse.AjaxData(GlobalConfig.ResponseCode.ERROR.getCode(), "Rendering history process failed", e.toString()); } } }