之前使用的是本地写死的
xml
字符串来渲染流程图,实际开发中肯定不满足我们的需求,那么我们应该如何解决这个问题呢?
常用的做法是:前端发送 axios
请求,获取到 xml
的字符串,然后使用 bpmn.js
中的 importXML
的方法将 xml
字符串转换为图形在页面上渲染出来。
接下来进入正题啦~
bpmn.js在vue中发送http请求
通过http请求获取并渲染数据
还是在之前创建好的项目 vue-bpmn
的基础上添加代码
先在项目中安装 axios
用于发送 http
请求
npm i axios --save-D
然后在 views
文件夹下新建 axios.vue
的文件,并配置好路由规则
// axios.vue
<template><div class="container"><template v-if="loading"><div class="loading">Loading</div></template><template v-else><div class="canvas" ref="canvas"></div><div id="js-properties-panel" class="panel"></div></template></div>
</template>
css
部分的样式
<style scoped> .container {
position: relative;width: 100%;height: 100%;
}
.canvas {
width: 100%;height: 100%;
}
.panel {
position: absolute;top: 0;right: 0;width: 300px;
}
</style>
然后在 js
部分引入 axios
并模拟向后端发送请求获取并渲染数据
<script>
import axios from 'axios'
import BpmnModeler from 'bpmn-js/lib/Modeler'
// 引入一个本地的xml字符串,若是没有获取到后台的数据则用它
import {
xmlStr } from '../mock/xmlStr'// 使用右侧属性栏
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'
export default {
data () {
return {
bpmnModeler: null, // bpmn 建模器container: null,canvas: null,loading: true,xmlUrl: '',defaultXmlStr: xmlStr}},mounted() {
this.init()},methods: {
async init () {
this.loading = truethis.xmlUrl = await this.getXmlUrl()console.log(this.xmlUrl)this.loading = false// 等待 DOM 更新之后再对工作流进行初始化this.$nextTick(() => {
this.initBpmn()})},// 该方法模拟请求后台获取 bpmn 文件getXmlUrl () {
return new Promise(resolve => {
setTimeout(() => {
const url = 'https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmnMock.bpmn'resolve(url)}, 1000)})},initBpmn () {
// 获取canvas的dom节点const canvas = this.$refs.canvas// 建模this.bpmnModeler = new BpmnModeler({
container: canvas,// 添加控制板propertiesPanel: {
parent: '#js-properties-panel'},additionalModules: [// 右边的属性栏propertiesProviderModule,propertiesPanelModule],moddleExtensions: {
camunda: camundaModdleDescriptor}})this.createNewDiagram()},async createNewDiagram () {
const that = thislet bpmnXmlStr = ''if (this.xmlUrl === '') {
// 若是后台没有数据则使用默认的一个 xmlbpmnXmlStr = this.defaultXmlStrthis.transformCanvas(bpmnXmlStr)} else {
let res = await axios({
method: 'get',timeout: 120000,url: that.xmlUrl,headers: {
'Content-Type': 'multipart/form-data' }})console.log(res)bpmnXmlStr = res['data']this.transformCanvas(bpmnXmlStr)}},transformCanvas (bpmnXmlStr) {
// 将字符串转换成图显示出来try {
const result = this.bpmnModeler.importXML(bpmnXmlStr)const {
warnings } = resultconsole.log(warnings)this.success()// 让图能自适应屏幕var canvas = this.bpmnModeler.get('canvas')canvas.zoom('fit-viewport')} catch (err) {
console.log(err.message, err.warnings)}},success () {
console.log('创建成功')}}
}
</script>
效果演示
请求接口来源 多谢
编辑之后将最新的bpmn发送给后台
仅仅涉及到数据渲染是远远不够的,如果我们修改了数据,该怎么把数据发送给后台并存储呢?
这个问题就涉及到 bpmn.js
中的事件绑定,需要给图形绑定一个事件 来检测到图形的改变,并获取到最新的 xml
信息发送给后台
在 views
文件夹下新建一个 save.vue
文件,并将 axios.vue
中的内容复制到 save.vue
中,同时记得配置路由哦
在 success()
方法中新增一个 addBpmnListener()
的方法
// save.vue
<script>success () {
console.log('创建成功')this.addBpmnListener()},// 添加绑定事件addBpmnListener () {
// 给图绑定事件,当图有发生改变的时候就会触发这个事件this.bpmnModeler.on('commandStack.changed', () => {
this.saveDiagram((err, xml) => {
console.log(xml) // 这里获取到的就是最新的 xml 信息})})},// 下载为 bpmn 格式,done 是个函数,调用的时候传入的saveDiagram (done) {
// 把传入的 done 再传给 bpmn 原型的 saveXML 函数调用this.bpmnModeler.saveXML({
format: true }, (err, xml) => {
done(err, xml)})}
</script>
编辑图后,就能获得最新的 xml
内容
编辑完后保存为bpmn文件或svg文件
通过监听 commandStack.changed
事件我们就能获取到修改完成之后最新的 xml
信息了
我们可以了最新的 xml
信息传递给后台,也可以直接下载为 bpmn/svg
文件
在 views
文件夹下新建 download.vue
并配置好路由规则,把 save.vue
的内容复制到 download.vue
中
先给添加两个按钮,这两个按钮先隐藏(因为此时 href
中没有连接),待图更新完后显示出来供用户下载
<template v-else><a href="javascript:;" ref="saveBpmn" class="hidden">保存为bpmn</a><a href="javascript:;" ref="saveSvg" class="hidden">保存为svg</a><div class="canvas" ref="canvas"></div><div id="js-properties-panel" class="panel"></div></template>
然后修改 js
部分的代码
<script>
methods: {
// 添加绑定事件addBpmnListener () {
const downloadLink = this.$refs.saveBpmnconst downloadSvgLink = this.$refs.saveSvg// 给图绑定事件,当图有发生改变的时候就会触发这个事件this.bpmnModeler.on('commandStack.changed', () => {
downloadLink.display = 'block'downloadSvgLink.display = 'block'this.saveBpmn((err, xml) => {
this.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml) // 这里获取到的 xml 就是最新的 xml 信息})this.saveSvg((err, svg) => {
this.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg)})})},// 下载为 Svg 格式,done 是个函数,调用的时候传入的saveSvg (done) {
// 把传入的 done 再传给 bpmn 原型的 saveSVG 函数调用this.bpmnModeler.saveSVG(done)},// 下载为 bpmn 格式,done 是个函数,调用的时候传入的saveBpmn (done) {
// 把传入的 done 再传给 bpmn 原型的 saveXML 函数调用this.bpmnModeler.saveXML({
format: true }, (err, xml) => {
done(err, xml)})},// 当图发生改变的时候会调用这个函数,这个 data 就是图的 xmlsetEncoded (link, name, data) {
// 把 xml 转换为 URI,下载要用到的const encodeData = encodeURIComponent(data)// 下载图的具体操作,改变 a 的属性,className 另 a 标签可点击,href 可以下载,download 是下载的文件的名字console.log(link, name, data)let xmlFile = new File([data], 'test.bpmn')console.log(xmlFile)if (data) {
link.className = 'active'// 将数据给到连接link.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodeData// 设置文件名link.download = name}}
}
</script>
效果演示