1、安装bpmn-js
npm install bpmn-js
2、vue引入相关依赖
import { markRaw } from 'vue';
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
import BpmnModeler from 'bpmn-js/lib/Modeler';
3、页面
<div id="container"></div>
4、初始化
data() {
return {
containerEl: null,
bpmnModeler: null
};
},
mounted() {
// 初始化流程图
this.init();
},
methods: {
/**
* 初始化流程图
*/
init() {
this.containerEl = document.getElementById('container');
// 加markRaw去除双向绑定作用域
this.bpmnModeler = markRaw(new BpmnModeler({
container: this.containerEl
}));
this.bpmnModeler.createDiagram(() => {
this.bpmnModeler.get('canvas').zoom('fit-viewport');
});
}
}
本人使用vue3+element-plus上述代码是参考各处资料精简得出的,在初始化new BpmnModeler时,一开始没有markRaw出现问题,画布是空白,左侧菜单无法拖动元素到画布上,光标显示禁用图标
前端菜鸟一个,又经过多方查资料,具说vue2没有问题,可直接定义。但vue3也没说清楚要怎么改,最终在下面两个地方找到了2种解决方案
Is bpmn.js currently incompatible with ES6 - Developers - Forum - bpmn.io
vue.js - Specify type of data value in Vue (typescript) - Stack Overflow
(1)、定义bpmnModeler时不定义data,在方法种直接const定义
this.containerEl = document.getElementById('container');
// 加markRaw去除双向绑定作用域
const bpmnModeler = new BpmnModeler({
container: this.containerEl
});
bpmnModeler.createDiagram(() => {
bpmnModeler.get('canvas').zoom('fit-viewport');
});
(2)、引入markRaw方法,去除双向绑定
markRaw此处不做赘述,作者也不是很明白☺
效果图:
流程图初始化完成后,流程图只能画出基本流程,无法设置节点信息,需要引入属性面板
5、安装bpmn-js-properties-panel,camunda-bpmn-moddle
npm install bpmn-js-properties-panel
npm install camunda-bpmn-moddle
6、引入相关依赖
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
7、页面添加面板区域
<div id="js-properties-panel" class="panel"></div>
8、初始化流程图加入属性面板
this.bpmnModeler = markRaw(new BpmnModeler({
container: this.containerEl,
// 添加控制板
propertiesPanel: {
parent: '#js-properties-panel'
},
// 右侧属性面板
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
}));
9、完整代码
<template>
<div class="processDrawBody">
<el-button-group>
<el-button size="mini" @click="showProcessInfo">xml数据</el-button>
<el-button type="primary" size="mini" @click="handleUndo">撤销</el-button>
<el-button type="success" size="mini" @click="handleRedo">恢复</el-button>
<el-button type="warning" size="mini" @click="handleDownload">下载</el-button>
<el-upload
style="display: inline-block;"
:file-list="fileList"
class="upload-demo"
action=""
:auto-upload="false"
:show-file-list="false"
:http-request="httpRequest"
:on-change="handleOnchangeFile"
:on-remove="handleRemove"
:before-remove="beforeRemove"
>
<el-button type="danger" size="mini">导入</el-button>
</el-upload>
</el-button-group>
<div class="containerBox" style="position: relative;">
<div id="container">
</div>
<div id="js-properties-panel" class="panel"></div>
</div>
</div>
</template>
<script>
import { markRaw } from 'vue';
// bpmn-js相关
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
import BpmnModeler from 'bpmn-js/lib/Modeler';
// bpmn-js-properties-panel相关
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
// 其他
import { processDeployment, getProcessXml } from "@/api/index.js";
export default {
props: ['deploymentId'],
data() {
return {
containerEl: null,
bpmnModeler: null,
fileList: []
};
},
mounted() {
// 初始化流程图
this.init();
},
methods: {
/**
* 初始化流程图
*/
init() {
this.containerEl = document.getElementById('container');
// 加markRaw去除双向绑定作用域
this.bpmnModeler = markRaw(new BpmnModeler({
container: this.containerEl,
// 添加控制板
propertiesPanel: {
parent: '#js-properties-panel'
},
// 右侧属性面板
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
}));
this.bpmnModeler.createDiagram(() => {
this.bpmnModeler.get('canvas').zoom('fit-viewport');
});
let _this = this;
// 如果deploymentId存在,则为编辑,导入xml信息
if (_this.deploymentId) {
getProcessXml({"deploymentId":_this.deploymentId})
.then((res) => {
_this.bpmnModeler.importXML(res.data, (err) => {
this.$message.success('加载成功!');
});
})
.catch((error) => {
this.$message.error('获取流程信息失败');
});
}
},
handleRemove(file) {
for (let i = 0; i < this.fileList.length; i++) {
if (file.name === this.fileList[i].name) {
this.fileList.splice(i, 1);
}
}
},
beforeRemove(file) {
return this.$confirm(`确定移除 ${file.name}?`);
},
// 后退
handleUndo() {
this.bpmnModeler.get('commandStack').undo();
},
// 前进
handleRedo() {
this.bpmnModeler.get('commandStack').redo();
},
// 下载
handleDownload() {
this.bpmnModeler.saveXML({format: true}, (err, data) => {
const dataTrack = 'bpmn';
const a = document.createElement('a');
const name = `diagram.${dataTrack}`;
a.setAttribute(
'href',
`data:application/bpmn20-xml;charset=UTF-8,${encodeURIComponent(data)}`
);
a.setAttribute('target', '_blank');
a.setAttribute('dataTrack', `diagram:download-${dataTrack}`);
a.setAttribute('download', name);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
},
// 导入成功回调
handleOnchangeFile(file) {
const reader = new FileReader();
let data = '';
reader.readAsText(file.raw);
reader.onload = (event) => {
data = event.target.result;
this.bpmnModeler.importXML(data, (err) => {
debugger
if (err) {
this.$message.info('导入失败');
} else {
this.$message.success('导入成功');
}
});
};
},
// 取xml信息
showProcessInfo() {
this.bpmnModeler.saveXML({format: true}, (err, data) => {
alert(data);
});
},
/**
* 保存
*/
save() {
this.bpmnModeler.saveXML({format: true}, (err, data) => {
let processInfo = {};
processInfo.xml = data.replace(/camunda/ig,"activiti");
processInfo.processId = document.getElementById("camunda-id").value;
processInfo.processName = document.getElementById("camunda-name").innerHTML;
processDeployment(processInfo)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
});
});
}
}
}
</script>
<style>
.processDrawBody {
height: 100%;
text-align: left;
}
.containerBox {
height: 100%;
}
.containerBox #container {
height: 100%;
border: 1px solid rgb(121, 121, 121);
}
.bpp-properties-panel [type=text] {
box-sizing: border-box;
}
.panel {
width: 400px;
position: absolute;
top: 1px;
right: 1px;
height:100%;
overflow: auto;
}
/* 右下角logo */
.bjs-powered-by {
display: none;
}
</style>
注意事项:
1、后台使用activiti,流程配置时勾选Executable
2、适配activiti解析xml,xml文件中,"camunda.org/schema/1.0/bpmn"全部替换为"activiti.org/bpmn","camunda"全部替换成activiti"
this.bpmnModeler.saveXML({format: true}, (err, data) => {
let xml = data.replace(/camunda.org\/schema\/1.0\/bpmn/ig,"activiti.org/bpmn").replace(/camunda/ig,"activiti");
……
});
3、默认bpmn任务要修改为用户任务,才是日常activiti中使用的用户任务