基于bpmn.js、React、Midway.js的在线流程编辑、数据管理工具(1)

3,809 阅读5分钟

最近部门要制作审批中台项目,前期调研过一些BPMN和NBF流程中心相关的知识。自己便动手尝试通过React、Midway.js和bpmn.js来制作web流程编辑+数据管理SDK。

背景、整体想法

由于事先了解过了阿里NBF流程中心的使用方法。对于这个小工具,首先,我们需要靠React和bpmn.js来实现浏览器在线的绘制bpmn2.0标准的流程图。对于流程图的每一个节点,我们可以自定义地编辑其属性,相关的任务,以及此节点任务需要调用的Node.js数据服务。

bpmn.js

image.png 什么是bpmn.js呢?bpmn.js是用于浏览器或者Node.js环境的渲染工具包/web bpmn建模器。由国外的开发者开发。我们通过BPMN.js和React或者Vue这种前端框架结合。

我们可以在web网页上,来画出符合BPMN2.0标准的流程图。同是我们还可以利用bpmn.js的基本模版,属性模版功能,在web端上,来自由地编辑bpmn2.0标准的流程图(任意添加节点,网关,事件以及各个节点的属性)

最近,使用了bpmn.js和React/Umi的结合,制作出web在线版的简易bpmn流程编辑工具。

image.png

下面,我想从最基础的技术(create-react-app、bpmn.js)来讲解,先来讲一讲我们如何用bpmn.js制作一个简易的React在线流程编辑器。

React + bpmn.js 流程管理 —— 实现简单的bpmn流程绘制,编排

一切首先得从bpmn.js和React入手,来制作一个简易的在线bpmn流程管理工具。我们使用create-react-app脚手架,搭建好一个react项目,之后通过npm来引入bpmn.js。

操作步骤:

npx create-react-app newapproval

npm install bpmn-js --save

npm install antd --save

first-step:初始bpmn流程图

由于,bpmn.js所展现的流程图是xml驱动的SVG。所以我们在React项目中,需要先来引用一个写好的xml文件,作为本次展示的示例:

./utils/testxml.js:

export const xmlstr = 
`<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
<process id="Process_1" isExecutable="false">
    <startEvent id="StartEvent_1y45yut" name="开始">
    <outgoing>SequenceFlow_0h21x7r</outgoing>
    </startEvent>
    <task id="Task_1hcentk">
    <incoming>SequenceFlow_0h21x7r</incoming>
    </task>
    <sequenceFlow id="SequenceFlow_0h21x7r" sourceRef="StartEvent_1y45yut" targetRef="Task_1hcentk" />
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
    <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
    <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_1y45yut">
        <omgdc:Bounds x="152" y="102" width="36" height="36" />
        <bpmndi:BPMNLabel>
        <omgdc:Bounds x="160" y="145" width="22" height="14" />
        </bpmndi:BPMNLabel>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape id="Task_1hcentk_di" bpmnElement="Task_1hcentk">
        <omgdc:Bounds x="240" y="80" width="100" height="80" />
    </bpmndi:BPMNShape>
    <bpmndi:BPMNEdge id="SequenceFlow_0h21x7r_di" bpmnElement="SequenceFlow_0h21x7r">
        <omgdi:waypoint x="188" y="120" />
        <omgdi:waypoint x="240" y="120" />
    </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>`

ok 我们有了静态的xml文件之后,我们可以在React代码中,来引入我们的bpmn了。我们需要先建立一组div,作为整个bpmn绘制的div容器。

之后引入bpmn-js/lib的BpmnModeler,用来初始化建模bpmn图形。

写好了方法之后,在uesEffect或者componentDidMounted生命周期中执行就可以了。

import { useEffect } from 'react';
import BpmnModeler from 'bpmn-js/lib/Modeler';
import { xmlstr } from './utils/testxml';
import './App.css';

// 全局组件
function App() {

  let bpmnModeler = null;

  useEffect(() => {  
    initBpmn();
  }, [])

  const initBpmn = () => {

    bpmnModeler = new BpmnModeler({
      container: '#canvas', // 这里为数组的第一个元素
      height: '100vh',
    });

    createBpmnDiagram();
  }

  const createBpmnDiagram = async () => {
    // 开始绘制出事bpmn的图
    try {
      const result = await bpmnModeler.importXML(xmlstr);
      console.log(result);
    } catch(error) {
      console.error(error)
    }
  }

  return (
    <div className="App">
      {/* bpmn容器 */}
      <div id="canvas" className="container"></div>
    </div>
  );
}

