沒有一個順手的流程繪製工具?好吧,自己動手,豐衣足食!

語言: CN / TW / HK

流程繪製工具感覺也挺常用的,而且流程圖基本上也都標準化了,標準化的東西其實是最容易做的,但是 IDEA 上卻一直沒有一個稱手的流程繪製工具,其實這也是一個機會吧哈哈,自己搞一個 IDEA 插件~

不過這個機會留給各位正在閲讀本文的小夥伴吧,鬆哥今天跟大家介紹另外一個工具 bpmn.js,利用這個,再結合大家熟悉的 Vue,我們就可以開發出一個自己的流程繪製工具,一起來看下。

先看下效果圖:

好了,不廢話了,開搞!

1. bpmn.js

bpmn.js 是一個工具包,利用這個工具包,我們可以非常方便的在瀏覽器中創建、嵌入或者擴展一個 BPMN 流程圖,重要的是,這個過程非常 Easy,我們只需要少量代碼即可實現這一目標。

不知道看文章的小夥伴們日常工作中接觸流程圖多不多,如果經常接觸的話,我估計有不少小夥伴可能都見過基於 bpmn.js 構建出來的流程圖繪製工具。

因為 flowable-ui 這種太重量級了,如果我們單純的只是想在自己的項目中嵌入一個流程繪製工具,那麼顯然 bpmn.js 是最佳選擇。

網上其實也有不少關於 bpmn.js 的文章,不過當和 Vue 整合的時候,基本上都用的是 Vue2,而這個工具在 Vue2 和 Vue3 的使用中,還是有不少差異的,今天鬆哥就以 Vue3 為例,來和小夥伴們分享一下這個工具在 Vue3 中的使用。

2. + Vue3

2.1 項目創建

首先我們執行如下命令,來創建一個 Vue3 項目:

npm create vite@latest bpmn_demo --template vue
cd bpmn_demo
npm install
npm run dev

創建完成後,我們先來裝上 bpmn.js 所需要的依賴,一共是三個依賴:

  • bpmn-js

這是最核心的流程繪製工具了。

  • bpmn-js-properties-panel

這是 bpmn-js 的屬性面板,流程圖中的每一個節點都有屬性,如果需要配置這些數據,就需要用到這個依賴,小夥伴們看看下圖中右邊的部分,就是這個依賴實現的功能:

  • camunda-bpmn-moddle

如果你的流程引擎使用了 Camunda,那麼可以通過 camunda-bpmn-moddle 模塊來配置該流程所支持的任務屬性。

好啦,廢話不多説,先把這三個依賴依次安裝上:

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

另外,鬆哥親測,還需要安裝 @bpmn-io/properties-panel 和 inherits 用以解決依賴內部的兼容性問題,安裝命令如下:

npm i @bpmn-io/properties-panel
npm i inherits

另外,項目中用到了一個 ElementUI 的按鈕,所以需要安裝上 ElementUI-Plus,如下:

npm install element-plus --save

裝好之後,我給大家看下我安裝的版本,都是目前最新版:

{
  "name": "bpmn_demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@bpmn-io/properties-panel": "^0.19.0",
    "bpmn-js": "^9.4.0",
    "bpmn-js-properties-panel": "^1.5.0",
    "camunda-bpmn-moddle": "^6.1.2",
    "element-plus": "^2.2.14",
    "inherits": "^2.0.4",
    "vue": "^3.2.37"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.0.3",
    "vite": "^3.0.7"
  }
}

鬆哥親測,如果使用 Webpack 而不是 Vite 來構建項目的話,那麼可以不用安裝 inherits,這個小夥伴們根據自己的實際情況安裝即可,項目創建完成後,如果提示缺少這個組件就安裝一下,如果不提示那就忽略即可。

2.2 開發頁面

用 Vite 新建的項目默認沒有安裝路由,配路由也比較麻煩,所以我這裏就省事一些,我直接新建一個組件來寫我們的頁面,將來在 App.vue 中引入我這個新建的組件即可。

首先我新建一個名為 BpmnView 的組件,然後在這個組件中配置 bpmn.js,內容如下:

<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">下載</el-button>
    </div>
</div>

小夥伴們看到,這個頁面整體上分為兩部分,上面是我們繪製的主區域,包括繪圖區以及屬性設置區;下面則放了一個下載流程圖 XML 文件的按鈕。

在上面的主繪製區,我們放了兩個東西,一個是畫布 canvas,另一個是屬性 properties,canvas 就是流程圖繪製時候的核心區域,properties 則是流程中的每一個節點的屬性配置。

參考下圖,大家就知道 canvas 和 properties 分別表示什麼了:

接下來我們先來初始化左邊的 canvas。

2.2.1 canvas

首先我們來看下左邊的 Canvas 該如何初始化。

<script setup>
    import { onMounted} from 'vue';

    import BpmnModeler from 'bpmn-js/lib/Modeler';

    let bpmnModeler;
    onMounted(() => {
        // 建模
        bpmnModeler = new BpmnModeler({
            container: '#canvas'
        })
        bpmnModeler.createDiagram();
    })
</script>

這個初始化工作在 onMounted 回調中完成。

創建 BpmnModeler 並設置畫布。

調用 createDiagram 方法開始繪圖。

配置完成後,還要記得在 main.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'

現在就可以了,左邊可以開始畫流程圖了。

2.2.2 properties

再來看右邊屬性的配置。

首先在 main.js 中加入右邊屬性的樣式文件:

import 'bpmn-js-properties-panel/dist/assets/properties-panel.css'

然後繼續在 BpmnView.vue 中進行配置即可:

<script setup>
    import {onMounted} from 'vue';

    import BpmnModeler from 'bpmn-js/lib/Modeler';
    import {
        BpmnPropertiesPanelModule,
        BpmnPropertiesProviderModule,
        CamundaPlatformPropertiesProviderModule
    } from 'bpmn-js-properties-panel';
    import CamundaExtensionModule from 'camunda-bpmn-moddle/lib';
    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();
    })
</script>

在創建 BpmnModeler 的時候,通過 propertiesPanel 去指定 parent 的位置,再把另外五個額外的模塊掛載上去就行了,這五個模塊分別代表不同的屬性,我就不挨個説了,小夥伴們可以自行嘗試刪除掉一個屬性,看看哪些屬性少了,就知道這個模塊的功能了。

2.2.3 下載按鈕

最後再來看看下載按鈕的點擊事件。

function 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();
            }
        }
    })
}
function getFileName(xml) {
    let split = xml.split('process id="');
    return split[1].split('" ')[0]+".bpmn20.xml";
}

調用 bpmnModeler.saveXML 方法,回調中的 xml 參數就是生成的流程圖 XML 文件,然後創建一個虛擬的 a 標籤,模擬一個點擊事件即可完成下載。

getFileName 方法則是從下載的 XML 文件中截取出來 bpmn:process 標籤的 id 值作為文件名,這也符合我們日常的命名習慣。

好啦,大功告成!以後就可以使用我們自己的流程繪製工具來畫流程圖了。

不過有一個小小遺憾,就是這個是針對 Camunda 這個流程引擎的,如果所以他畫出來的流程圖並不能直接用在 Flowable 中,如果想在 Flowable 中使用,還需要一點額外的定製,這個咱們以後再説。

3. 小結

bpmn.js 最大的優勢在於可以根據自己項目的需求,方便的嵌入到已有項目中。好啦,公眾號江南一點雨後台回覆 bpmn_demo 可以下載文本完整案例。