vue中使用bpmn.js 绘制流程图
项目中需要前端绘制流程图保存为xml通过接口调用传给后台
npm install bpmn-js --save
npm install bpmn-js-properties-panel --save
npm install bpmn-moddle --save
npm install camunda-bpmn-moddle --save
上面四个插件安装好
1.在使用页面引入 插件
import BpmnViewer from 'bpmn-js'
import BpmnModeler from "bpmn-js/lib/Modeler"; // bpmn-js 设计器
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 customTranslate from './customTranslate'
/* 右边工具栏样式*/
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
import BpmData from "./BpmData";
其他相关文件
BpmnData.js文件
/**
* 存储流程设计相关参数
*/
export default class BpmData {
constructor () {
this.controls = [] // 设计器控件
this.init()
}
init () {
this.controls = [
{
action: 'create.start-event',
title: '开始'
},
{
action: 'create.intermediate-event',
title: '中间'
},
{
action: 'create.end-event',
title: '结束'
},
{
action: 'create.exclusive-gateway',
title: '网关'
},
{
action: 'create.task',
title: '任务'
},
{
action: 'create.user-task',
title: '用户任务'
},
{
action: 'create.user-sign-task',
title: '会签任务'
},
{
action: 'create.subprocess-expanded',
title: '子流程'
},
{
action: 'create.data-object',
title: '数据对象'
},
{
action: 'create.data-store',
title: '数据存储'
},{
action: 'create.participant-expanded',
title: '扩展流程'
},
{
action: 'create.group',
title: '分组'
}
]
}
// 获取控件配置信息
getControl (action) {
const result = this.controls.filter(item => item.action === action)
return result[0] || {}
}
}
customTranslate.js
import translations from './translationsGerman'
export default function customTranslate(template, replacements) {
replacements = replacements || {}
// Translate
template = translations[template] || template
// Replace
return template.replace(/{([^}]+)}/g, function(_, key) {
var str = replacements[key]
if (translations[replacements[key]] != null && translations[replacements[key]] !== 'undefined') {
str = translations[replacements[key]]
}
return str || '{' + key + '}'
})
}
2.html代码
2.js初始化
mounted() {
const canvas = this.$refs.canvas;
// 生成实例
this.bpmnModeler = new BpmnModeler({
container: canvas,
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
// 左边工具栏以及节点
propertiesProviderModule,
// 右边的工具栏
propertiesPanelModule,
{
translate: ['value', customTranslate]
}
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
});
// 获取a标签dom节点
const downloadLink = this.$refs.saveDiagram1;
const downloadSvgLink = this.$refs.saveSvg;
// 监听流程图改变事件
const _this = this;
this.bpmnModeler.on("commandStack.changed", function() {
_this.saveSVG(function(err, svg) {
_this.setEncoded(downloadSvgLink, "diagram.svg", err ? null : svg);
});
_this.saveDiagram1(function(err, xml) {
_this.setEncoded(downloadLink, "diagram.bpmn", err ? null : xml);
});
});
// 新增流程定义
this.createNewDiagram();
}
3.定义函数
methods: {
createNewDiagram() {
const bpmnXmlStr = `
Flow_0kaxh13
Flow_0t6sg2a
Flow_0kaxh13
Flow_0t6sg2a
`;
// 将字符串转换成图显示出来
this.bpmnModeler.importXML(bpmnXmlStr, err => {
if (err) {
console.error(err);
} else {
this.adjustPalette();
}
});
},
// 调整左侧工具栏排版
adjustPalette() {
try {
// 获取 bpmn 设计器实例
const canvas = this.$refs.canvas;
const djsPalette = canvas.children[0].children[1].children[4];
const djsPalStyle = {
width: "130px",
padding: "5px",
background: "white",
left: "20px",
borderRadius: 0
};
for (var key in djsPalStyle) {
djsPalette.style[key] = djsPalStyle[key];
}
const palette = djsPalette.children[0];
const allGroups = palette.children;
allGroups[0].style["display"] = "none";
// 修改控件样式
for (var gKey in allGroups) {
const group = allGroups[gKey];
for (var cKey in group.children) {
const control = group.children[cKey];
const controlStyle = {
display: "flex",
justifyContent: "flex-start",
alignItems: "center",
width: "100%",
padding: "5px"
};
if (
control.className &&
control.dataset &&
control.className.indexOf("entry") !== -1
) {
const controlProps = this.bpmData.getControl(
control.dataset.action
);
control.innerHTML = `${
controlProps["title"]
}`;
for (var csKey in controlStyle) {
control.style[csKey] = controlStyle[csKey];
}
}
}
}
} catch (e) {
console.log(e);
}
},
// 下载为SVG格式,done是个函数,调用的时候传入的
saveSVG(done) {
// 把传入的done再传给bpmn原型的saveSVG函数调用
this.bpmnModeler.saveSVG(done);
},
// 下载为SVG格式,done是个函数,调用的时候传入的
saveDiagram(done) {
// 把传入的done再传给bpmn原型的saveXML函数调用
let that=this
this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
that.submitData(xml)
// done(err, xml);
});
},
saveDiagram1(done){
this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
done(err, xml);
});
},
// 当图发生改变的时候会调用这个函数,这个data就是图的xml
setEncoded(link, name, data) {
// 把xml转换为URI,下载要用到的
const encodedData = encodeURIComponent(data);
// 获取到图的xml,保存就是把这个xml提交给后台
this.xmlStr = data;
// 下载图的具体操作,改变a的属性,className令a标签可点击,href令能下载,download是下载的文件的名字
if (data) {
link.className = "active";
link.href = "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
link.download = name;
}
},
}