針對一些開發(fā)中可能遇到的問題,進(jìn)行設(shè)想和總結(jié)
寫在最前
一些已經(jīng)掌握的技術(shù)點(diǎn)分享
bpmn-js生成的xml結(jié)構(gòu)
- 主要分成2大塊

- bpmndi節(jié)點(diǎn) 是圖像渲染的部分,和我們的業(yè)務(wù)邏輯關(guān)系不大
- process包含了幾種節(jié)點(diǎn),
1.開始 startEvent
2.線 sequenceFlow
3.任務(wù)(方塊) task
4.判斷節(jié)點(diǎn),網(wǎng)關(guān)(菱形) exclusiveGateway
5.結(jié)束 endEvent
更多元素內(nèi)容參考BPMN2規(guī)范內(nèi)容 - 每個(gè)都包含id,name屬性,name就是現(xiàn)實(shí)在上面的文字
- 任務(wù),判斷 節(jié)點(diǎn)包含 incoming,outgoing子節(jié)點(diǎn)
- 線 只有 起點(diǎn)-sourceRef,指向-targetRef 屬性
- 起點(diǎn)只有 outgoing 節(jié)點(diǎn),結(jié)束 只有 incoming 節(jié)點(diǎn)
incoming,outgoing,sourceRef,targetRef 都是指向一個(gè)id
我們只要通過這些數(shù)據(jù)就能記錄某次操作去向何方,并且通過時(shí)間可以得知當(dāng)前運(yùn)行時(shí)的流程 當(dāng)前執(zhí)行到哪里已經(jīng)過去所有的操作過程.
給一個(gè)基礎(chǔ)的"單步操作記錄實(shí)體"設(shè)計(jì):
/// <summary>
/// 每一步操作,包括了開始和結(jié)束,進(jìn)入和離開
/// </summary>
public class Operation
{
public string Id { get; set; }
/// <summary>
/// 從哪來
/// </summary>
public string From { get; set; }
/// <summary>
/// 現(xiàn)在在哪里
/// </summary>
public string Here { get; set; }
/// <summary>
/// 創(chuàng)建時(shí)間
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 做了啥
/// </summary>
public string Remark { get; set; }
}
- bpmn-js 有一些發(fā)布于npm的擴(kuò)展包,比如
Properties Panel

大膽猜測 其實(shí)Properties Panel 無非是修改了xml的字段屬性(由于是nodejs的項(xiàng)目,目前還沒辦法測試)
下面介紹一下我的解決方案和一些思路
首先,我畫了一個(gè)簡化安樁流程圖如下

