项目中流程图在后台绘制,但需要在app及小程序中实现预览,后来因为小程序域名问题,所以放弃小程序,打包为h5了。
两种方式:
-
通过npm引入bmob,直接在vue页面使用。app及h5可以正常使用,小程序不兼容,因为小程序不允许操作dom。
-
新建html文件,在html中引入bmob.js,再通过webview把html文件插入到页面。h5能正常使用,app和小程序只能展示,不能放大拖动,可能需要加些额外配置,但我没成功。
一定要小程序的话,建议在小程序加个按钮,让用户跳转到浏览器打开流程图。
一.通过npm引入
1.npm引入,在package.json填入以下配置,然后npm install
"dependencies": {
"bpmn-js": "^9.4.0",
"crypto-js": "^3.1.9-1",
"minio": "^7.0.29",
"qs": "^6.9.7",
"vue-i18n": "^8.20.0"
},
2.新建components/bpmnChat22.vue文件

<template>
<view id="bpmnCanvas" :change:prop="bpmnCanvas.initPage" :prop="bpmnObj"
class="bpmnCanvas bpmnCanvasBox">
</view>
</template>
<script>
export default {
props: ['bpmnObj'],
data() {
return {
}
},
// 监听 bpmnObj 的变化, 数据变化会自动通过 :prop 传递给 renderjs
watch: {
bpmnObj: {
handler(newVal) {
console.log('bpmnObj 变化:', newVal);
},
immediate: true,
deep: true
}
}
}
</script>
<script module="bpmnCanvas" lang="renderjs">
import BpmnModeler from 'bpmn-js/lib/Modeler';
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
let bpmnViewer = ''
export default {
name: 'bpmn',
data() {
return {
executedLightNode: [],
highlightLine: ['flow2','flow3'],
bpmnTemplate: "",
canvas: '',
}
},
methods: {
async initPage(bpmnObj) {
console.log("xxxxxxxxx",bpmnObj)
if(!bpmnObj||!bpmnObj.bpmnXml){
return
}
// 流程图的xmljson
this.bpmnTemplate = bpmnObj.bpmnXml
//已完成的节点
this.executedLightNode = bpmnObj.activityIds
this.bpmnObj.activeLightNode = bpmnObj.activityIds
let that = this;
bpmnViewer && bpmnViewer.destroy();
bpmnViewer = new BpmnModeler({
container: document.getElementById('bpmnCanvas'),
// 禁用部分模块,与modules二选一
additionalModules: [
{
// 禁止拖动线
bendpoints: ["value", ""],
// 禁用单个图形拖动
move: ["value", ""],
// 禁用左侧面板
paletteProvider: ["value", ""],
// 禁止点击节点出现contextPad
contextPadProvider: ["value", ""],
// 禁止双击节点出现label编辑框
labelEditingProvider: ["value", ""]
}
],
// 启用所有模块
// modules: BpmnModeler.prototype._modules,
});
try {
const result = await bpmnViewer.importXML(this.bpmnTemplate);
const { warnings } = result;
// document.getElementById('bpmnCanvas').addMarker('BPMNEdge_flow9','highlight');
console.log("ddddddddddddddd",this.bpmnObj)
//this.importXmlSuccess();
setTimeout(()=> {
this.importXmlSuccess();
}, 100);
} catch (err) {
console.log(err.message, err.warnings);
}
},
importXmlSuccess() {
// 使流程图自适应屏幕
let canvas = bpmnViewer.get('canvas');
this.$ownerInstance.callMethod('initLoadin',false);
// canvas.zoom('fit-viewport', 'auto')
//设置高亮线和高亮节点,需要配合style中的css样式一起使用,否则没有颜色
this.setViewerStyle(canvas)
},
setViewerStyle(canvas) {
//已完成节点高亮
console.log(this.executedLightNode,"sssssssssssss")
let executedLightNode = this.executedLightNode;
if (executedLightNode && executedLightNode.length > 0) {
executedLightNode.forEach(item => {
canvas.addMarker(item, 'highlight')
})
document.querySelectorAll('.highlight').forEach((item, index) => {
if(item.querySelector('.djs-visual rect')){
item.querySelector('.djs-visual rect').setAttribute('stroke-dasharray', '4,4')
}
})
}
//顺序线高亮
// let highlightLines = this.highlightLine;
// if (highlightLines && highlightLines.length > 0) {
// highlightLines.forEach(item => {
// canvas.addMarker(item, 'highlight');
// })
// }
//正在执行节点高亮
let activeLightNode = this.bpmnObj.activeLightNode;
if (activeLightNode && activeLightNode.length > 0) {
activeLightNode.forEach((item, index) => {
canvas.addMarker(item, 'highlight')
})
document.querySelectorAll('.highlight').forEach((item, index) => {
if(item.querySelector('.djs-visual rect')){
item.querySelector('.djs-visual rect').setAttribute('stroke-dasharray', '4,4')
}
})
}
},
},
}
</script>
<style scoped>
.bpmnCanvas{
width: 100vw;
height: 100vh;
}
</style>
3.在页面引入这个组件
<bpmnChat22 v-if="subCurrent==2" :bpmnObj="bpmnObj"></bpmnChat22>
import bpmnChat22 from '@/components/bpmnFlowChart/bpmnChat22.vue'
components: { kTable,kForm,bpmnChat22 },

