vue中使用bpmn.js 绘制流程图

项目中需要前端绘制流程图保存为xml通过接口调用传给后台

npm安装bpmn

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代码

<template>
  <div class="containers">
    <div class="canvas" ref="canvas" />
    <div id="js-properties-panel" class="panel"></div>
    <div class="toolbar">
      <a title="download">下载</a>
      <a ref="saveDiagram1" href="javascript:" title="download BPMN diagram">BPMN</a>
      <a ref="saveSvg" href="javascript:" title="download as SVG image">SVG</a>
      
    </div>
  </div>
</template>

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 = `
     <?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0bka6us" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.0.0">
  <bpmn:process id="PSVMKKK" name="测试流程发布" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_0kaxh13</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:endEvent id="Event_061g5sm">
      <bpmn:incoming>Flow_0t6sg2a</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0kaxh13" sourceRef="StartEvent_1" targetRef="Activity_145aizd" />
    <bpmn:userTask id="Activity_145aizd" name="审批节点">
      <bpmn:incoming>Flow_0kaxh13</bpmn:incoming>
      <bpmn:outgoing>Flow_0t6sg2a</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:sequenceFlow id="Flow_0t6sg2a" sourceRef="Activity_145aizd" targetRef="Event_061g5sm" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="PSVMKKK">
      <bpmndi:BPMNEdge id="Flow_0t6sg2a_di" bpmnElement="Flow_0t6sg2a">
        <di:waypoint x="410" y="117" />
        <di:waypoint x="532" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0kaxh13_di" bpmnElement="Flow_0kaxh13">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="310" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_061g5sm_di" bpmnElement="Event_061g5sm">
        <dc:Bounds x="532" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0wfa4qo_di" bpmnElement="Activity_145aizd">
        <dc:Bounds x="310" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>
      `;
      // 将字符串转换成图显示出来
      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 = `<div style='font-size: 14px;font-weight:500;margin-left:15px;'>${
                controlProps["title"]
              }</div>`;
              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;
      }
    },

  }
Logo

前往低代码交流专区

更多推荐