<?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="http://bpmn.io" exporterVersion="0.10.1">
<collaboration id="Collaboration_13mq84e">
<participant id="Participant_0g75ubx" processRef="Process_1" />
</collaboration>
<process id="Process_1" isExecutable="false">
<!--泳道-->
<laneSet>
<lane id="Lane_05t1wqa" name="經(jīng)銷商">
<flowNodeRef>Task_1</flowNodeRef>
<flowNodeRef>Task_1y56h2p</flowNodeRef>
<flowNodeRef>StartEvent_1</flowNodeRef>
</lane>
<lane id="Lane_1vbqiw2" name="服務(wù)商">
<flowNodeRef>Task_1ubxr83</flowNodeRef>
<flowNodeRef>ExclusiveGateway_01todg7</flowNodeRef>
<flowNodeRef>Task_0cxcj51</flowNodeRef>
<flowNodeRef>IntermediateThrowEvent_0pknvty</flowNodeRef>
</lane>
</laneSet>
<!--/泳道-->
<!--開始-->
<startEvent id="StartEvent_1" name="開始">
<outgoing>SequenceFlow_1</outgoing>
</startEvent>
<!--/開始-->
<sequenceFlow id="SequenceFlow_1" name="" sourceRef="StartEvent_1" targetRef="Task_1" />
<task id="Task_1" name="收集信息并創(chuàng)建工單">
<incoming>SequenceFlow_1</incoming>
<outgoing>SequenceFlow_13cmz0x</outgoing>
</task>
<sequenceFlow id="SequenceFlow_13cmz0x" sourceRef="Task_1" targetRef="Task_1y56h2p" />
<task id="Task_1y56h2p" name="選擇服務(wù)商">
<incoming>SequenceFlow_13cmz0x</incoming>
<incoming>SequenceFlow_0pfete3</incoming>
<outgoing>SequenceFlow_00i63bm</outgoing>
</task>
<task id="Task_1ubxr83" name="簽收">
<incoming>SequenceFlow_00i63bm</incoming>
<outgoing>SequenceFlow_1v2dj37</outgoing>
</task>
<sequenceFlow id="SequenceFlow_1v2dj37" sourceRef="Task_1ubxr83" targetRef="ExclusiveGateway_01todg7" />
<exclusiveGateway id="ExclusiveGateway_01todg7" name="是否合格">
<incoming>SequenceFlow_1v2dj37</incoming>
<outgoing>SequenceFlow_0j75wny</outgoing>
<outgoing>SequenceFlow_0pfete3</outgoing>
</exclusiveGateway>
<sequenceFlow id="SequenceFlow_0j75wny" name="是" sourceRef="ExclusiveGateway_01todg7" targetRef="Task_0cxcj51" />
<task id="Task_0cxcj51" name="安裝">
<incoming>SequenceFlow_0j75wny</incoming>
<outgoing>SequenceFlow_14n5686</outgoing>
</task>
<sequenceFlow id="SequenceFlow_14n5686" sourceRef="Task_0cxcj51" targetRef="IntermediateThrowEvent_0pknvty" />
<sequenceFlow id="SequenceFlow_00i63bm" sourceRef="Task_1y56h2p" targetRef="Task_1ubxr83" />
<sequenceFlow id="SequenceFlow_0pfete3" name="否" sourceRef="ExclusiveGateway_01todg7" targetRef="Task_1y56h2p" />
<!--結(jié)束-->
<endEvent id="IntermediateThrowEvent_0pknvty" name="結(jié)束">
<incoming>SequenceFlow_14n5686</incoming>
</endEvent>
<!--結(jié)束-->
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
<!--圖像渲染部分省略-->
</bpmndi:BPMNDiagram>
</definitions>
現(xiàn)有問題匯總:
1.如何應(yīng)用表達(dá)式
2.如何綁定視圖
3.如何通過視圖泳道來判斷權(quán)限等問題
4.如何生成流程
5.流程如何運(yùn)行
我的方案
后端設(shè)計(jì)好表達(dá)式和視圖,并指定特定的Id/Name標(biāo)識,通過 Properties Panel 加到流程圖上(xml) 以下拉框等方式讓用戶選擇,并指定給 方塊/菱形 ,這樣 視圖引擎運(yùn)行到某個(gè)task或者 gateway的時(shí)候,可以通過 其上綁定的屬性 找到指定的 方法/視圖.
后端我建議我們自己開發(fā)一套流程解析引擎
大致包括數(shù)據(jù)內(nèi)容:
1.流程圖
2.運(yùn)行時(shí)任務(wù)
3.任務(wù)操作
4.表達(dá)式
5.視圖
6.相關(guān)數(shù)據(jù)
...
針對流程圖的修改,我建議每次修改都必須重新生成新的流程圖,之前的 運(yùn)行時(shí)任務(wù) 不能遷移到新流程上.
要廢棄老流程圖,必須在其上的運(yùn)行時(shí)任務(wù)都結(jié)束/終止
關(guān)于泳道
流程圖中保存了泳道,我們可以把對應(yīng)的用戶存入其中,而泳道的子節(jié)點(diǎn)涵蓋了所有在其中的模塊Id如圖:

關(guān)于引擎如何運(yùn)作
我們需要有
一個(gè)展示方法:傳入[流程圖],[運(yùn)行時(shí)任務(wù)],[當(dāng)前用戶],方法通過查詢所有[任務(wù)操作]返回視圖/表達(dá)式表單 等待用戶操作
一個(gè)操作方法:傳入[操作結(jié)果],[流程圖],[運(yùn)行時(shí)任務(wù)],[當(dāng)前用戶],方法會添加一個(gè)[任務(wù)操作],這樣就任務(wù)就到"下一步"了
總結(jié),我們需要有一個(gè)通用的方法來解析傳入的task/gateway,他們可能包含不同的表單,判斷,而通用方法需要給出指定的操作
關(guān)于數(shù)據(jù)隔離
參考之前我做的一個(gè)流程項(xiàng)目,他們的做法是 每個(gè)新的 流程圖 都會有自己獨(dú)立的表 由系統(tǒng)自動(dòng)創(chuàng)建,但他們的設(shè)計(jì)和我們的不太一樣,他們的引擎生成的每個(gè)表的字段非常多,幾乎涵蓋了所有相關(guān)數(shù)據(jù),我認(rèn)為這個(gè)是沒有必要的.
方案風(fēng)險(xiǎn)
1.Properties Panel 的二次開發(fā)
由于這個(gè)東西是nodejs的 集成到我們.net項(xiàng)目中沒有相關(guān)經(jīng)驗(yàn),二次開發(fā)修改成我們想要的樣子,比如視圖選擇框等功能難度較大.
2.子流程開發(fā)問題
如何雙擊進(jìn)入某個(gè)流程的子流程,這個(gè)也是需要對bpmn進(jìn)行深入研究的
3.流程解析引擎
如果需要實(shí)現(xiàn)所有bpmn2.0的規(guī)范與要求,我們自主開發(fā)的流程引擎短時(shí)間內(nèi)肯定做不到,但要實(shí)現(xiàn)安裝2的需求,并部分實(shí)現(xiàn)bpmn2.0是可能的
4.表單設(shè)計(jì)器
針對每一步需要填寫的表單資料,如何設(shè)計(jì),是固定還是需要有編輯器,如果要編輯器,則需要開發(fā)時(shí)間,但一勞永逸