export default App;
.App {
  /* background-color: #282c34 */
  min-height: 100vh;
}
.container{
  width: 100%;
  height: 100%;
}

其中,BpmnModeler属于bpmn-js的一个API,通过new BpmnModeler来对它进行定义,确定他所存在div节点,以及相对应的大小,之后通过importXML方法来对我们之前保存好的xml进行引入,我们可以在网页上得到此建模器所绘制的bpmn流程图效果。

image.png

(踩坑:xml文件的写法,应当严格按照上面所给的js文件的写法来,在React项目中回程别的写法可能会有报错)

这里分享一下bpmn.Modeler的相关api方法,参数:

image.png

second-step:添加属性面板,画图工具栏

单纯只有bpmn流程图(SVG)肯定是不够的。我们还需要画图工具栏和属性面板,这样,我们就可以在web网页上完整地绘制BPMN流程图了。

bpmn.js属性面板,是单独的一个npm包,我们需要单独引入。

操作步骤:

npm install bpmn-js-properties-panel --save-D
npm install camunda-bpmn-moddle --save-D

装完这两个包之后,我们就可以在React项目中引入属性面板了。(其中,camunda-bpmn-moddle官方的解释是将将BPMN 2.0的Camunda名称空间扩展定义为模块描述符。通过这个包,我们在使用bpmn.moddle可以自由创建bpmn流程节点,同时它也可用于bpmn.Modeler的Extension扩展中)

之后,我们在React项目中,首先,见一个className为properties-panel的div节点,之后引入propertiesPanelModule、propertiesProviderModule和camundaModdleDescriptor。

在BpmnModeler的propertiesPane、additionalModules和moddleExtensions添加相对应的属性。

// APP.js
import { useEffect } from 'react';
import BpmnModeler from 'bpmn-js/lib/Modeler';
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 { xmlstr } from './utils/testxml';
import './App.css';

// 全局组件
function App() {

  let bpmnModeler = null;

  useEffect(() => {
    
    initBpmn();
  }, [])

  const initBpmn = () => {

    bpmnModeler = new BpmnModeler({
      container: '#canvas', // 这里为数组的第一个元素
      height: '100vh',
      //添加控制板
      propertiesPanel: {
        parent: '.properties-panel'
      },
      additionalModules: [
        // 左边工具栏以及节点
        propertiesPanelModule,
        propertiesProviderModule
      ],
      moddleExtensions: {
        camunda: camundaModdleDescriptor
      }
    });

    createBpmnDiagram();
  }

  const createBpmnDiagram = async () => {
    // 开始绘制出事bpmn的图
    try {
      const result = await bpmnModeler.importXML(xmlstr);
      console.log(result);
      console.log('属性面板数据: ', bpmnModeler.get('propertiesPanel'));
    } catch(error) {
      console.error(error)
    }
  }

  return (
    <div className="App">
      {/* bpmn容器 */}
      <div id="canvas" className="container"></div>
      <div  className="properties-panel"></div>
    </div>
  );
}

export default App;
.App {
  /* background-color: #282c34 */
  min-height: 100vh;
}
.container{
  width: 100%;
  height: 100%;
}
.properties-panel{
  position: absolute;
  right: 0;
  top: 0;
  width: 300px;
}

(踩坑:BpmnModeler的引入一定要写完整,否则网页绘制bpmn流程图会有显示不出的情况。)

光有这些还不够,我们需要引入相对应的css样式,这样才能将绘图工具和属性面板展现。(这里,我将相关的css、文件放到主组件里。)

// mian.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

// 以下为bpmn工作流绘图工具的样式
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/bpmn-js-properties-panel.css'

ReactDOM.render(
    <App />,
  document.getElementById('root')
);

得到的效果:

image.png

后续想法

本文主要讲了,如何去初步地实现一个在线bpmn流程展现,绘制的工具。后面,如何去完善这个Demo?

  1. 需要去建立Node.js服务端体系,将用户每次绘制好的bpmn流程图,用bpmn-js自带的相关事件进去获取,传递到服务端。
  2. 同时,我们需要针对不同的节点,不同的流程出发不同的事件,从而达到不同业务需求。
  3. 如何去自定义bpmn的调色板、属性面板,整体色调等等。