本文主要讲解在jeecgboot前端项目中如何集成bpmn-js。首先要明确一点Bpmn-Js默认支持Camunda流程引擎。如果需要支持Flowable,Activiti则需另行改造!

项目环境说明

 "vue": "^3.2.45",
 "vite": "^4.1.0",
 "vue-tsc": "^1.0.24"

项目采用最新vue3+ts+vite进行构建

# Bpmn-Js集成

  • 在项目的终端执行如下命令
pnpm install bpmn-js@^13.2.2
pnpm install bpmn-js-properties-panel@^3.0.0
pnpm install bpmn-js-token-simulation@^0.21.1
pnpm install camunda-bpmn-moddle@^7.0.1
pnpm install @bpmn-io/properties-panel@^3.13.0
pnpm install sass
pnpm install diagram-js

  • 检查package.json是否安装成功相应的模块
"dependencies": {
   "@ant-design/colors": "^7.0.2",
   "@ant-design/icons-vue": "^7.0.1",
   //这里
   "@bpmn-io/properties-panel": "^3.13.0",

   "@iconify/iconify": "^3.1.1",
   "@jeecg/online": "3.7.0-beta",
   "@tinymce/tinymce-vue": "4.0.7",
   "@traptitech/markdown-it-katex": "^3.6.0",
   "@vue/shared": "^3.4.19",
   "@vueuse/core": "^10.8.0",
   "@zxcvbn-ts/core": "^3.0.4",
   "ant-design-vue": "^4.1.2",
   "axios": "^1.6.7",
   //这里
   "bpmn-js": "^13.2.2",
   "bpmn-js-properties-panel": "^3.0.0",
   "bpmn-js-token-simulation": "^0.21.1",
   "camunda-bpmn-moddle": "^7.0.1",

   "china-area-data": "^5.0.1",
   "clipboard": "^2.0.11",
   "codemirror": "^5.65.3",
   "cron-parser": "^4.9.0",
   "cropperjs": "^1.6.1",
   "crypto-js": "^4.2.0",
   "dayjs": "^1.11.10",
   "dom-align": "^1.12.4",
   "echarts": "^5.4.3",
   "emoji-mart-vue-fast": "^15.0.1",
   "enquire.js": "^2.1.6",
   "event-source-polyfill": "^1.0.31",
   "highlight.js": "^11.9.0",
   "intro.js": "^7.2.0",
   "lodash-es": "^4.17.21",
   "lodash.get": "^4.4.2",
   "markdown-it": "^14.0.0",
   "markdown-it-link-attributes": "^4.0.1",
   "md5": "^2.3.0",
   "mockjs": "^1.1.0",
   "nprogress": "^0.2.0",
   "path-to-regexp": "^6.2.1",
   "pinia": "2.1.7",
   "print-js": "^1.6.0",
   "qrcode": "^1.5.3",
   "qs": "^6.11.2",
   "resize-observer-polyfill": "^1.5.1",
   //这里
   "sass": "^1.77.6",

   "showdown": "^2.1.0",
   "sortablejs": "^1.15.2",
   "tinymce": "6.6.2",
   "vditor": "^3.9.9",
   "vue": "^3.4.19",
   "vue-cropper": "^0.6.4",
   "vue-cropperjs": "^5.0.0",
   "vue-i18n": "^9.9.1",
   "vue-infinite-scroll": "^2.0.2",
   "vue-print-nb-jeecg": "^1.0.12",
   "vue-router": "^4.3.0",
   "vue-types": "^5.1.1",
   "vuedraggable": "^4.1.0",
   "vxe-table": "4.6.17",
   "vxe-table-plugin-antd": "4.0.7",
   "xe-utils": "3.5.26",
   "xss": "^1.0.14"
 },
  • main.ts 配置bpmn-js样式
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 'bpmn-js-properties-panel/dist/assets/properties-panel.css' // 右边工具栏样式

# MyCamunda.vue

定义一个camunda文件。用于完成代码的整合

<template>
    <div>
        <div class="containers" style="display: flex;width:100%;height: 96vh">
            <div class="canvas" style="width: 100%" id="canvas"></div>
            <div id="properties">
            </div>
        </div>
        <div style="display:flex;justify-content: flex-end;">
            <el-button @click="downloadXML" type="primary" :icon="Download" style="width:104px">下载</el-button>
        </div>
    </div>
</template>

<script setup lang="ts"> 
import {onMounted} from 'vue';

import BpmnModeler from 'bpmn-js/lib/Modeler';
import {
    BpmnPropertiesPanelModule,
    BpmnPropertiesProviderModule,
    CamundaPlatformPropertiesProviderModule
} from 'bpmn-js-properties-panel';

import camundaModdleDescriptors from 'camunda-bpmn-moddle/resources/camunda';

let bpmnModeler;
onMounted(() => {
    // 建模
    bpmnModeler = new BpmnModeler({
        container: '#canvas', propertiesPanel: {
            parent: '#properties'
        },
        additionalModules: [
            BpmnPropertiesPanelModule,
            BpmnPropertiesProviderModule,
            CamundaPlatformPropertiesProviderModule
            // CamundaExtensionModule
        ],
        moddleExtensions: {
            camunda: camundaModdleDescriptors
        }
    })
    bpmnModeler.createDiagram();
})

const downloadXML = () =>{
    bpmnModeler.saveXML({format: true}, (err, xml) => {
        if (!err) {
            console.log(xml);
            // 获取文件名
            const name = getFileName(xml);
            // 把输就转换为URI,下载要用到的
            const encodedData = encodeURIComponent(xml);
            const downloadLink = document.createElement('a');
            if (xml) {
                // 将数据给到链接
                downloadLink.href =
                    "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
                // 设置文件名
                downloadLink.download = name;
                // 触发点击事件开始下载
                downloadLink.click();
            }
        }
    })
}
const getFileName = (xml) =>{
    let split = xml.split('process id="');
    return split[1].split('" ')[0]+".bpmn20.xml";
}

</script>


<style scoped>

</style>

# 异常分析

在加载bpmn文件之后会出现如下异常情况。

Error: Passing callbacks to importXML is deprecated and will be removed in a future major release. Please switch to promises: https://bpmn.io/l/moving-to-promises.html
    at Viewer.importXML (chunk-CNF6DI4Q.js?v=30ff7c0e:824:20)
    at importXml (ModelView.vue:62:17)
    at ModelView.vue:56:13

官方提供的解决方案 (opens new window)

//修改前
  const importXml =  (xml:string) =>{
     bpmnViewer.importXML(xml, (err) => {
        if (err) {
            console.error(err, 1111)
        } else {
              // 使流程图自适应屏幕
            let canvas = bpmnViewer.get('canvas')
            canvas.zoom('fit-viewport', 'auto')
        }
       })
  }

//修改后的写法
 const importXml = async (xml:string) =>{
      try {
        const result = await bpmnViewer.importXML(xml);
        const { warnings } = result;
        console.log(warnings);
        //使流程图自适应屏幕
        let canvas = bpmnViewer.get('canvas')
        canvas.zoom('fit-viewport', 'auto')
      } catch (err) {
        console.log(err.message, err.warnings);
      }
  }
  
//主要将方法改成了Promis格式, 问题解决了!!!!  

集成之后的Bpmn-Js效果 (opens new window)