使用bpmn-js
流程图开发过程中会遇到会签和或签的问题,这个时候我们就需要使用多实例配置来实现BPMN 2.0
的配置实现了,多实例任务,是从流程编辑概念之初也就是Activiti
时期就存在的一个方式。所谓的多实例任务也就是字面意思,一个任务由多个人完成,常见于我们的审批流程的或签【一个审批完成即可】和会签【多个用户审批都通过才算结束】,由于存在多个成员的操作,引入了多实例的概念。
多实例
分类
多实例的出现其实就是确定重复的多成员操作的工作流顺序关系,按此可区分为串行和并行:
- 串行多实例:按先后顺序执行,依序执行
- 并行多实例:完成任务没有先后顺序的要求,并行执行
flowable
中的多实例的配置样式如下所示:
如上就是一个并行多实例审批的图示,生成xml
格式如下:
<bpmn2:userTask id="Activity_1vv1m6z" name="审批">
<bpmn2:incoming>Flow_0w3q52d</bpmn2:incoming>
<bpmn2:outgoing>Flow_1ugegu7</bpmn2:outgoing>
<bpmn2:multiInstanceLoopCharacteristics flowable:collection="assigneeList" flowable:elementVariable="assignee">
<bpmn2:extensionElements>
<flowable:executionListener class="cn.com.fsg.hcmplus.flowable.service.flowservice.flowlistener.ParallelListener" event="start" />
</bpmn2:extensionElements>
// <bpmn2:loopDataInputRef>assigneeList</bpmn2:loopDataInputRef>
// <bpmn2:inputDataItem name="assignee" />
<bpmn2:completionCondition xsi:type="bpmn2:tFormalExpression">${multiInstanceCompleteTask.accessCondition(execution)}</bpmn2:completionCondition>
</bpmn2:multiInstanceLoopCharacteristics>
</bpmn2:userTask>
配置属性
如上:bpmn2:multiInstanceLoopCharacteristics
节点就是多实例审批配置节点,通过上述节点我们了解下基础的节点配置属性:
isSequential
:true
为串行多实例,false
为并行多实例collection
:适配flowable
中该属性为:flowable:collection
, 表示多实例的人员集合的变量名,,同时也支持通过loopDataInputRef
设置elementVariable
:适配flowable
中该属性为:flowable:
,表示多实例集合中的元素的变量名,同时也支持通过elementVariable
inputDataItem
设置completionCondition
:配置多实例完成的条件loopCardinality
:使用loopCardinality
子元素直接指定一个数字作为多实例的数量FailedJobRetryTimeCycle
: 重试周期
支持元素
bpmn
中常用的任务类型元素模型均支持使用多实例方式配置,如下提供部分支持的元素模型:
- User Task
- Script Task
- Java Service Task
- Call Activity
- Manual Task
- Receive Task
- Embedded Sub-Process
- Web Service Task
- Business Rule Task
创建多实例
多实例的创建其实就是上述xml
创建的过程,由于我这边大多配置都是固定的,没有单独添加多实例配置,有需要的可以根据需要添加配置设置,按配置动态写入元素,如下为我这边写入的代码:
// 更新多实例配置
const creatMultiInstance= () => {
const type = model.value.parallelType
if (isNil(type))
return
const isSerial = type === MultiInstanceTypes.SERIAL // 是否是串行
const moddle = toRaw(bpmnInstances.value?.moddle)
const modeling = toRaw(bpmnInstances.value?.modeling)
const element = toRaw(bpmnInstances.value?.bpmnElement)
let multiLoopInstance
let extensionElements
// isSequential: true是串行,false是并行
if (isSerial) {
// 串行实例
extensionElements = moddle.create('bpmn:ExtensionElements', {
values: [],
})
multiLoopInstance = moddle.create('bpmn:MultiInstanceLoopCharacteristics', {
isSequential: true,
collection: 'assigneeList',
elementVariable: 'assignee',
extensionElements,
})
}
else {
// 并行实例
const executionListener = moddle.create('flowable:ExecutionListener', {
class: 'cn.xxxx.JavaListener',
event: 'start',
})
extensionElements = moddle.create('bpmn:ExtensionElements', {
values: [executionListener],
})
const completionCondition = moddle.create('bpmn:FormalExpression', {
// eslint-disable-next-line no-template-curly-in-string
body: '${multiInstanceCompleteTask.accessCondition(execution)}',
})
multiLoopInstance = moddle.create('bpmn:MultiInstanceLoopCharacteristics', {
isSequential: false,
collection: 'assigneeList',
elementVariable: 'assignee',
completionCondition,
extensionElements,
})
}
modeling.updateProperties(element, {
loopCharacteristics: multiLoopInstance,
})
}