二.新建html渲染
- 新建components/bpmnChat22.vue文件,以及在static/bpmnChat.html文件。
static/bpmnChat.html在app中可以直接使用,但是小程序不支持,需要把bpmnChat.html单独部署,然后通过在线链接引入。

2.在components/bpmnChat22.vue文件中,bpmnTemplate 我放了测试的xmljson,所以有点大。而且不要直接传xmljson,因为体积很大,实际使用中会报错 ,最好在html中请求获取xmljson。
<template>
<view class="bpmn-container">
<web-view :src="bpmnViewerUrl"></web-view>
</view>
</template>
<script>
let bpmnTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:flowable=\"http://flowable.org/bpmn\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" typeLanguage=\"http://www.w3.org/2001/XMLSchema\" expressionLanguage=\"http://www.w3.org/1999/XPath\" targetNamespace=\"http://www.flowable.org/processdef\">\n <process id=\"Process_1772433229965\" name=\"流程_1772433229965\" isExecutable=\"true\">\n <startEvent id=\"StartEvent_1772433286788\" name=\"开始\" flowable:initiator=\"applyUserId\" flowable:formKey=\"2029072422393073665\">\n <extensionElements>\n <flowable:formProperty id=\"fBillNo\" name=\"单据编号\"></flowable:formProperty>\n <flowable:formProperty id=\"fBillType\" name=\"业务类型\"></flowable:formProperty>\n <flowable:formProperty id=\"fContactUnitDisplayName\" name=\"结算供应商\"></flowable:formProperty>\n <flowable:formProperty id=\"fDate\" name=\"单据日期\"></flowable:formProperty>\n <flowable:formProperty id=\"fDept\" name=\"部门\"></flowable:formProperty>\n <flowable:formProperty id=\"fSalerName\" name=\"业务员\"></flowable:formProperty>\n <flowable:formProperty id=\"fCurrencyName\" name=\"币别\"></flowable:formProperty>\n <flowable:formProperty id=\"fExchangeRate\" name=\"汇率\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmount\" name=\"申请额本位币\"></flowable:formProperty>\n <flowable:formProperty id=\"sysId\" name=\"sysId\"></flowable:formProperty>\n <flowable:formProperty id=\"tableType\" name=\"tableType\"></flowable:formProperty>\n <flowable:formProperty id=\"completedStatus\" name=\"completedStatus\"></flowable:formProperty>\n <flowable:formProperty id=\"fRemark\" name=\"请款说明\"></flowable:formProperty>\n <flowable:formProperty id=\"details\" name=\"动态表格\"></flowable:formProperty>\n <flowable:formProperty id=\"fAllAmountFor\" name=\"单据总金额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请金额\"></flowable:formProperty>\n </extensionElements>\n </startEvent>\n <userTask id=\"UserTask_1v8t6wm\" name=\"A\" flowable:formKey=\"2029072422393073665\" xmlns:flowable=\"http://flowable.org/bpmn\" flowable:formType=\"1\">\n <extensionElements>\n <flowable:formProperty id=\"fBillNo\" name=\"单据编号\"></flowable:formProperty>\n <flowable:formProperty id=\"fBillType\" name=\"业务类型\"></flowable:formProperty>\n <flowable:formProperty id=\"fContactUnitDisplayName\" name=\"结算供应商\"></flowable:formProperty>\n <flowable:formProperty id=\"fDate\" name=\"单据日期\"></flowable:formProperty>\n <flowable:formProperty id=\"fDept\" name=\"部门\"></flowable:formProperty>\n <flowable:formProperty id=\"fSalerName\" name=\"业务员\"></flowable:formProperty>\n <flowable:formProperty id=\"fCurrencyName\" name=\"币别\"></flowable:formProperty>\n <flowable:formProperty id=\"fExchangeRate\" name=\"汇率\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmount\" name=\"申请额本位币\"></flowable:formProperty>\n <flowable:formProperty id=\"sysId\" name=\"sysId\"></flowable:formProperty>\n <flowable:formProperty id=\"tableType\" name=\"tableType\"></flowable:formProperty>\n <flowable:formProperty id=\"completedStatus\" name=\"completedStatus\"></flowable:formProperty>\n <flowable:formProperty id=\"fRemark\" name=\"请款说明\"></flowable:formProperty>\n <flowable:formProperty id=\"details\" name=\"动态表格\"></flowable:formProperty>\n <flowable:formProperty id=\"fAllAmountFor\" name=\"单据总金额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请金额\"></flowable:formProperty>\n <flowable:Button code=\"同意\" name=\"_flow_agree\" isHide=\"0\" sort=\"2\"></flowable:Button>\n <flowable:Button code=\"驳回\" name=\"_flow_reject\" isHide=\"0\" sort=\"3\"></flowable:Button>\n <flowable:Button code=\"指定回退\" name=\"_flow_back\" isHide=\"0\" sort=\"4\"></flowable:Button>\n <flowable:Assignee type=\"role\" value=\"1\" condition=\"0\" operationType=\"0\" sort=\"0\"></flowable:Assignee>\n </extensionElements>\n </userTask>\n <sequenceFlow id=\"SequenceFlow_10krtxt\" sourceRef=\"StartEvent_1772433286788\" targetRef=\"UserTask_1v8t6wm\"></sequenceFlow>\n <userTask id=\"UserTask_0wqk1nm\" name=\"B\" flowable:formKey=\"2029072422393073665\" xmlns:flowable=\"http://flowable.org/bpmn\" flowable:formType=\"1\">\n <extensionElements>\n <flowable:formProperty id=\"fBillNo\" name=\"单据编号\"></flowable:formProperty>\n <flowable:formProperty id=\"fBillType\" name=\"业务类型\"></flowable:formProperty>\n <flowable:formProperty id=\"fContactUnitDisplayName\" name=\"结算供应商\"></flowable:formProperty>\n <flowable:formProperty id=\"fDate\" name=\"单据日期\"></flowable:formProperty>\n <flowable:formProperty id=\"fDept\" name=\"部门\"></flowable:formProperty>\n <flowable:formProperty id=\"fSalerName\" name=\"业务员\"></flowable:formProperty>\n <flowable:formProperty id=\"fCurrencyName\" name=\"币别\"></flowable:formProperty>\n <flowable:formProperty id=\"fExchangeRate\" name=\"汇率\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmount\" name=\"申请额本位币\"></flowable:formProperty>\n <flowable:formProperty id=\"sysId\" name=\"sysId\"></flowable:formProperty>\n <flowable:formProperty id=\"tableType\" name=\"tableType\"></flowable:formProperty>\n <flowable:formProperty id=\"completedStatus\" name=\"completedStatus\"></flowable:formProperty>\n <flowable:formProperty id=\"fRemark\" name=\"请款说明\"></flowable:formProperty>\n <flowable:formProperty id=\"details\" name=\"动态表格\"></flowable:formProperty>\n <flowable:formProperty id=\"fAllAmountFor\" name=\"单据总金额\"></flowable:formProperty>\n <flowable:formProperty id=\"fReqAmountFor\" name=\"本次申请金额\"></flowable:formProperty>\n <flowable:Button code=\"同意\" name=\"_flow_agree\" isHide=\"0\" sort=\"2\"></flowable:Button>\n <flowable:Button code=\"驳回\" name=\"_flow_reject\" isHide=\"0\" sort=\"3\"></flowable:Button>\n <flowable:Button code=\"指定回退\" name=\"_flow_back\" isHide=\"0\" sort=\"4\"></flowable:Button>\n <flowable:Assignee type=\"role\" value=\"1\" condition=\"0\" operationType=\"0\" sort=\"0\"></flowable:Assignee>\n </extensionElements>\n </userTask>\n <sequenceFlow id=\"SequenceFlow_14rxdan\" sourceRef=\"UserTask_1v8t6wm\" targetRef=\"UserTask_0wqk1nm\"></sequenceFlow>\n <endEvent id=\"EndEvent_1relb3d\">\n <extensionElements>\n <flowable:executionListener event=\"end\" class=\"com.mexsd.smartcloud.listener.BizStatusUpdateListener\"></flowable:executionListener>\n </extensionElements>\n </endEvent>\n <sequenceFlow id=\"SequenceFlow_11in6jh\" sourceRef=\"UserTask_0wqk1nm\" targetRef=\"EndEvent_1relb3d\"></sequenceFlow>\n </process>\n <bpmndi:BPMNDiagram id=\"BPMNDiagram_Process_1772433229965\">\n <bpmndi:BPMNPlane bpmnElement=\"Process_1772433229965\" id=\"BPMNPlane_Process_1772433229965\">\n <bpmndi:BPMNShape bpmnElement=\"StartEvent_1772433286788\" id=\"BPMNShape_StartEvent_1772433286788\">\n <omgdc:Bounds height=\"36.0\" width=\"36.0\" x=\"209.0\" y=\"283.0\"></omgdc:Bounds>\n </bpmndi:BPMNShape>\n <bpmndi:BPMNShape bpmnElement=\"UserTask_1v8t6wm\" id=\"BPMNShape_UserTask_1v8t6wm\">\n <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"300.0\" y=\"261.0\"></omgdc:Bounds>\n </bpmndi:BPMNShape>\n <bpmndi:BPMNShape bpmnElement=\"UserTask_0wqk1nm\" id=\"BPMNShape_UserTask_0wqk1nm\">\n <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"460.0\" y=\"261.0\"></omgdc:Bounds>\n </bpmndi:BPMNShape>\n <bpmndi:BPMNShape bpmnElement=\"EndEvent_1relb3d\" id=\"BPMNShape_EndEvent_1relb3d\">\n <omgdc:Bounds height=\"36.0\" width=\"36.0\" x=\"622.0\" y=\"283.0\"></omgdc:Bounds>\n </bpmndi:BPMNShape>\n <bpmndi:BPMNEdge bpmnElement=\"SequenceFlow_10krtxt\" id=\"BPMNEdge_SequenceFlow_10krtxt\">\n <omgdi:waypoint x=\"244.0\" y=\"301.0\"></omgdi:waypoint>\n <omgdi:waypoint x=\"299.0\" y=\"301.0\"></omgdi:waypoint>\n </bpmndi:BPMNEdge>\n <bpmndi:BPMNEdge bpmnElement=\"SequenceFlow_14rxdan\" id=\"BPMNEdge_SequenceFlow_14rxdan\">\n <omgdi:waypoint x=\"399.0\" y=\"301.0\"></omgdi:waypoint>\n <omgdi:waypoint x=\"459.0\" y=\"301.0\"></omgdi:waypoint>\n </bpmndi:BPMNEdge>\n <bpmndi:BPMNEdge bpmnElement=\"SequenceFlow_11in6jh\" id=\"BPMNEdge_SequenceFlow_11in6jh\">\n <omgdi:waypoint x=\"559.0\" y=\"301.0\"></omgdi:waypoint>\n <omgdi:waypoint x=\"622.0\" y=\"301.0\"></omgdi:waypoint>\n </bpmndi:BPMNEdge>\n </bpmndi:BPMNPlane>\n </bpmndi:BPMNDiagram>\n</definitions>"
export default {
data() {
return {
bpmnViewerUrl: '/static/bpmnChat.html?xml=' + encodeURIComponent(bpmnTemplate),
//"http://192.168.3.16:8083?xml=" + encodeURIComponent(bpmnTemplate),
}
},
methods: {
}
}
</script>
<style scoped>
</style>
3.在bpmnChat.html文件中。我直接通过链接方式引入的,实际上把这些js和css下载到本地引入更好。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>BPMN 预览</title>
<link rel="stylesheet" href="https://unpkg.com/bpmn-js/dist/assets/diagram-js.css">
<link rel="stylesheet" href="https://unpkg.com/bpmn-js/dist/assets/bpmn-font/css/bpmn.css">
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #ffffff;
}
#canvas {
width: 100%;
height: 100%;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.7);
color: white;
padding: 12px 24px;
border-radius: 24px;
font-size: 14px;
z-index: 1000;
}
.error {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
background: #ff4444;
color: white;
padding: 12px 20px;
border-radius: 8px;
font-size: 14px;
display: none;
z-index: 1001;
}
</style>
</head>
<body>
<div id="canvas"></div>
<div class="loading" id="loading">加载中...</div>
<div class="error" id="error"></div>
<!-- 使用固定的版本号,确保加载成功 -->
<script src="https://unpkg.com/bpmn-js/dist/bpmn-modeler.development.js"></script>
<script>
// 等待DOM和脚本加载完成
window.onload = function() {
const params = new URLSearchParams(window.location.search);
const xmlParam = params.get('xml');
// if (!xmlParam) {
// showError('请提供BPMN XML参数');
// return;
// }
// 解码XML
let xml = xmlParam
try {
xml = decodeURIComponent(xmlParam);
} catch (e) {
showError('XML解码失败');
return;
}
// 检查BpmnJS是否可用
if (typeof BpmnJS === 'undefined') {
showError('BPMN库加载失败,请刷新重试');
return;
}
console.log('BpmnJS可用,开始初始化...');
// 初始化查看器
const viewer = new BpmnJS({
container: '#canvas',
//去掉部分操作模块,与modules二选一
additionalModules: [
{
// 禁止拖动线
bendpoints: ["value", ""],
// 禁用单个图形拖动
move: ["value", ""],
// 禁用左侧面板
paletteProvider: ["value", ""],
// 禁止点击节点出现contextPad
contextPadProvider: ["value", ""],
// 禁止双击节点出现label编辑框
labelEditingProvider: ["value", ""]
}
]
// 启用所有模块
// modules: BpmnJS.prototype._modules,
});
// 导入XML
viewer.importXML(xml).then(result => {
console.log('导入成功', result);
// 获取canvas并自适应
const canvas = viewer.get('canvas');
canvas.zoom('fit-viewport');
// 获取eventBus验证交互
const eventBus = viewer.get('eventBus');
// 监听视图变化,确认拖动有效
eventBus.on('canvas.viewbox.changed', (event) => {
console.log('视图变化 - 缩放:', event.viewbox.scale);
});
const move = viewer.get('move', false);
if (move) {
console.log('移动模块已启用');
}
// 隐藏加载提示
document.getElementById('loading').style.display = 'none';
}).catch(err => {
console.error('导入失败', err);
showError('BPMN解析失败: ' + (err.message || '未知错误'));
});
function showError(msg) {
const errorEl = document.getElementById('error');
errorEl.textContent = msg;
errorEl.style.display = 'block';
document.getElementById('loading').style.display = 'none';
}
};
</script>
</body>
</html>
4.在页面中引入
<bpmnChat22 v-if="subCurrent==2" :bpmnObj="{}"></bpmnChat22>
import bpmnChat22 from './components/bpmnFlowChart/bpmnChat22.vue'
components: { bpmnChat22 },
