使用Bpmn.js在vue里制作查看流程图组件
程序员文章站
2022-07-04 20:26:46
...
说明
啊 好久不见,最近出差了很久,那久没写博客,来冒泡(填坑)啦~最近需要使用Bpmn.js制作流程的前端,技术上选的是vue,前几篇里我们一直讲的都是后端通用流程的实现,现在来讲一下前端吧(其实我是搞后端的ヽ(ー_ー)ノ有不对的地方欢迎指点)。
快速开始
默认项目已经引入bpmn-js等相关组件,我这里弹窗和按钮用的都是antdesign组件,你可以任意替换你喜欢的弹窗和按钮组件,直接上代码
两次Axios请求数据张这样第一个json里的node指的是你流程里节点的Key值,第二个json里的result指的是你流程图的xml,分别是用来变色节点和绘制图的,很好理解吧。都用这么久流程了这两个接口应该能写出来了,如果需要的人多的话我再写一篇后端教怎么拿好了( ̄ェ ̄;):
{
"success": true,
"message": "操作成功!",
"code": 0,
"token": null,
"result": {
"node": ["Task_00475vw"]
},
"timestamp": 1585620877025
}
{
"success": true,
"message": "操作成功!",
"code": 0,
"token": null,
"result": "这里是你的流程xml数据",
"timestamp": 1585620877326
}
制作组件Bpmn.vue代码如下,比较重要的代码是eventBus.off(events, null),因为是查看,不需要绘制的各种操作,这里去掉监听,更多Event.js的方法戳->Event-js,同样的,如果需要监听每个节点例如弹出弹窗,可以在我注释掉的eventBus.on里写代码
<template>
<a-modal
title="流程查看"
width="100%"
:visible="dialogVisible"
@cancel="dialogVisible=false"
cancelText="关闭"
>
<div class="containers" ref="content">
<div id="canvas" class="canvas" ref="canvas"></div>
</div>
<template slot="footer">
<div>
<a-button @click="dialogVisible=false">取消</a-button>
</div>
</template>
</a-modal>
</template>
<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
import { axios } from '@/utils/request'
export default {
data() {
return {
proId: '',
proInstanceId: '',
bpmnModeler: null,
height: '',
container: null,
canvas: null,
// 弹窗
dialogVisible: false
}
},
methods: {
parentHandleclick(proId, proInstanceId, height) {
this.proId = proId
this.proInstanceId = proInstanceId
this.height = height
this.createNewDiagram()
},
createNewDiagram() {
this.dialogVisible = true
this.$nextTick(() => {
// 设置父节点高
this.$refs.content.parentNode.style.height = this.height
this.$refs.content.style.height = this.height
const that = this
let nodeCodes = []
if (this.proInstanceId != '') {
axios({
url: '/process/getPassingNodeAndLineByProInstanceId/' + this.proInstanceId,
method: 'get'
}).then(res2 => {
nodeCodes = res2.result.node
})
}
axios({
url: '/process/getXmlByProId/' + this.proId,
method: 'get'
}).then(res => {
// console.log('proId:' + this.proId + ' proInstanceId:' + this.proInstanceId)
// console.log('节点数据:' + JSON.stringify(nodeCodes))
this.container = this.$refs.content
var canvas = document.getElementById('canvas')
// 先移除之前的图
canvas.innerHTML = ''
// var canvas = this.$refs.canvas
this.bpmnModeler = new BpmnModeler({
container: canvas
})
const bpmnXmlStr = res.result
// console.log(bpmnXmlStr)
this.bpmnModeler.importXML(bpmnXmlStr, function(err) {
if (err) {
console.error(err)
}
that.success()
const canvas = that.bpmnModeler.get('canvas')
canvas.zoom('fit-viewport')
const colorClass = 'nodeSuccess'
that.setNodeColor(nodeCodes, colorClass, canvas)
})
})
})
},
// 给已经走过的流程添加颜色
setNodeColor(nodeCodes, colorClass, canvas) {
for (let i = 0; i < nodeCodes.length; i++) {
canvas.addMarker(nodeCodes[i], colorClass)
}
},
success() {
// const bpmnjs = this.bpmnModeler
// const eventBus = bpmnjs.get('eventBus')
// const elementFactory = bpmnjs.get('elementFactory')
// const commandStack = require('diagram-js/lib/command/index')
// const bpmnRules = require('bpmn-js/lib/features/rules/index')
// const ml = new Modeling(eventBus, elementFactory, commandStack, bpmnRules)
// this.setLineColor('Task_0307aue','RED', this, modeling);
this.addBpmnListener(this, 'ml')
},
// 给节点添加监听时间(点击)
addBpmnListener(_self, modeling) {
const bpmnjs = this.bpmnModeler
const eventBus = bpmnjs.get('eventBus')
const events = ['element.click', 'element.dblclick','element.mousedown', 'element.mousemove']
eventBus.off(events, null)
// events.forEach(function(event) {
// eventBus.on(event, function(e) {
// console.log('点击了节点')
// //bpmn:Lane bpmn:SequenceFlow bpmn:Task bpmn:SequenceFlow bpmn:ExclusiveGateway
// //bpmn:Process
// console.log(event + ' ' + JSON.stringify(e))
// // if (e.element.type === 'bpmn:Process' || e.element.type === 'bpmn:Lane') return
// // //debugger;
// // const elementRegistry = bpmnjs.get('elementRegistry')
// // const shape = elementRegistry.get(e.element.id)
// // // console.log(shape)
// // modeling.setColor(shape, { stroke: 'RED' })
// // // _self.nodeCode=e.element.id;
// // _self.nodeCode = shape.businessObject.id;
// // // console.log(_self.nodeCode)
// // _self.nodeName = shape.businessObject.name;
// // _self.getDialogId()
// })
// })
}
}
}
</script>
<style lang="scss">
@import 'aaa@qq.com/less/diagram-js.css';
@import 'aaa@qq.com/less/bpmn-font/css/bpmn-embedded.css';
.containers {
position: absolute;
display: inline-block;
background-color: #ffffff;
width: 90%;
height: 90%;
}
.canvas {
width: 100%;
height: 100%;
pointer-events: none;
cursor: default;
}
.panel {
position: absolute;
right: 0;
top: 0;
width: 300px;
}
.nodeSuccess:not(.djs-connection) .djs-visual > :nth-child(1) {
stroke: #1890ff !important;
stroke-width: 3px;
/* elements as success */
}
.nodeError:not(.djs-connection) .djs-visual > :nth-child(1) {
stroke: red !important;
stroke-width: 3px;
/* elements as error */
}
.lineSuccess:not(.djs-shape) .djs-visual :last-child {
stroke: #1890ff !important;
}
.lineError:not(.djs-shape) .djs-visual :last-child {
stroke: red !important;
}
.canvas img {
// 隐藏bpmn-js引入的图标
display: none;
}
.two-column {
// 隐藏左边操作栏
display: none;
}
</style>
使用方法
在其他页面里引入这个模板,通过ref调用子组件的方法,需要传入参数:流程定义id,流程实例id,弹窗大小
<template>
<div>
<a @click="handleLook()">查看</a>
<Bpmn ref="bpmn"></Bpmn>
</div>
</template>
<script>
import Bpmn from '@/components/Bpmn'
export default {
name: 'ProcessManageList',
components: {
Bpmn
},
methods: {
handleLook() {
let record = {
proId: '流程定义id',
proInstanceId: '流程实例id'
}
this.$refs.bpmn.parentHandleclick(record.proId, record.proInstanceId, '300px');
}
}
}
</script>
测试: