这是一个日志贴
原始插件
https://www.cuba-platform.cn/marketplace/business-process-management/
有待增强部分
- 设计器没有汉化(已实现,参考)
- 流程运行是在后台的,不能在表单中直观的看到流程状态(当前处理)
这是一个日志贴
https://www.cuba-platform.cn/marketplace/business-process-management/
目前已经将流程图嵌入系统,当前需要做的是找到当前表单的流程描述文件和已处理节点数据并高亮流程图。之前的步骤会补齐。
流程编辑器保存的时候是json串,引擎认识的却是符合bpmn2.0规范的xml,所以在首次的部署的时候要将json串转换为BpmnModel,再将BpmnModel转换成xml保存进数据库,以后每次使用就直接将xml转换成BpmnModel。
js代码
com_enruipu_rfid_web_screens_BpmnViewer = function () {
const connector = this;
const element = connector.getElement();
element.innerHTML = "<div style='height: 900px' id=\"diagram\"></div>";
const viewer = new BpmnJS({container: '#diagram'});
// 流程描述文件,后面会通过Controller加载
$.get('/app/VAADIN/themes/helium/layouts/resources/pizza-collaboration.bpmn', showDiagram, 'text');
connector.highlight = function () {
$.get('/app/VAADIN/themes/helium/layouts/resources/pizza-collaboration.bpmn', showDiagramHighlight, 'text');
}
/**
* 普通加载
*
* @param diagramXML
* @returns {Promise<void>}
*/
async function showDiagram(diagramXML) {
viewer.importXML(diagramXML);
}
/**
* 高亮加载
*
* @param diagramXML
* @returns {Promise<void>}
*/
async function showDiagramHighlight(diagramXML) {
await viewer.importXML(diagramXML);
const canvas = viewer.get('canvas');
// id、css样式
canvas.addMarker('sid-9B186814-71C7-4E03-81C3-449836752A3E', 'primary');
canvas.addMarker('sid-895E66D2-EA41-4A8E-90CE-3A60C3BC96E6', 'success');
canvas.addMarker('sid-66D34D68-C943-417F-986A-124F15BDC913', 'danger');
canvas.addMarker('sid-7E119504-A334-4964-A803-A6771E7ADA19', 'primary');
canvas.addMarker('sid-94A54FD5-2A05-4250-B17E-A0D25C8EE53E', 'danger');
}
};
Controller
import com.haulmont.cuba.gui.components.Button;
import com.haulmont.cuba.gui.screen.Screen;
import com.haulmont.cuba.gui.screen.Subscribe;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
import com.haulmont.cuba.web.gui.components.JavaScriptComponent;
import javax.inject.Inject;
@UiController(“demo_Sandbox”)
@UiDescriptor(“test-browse.xml”)
public class Sandbox extends Screen {
@Inject
private JavaScriptComponent bpmnComponent;
@Subscribe("highlight")
public void onHighlightClick(Button.ClickEvent event) {
bpmnComponent.callFunction("highlight");
}
@Subscribe
protected void onInit(InitEvent event) {
}
}
css
.primary:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(64, 158, 255, 0.3) !important;
}
.success:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(103, 194, 58, 0.3) !important;
}
.danger:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(245, 108, 108, 0.3) !important;
}
用 canvas 不能实现连接线的高亮!
数据还没处理,先预览一下。
是不是顿时感觉系统又更高大上了些~
1. screens
<!--流程-->
<groupBox id="procActionsBox"
caption="mainMsg://menu-config.bpm"
spacing="true"
width="1400px">
<tabSheet id="procTabSheet" height="100%">
<tab id="procActions" caption="审批" margin="true" spacing="true">
<fragment id="procActionsFragment"
screen="bpm_ProcActionsFragment" width="AUTO"/>
</tab>
<tab id="procView" caption="流程图" margin="true" spacing="true">
<fragment id="procViewActionFragment"
screen="bpm_ProcViewActionFragment" width="100%"/>
</tab>
</tabSheet>
</groupBox>
2. controller
@Inject
protected ProcViewActionFragment procViewActionFragment;
@Subscribe
protected void onInit(InitEvent event) {
procTabSheet.addSelectedTabChangeListener(selectedTabChangeEvent -> {
if ("procView".equals(selectedTabChangeEvent.getSelectedTab().getName())) {
procViewActionFragment.highlight();
}
});
}
还有需要优化的地方,后续慢慢处理了。
包路径:com.haulmont.bpm.gui.procactionsfragment
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
messagesPack="com.haulmont.bpm.gui.procactionsfragment">
<data readOnly="true">
<collection id="procTasksDs"
class="com.haulmont.bpm.entity.ProcTask"
view="procTask-frame">
<loader id="procTasksDl">
<query>
<![CDATA[select e from bpm$ProcTask e
where e.procInstance.id = :custom$procInstance
order by e.createTs desc]]>
</query>
</loader>
</collection>
</data>
<layout spacing="true" expand="bpmnComponent">
<jsComponent id="bpmnComponent" width="100%"
initFunctionName="com_enruipu_rfid_web_screens_BpmnViewer">
<dependencies>
<dependency path="vaadin://bpmn/css/bpmn.css" type="STYLESHEET"/>
<dependency path="vaadin://bpmn/js/jquery.js" type="JAVASCRIPT"/>
<dependency path="vaadin://bpmn/js/bpmn-navigated-viewer.js" type="JAVASCRIPT"/>
<dependency path="vaadin://bpmn/js/bpmn-connector.js" type="JAVASCRIPT"/>
</dependencies>
</jsComponent>
</layout>
</window>
package com.haulmont.bpm.gui.procactionsfragment;
import com.haulmont.bpm.BpmConstants;
import com.haulmont.bpm.entity.ProcDefinition;
import com.haulmont.bpm.entity.ProcInstance;
import com.haulmont.bpm.entity.ProcTask;
import com.haulmont.bpm.service.BpmEntitiesService;
import com.haulmont.bpm.service.ProcessRepositoryService;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.screen.ScreenFragment;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
import com.haulmont.cuba.web.gui.components.JavaScriptComponent;
import org.slf4j.Logger;
import javax.inject.Inject;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* @author Rubin
* @version v1 2021/4/6 15:36
*/
@UiController("bpm_ProcViewActionFragment")
@UiDescriptor("proc-view-action-fragment.xml")
public class ProcViewActionFragment extends ScreenFragment {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(ProcViewActionFragment.class);
protected ProcInstance procInstance;
@Inject
protected BpmEntitiesService bpmEntitiesService;
@Inject
protected ProcessRepositoryService processRepositoryService;
@Inject
private JavaScriptComponent bpmnComponent;
/**
* 获取 xml
* 获取已经审批的节点
* 获取最后一个节点的状态(审批中、拒绝)
*/
@Inject
protected CollectionLoader<ProcTask> procTasksDl;
public void highlight(String procCode, Entity<?> entity) {
ProcDefinition procDefinition = bpmEntitiesService.findProcDefinitionByCode(procCode, BpmConstants.Views.PROC_DEFINITION_WITH_ROLES);
if (procDefinition == null) {
log.debug("Process definition with code '{}' not found", procCode);
return;
}
List<ProcInstance> procInstances = bpmEntitiesService.findActiveProcInstancesForEntity(procDefinition.getCode(), entity, BpmConstants.Views.PROC_INSTANCE_FULL);
procInstance = procInstances.isEmpty() ? null : procInstances.get(0);
if (procInstance != null) {
String actId = procDefinition.getActId();
// 获取XML
String processXml = processRepositoryService.getProcessDefinitionXml(actId);
// 获取已经审批的节点
procTasksDl.setParameter("custom$procInstance", procInstance.getId());
procTasksDl.load();
List<ProcTask> items = procTasksDl.getContainer().getMutableItems();
Collections.reverse(items);
StringBuilder actTaskId = new StringBuilder();
for (ProcTask task : items) {
actTaskId.append(task.getActTaskDefinitionKey()).append(";");
}
// 最后一个节点判断
// todo 拒绝时的判断
ProcTask procTask = items.get(items.size() - 1);
Date endDate = procTask.getEndDate();
String marker = "primary";
if (endDate != null) {
marker = "danger";
}
String last = procTask.getActTaskDefinitionKey() + ";" + marker;
bpmnComponent.callFunction("highlight", processXml, actTaskId.toString(), last);
}
}
}
.primary:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(64, 158, 255, 0.3) !important;
}
.success:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(103, 194, 58, 0.3) !important;
}
.danger:not(.djs-connection) .djs-visual > :nth-child(1) {
fill: rgba(245, 108, 108, 0.3) !important;
}
https://unpkg.com/bpmn-js@8.2.2/dist/bpmn-navigated-viewer.development.js
com_enruipu_rfid_web_screens_BpmnViewer = function () {
const connector = this;
const element = connector.getElement();
element.innerHTML = "<div style='height: 500px' id=\"diagram\"></div>";
connector.highlight = async function (diagramXML, items, last) {
items = items.substring(0, items.length - 1)
const taskIds = items.split(";")
const lastStatus = last.split(";")
const viewer = new BpmnJS({container: '#diagram'});
await viewer.importXML(diagramXML);
const canvas = viewer.get('canvas');
for (let i = 0; i < taskIds.length - 1; i++) {
canvas.addMarker(taskIds[i], 'success');
}
// 最后一个节点状态
canvas.addMarker(lastStatus[0], lastStatus[1]);
// id、css样式
// canvas.addMarker('sid-9B186814-71C7-4E03-81C3-449836752A3E', 'primary');
// canvas.addMarker('sid-895E66D2-EA41-4A8E-90CE-3A60C3BC96E6', 'success');
// canvas.addMarker('sid-66D34D68-C943-417F-986A-124F15BDC913', 'danger');
// canvas.addMarker('sid-7E119504-A334-4964-A803-A6771E7ADA19', 'primary');
// canvas.addMarker('sid-94A54FD5-2A05-4250-B17E-A0D25C8EE53E', 'danger');
}
};
参考
本次优化还未处理的问题:
@Subscribe
protected void onInit(InitEvent event) {
procTabSheet.addSelectedTabChangeListener(selectedTabChangeEvent -> {
if ("procView".equals(selectedTabChangeEvent.getSelectedTab().getName())) {
procViewActionFragment.highlight(PROCESS_CODE, getEditedEntity());
}
});
}
厉害,厉害
有时间了做个Jmix的免费版
厉害,不得不点赞