引言
在任何行业和企业中,一定存在着各式各样的流程,请假流程、报销流程、入职流程、离职流程、出差流程、合同审批流程、出入库流程等。所有人都需要按照规定的流程办事,如果流程比较简单我们可以通过画草图让大家理解。但当业务过于复杂时,如果没有一个业务流程图的规范,恐怕很难让人和机器看懂。为了让全球各种业务流程图能统一,就出现了BPMN(Business Process Model and Notation)标准,该标准已经成为了ISO标准之一。BPMN的主要目标是提供一些被所有业务用户容易理解的符号,从创建流程轮廓的业务分析到这些流程的实现,直到最终用户的管理监控。
BPMN2.0 BPMN2.0即BPMN规范的2.0版本,当前版本是比较稳定的一个版本。允许在BPMN的图形和元素中添加精确的技术细节,同时制定BPMN元素的执行语法。通过使用XML语言来指定业务流程的可执行语法,BPMN规范已经演变为业务流程的语言,可以执行在任何兼容BPMN2.0的流程引擎中,同时依然可以使用强大的图形注解。 BPMN2.0相对于BPMN1.0最大的区别是定义、规范了流程引擎的执行语义和格式,利用标准的图元描述真实的业务发生过程,保证相同的流程在不同的流程引擎中得到一致的执行结果。在BPMN2.0的这套标准中,组件主要分为四类:活动、网关、事件、辅助。 1、活动 ACTIVITY 活动相当于实体,可以说流程图的实体模型定义主要就是由活动组成的。组件如下图所示: 任务:最常用的活动就是任务。为了区分各种类型的任务,通常会在任务组件中,加入图标用以说明。 子流程:当流程过于复杂,就需要对流程图进行抽象。这样可以将细枝末节并相对独立的部分抽取到一个单独的流程里,在总体流程中再进行引入。 调用活动:在多数情况下,一个活动应该在多个流程图中都可以复用。BPMN为此提供了调用活动的构造。当一个全局的活动或子流程被调用时候,用粗边框进行表示。 事件子流程:与普通流程不同,事件子流程不是序列流触发的,而是由程序执行期间,消息流所触发的事件而设计的流程。 事务:和数据库里的事务概念一样,一项事务可以全部执行,也可以全部不执行。如果出现问题,则必须回滚事务。 2、网关 GATEWAY 网关相当于业务处理组件,活动(实体)只是来说明有什么,网关则可以通过与活动的连线来定义其规则。组件如下图所示: 排他网关:按照所有出口顺序流定义的顺序对它们进行计算,选择第一个条件计算为true的顺序流(当没有设置条件时,认为顺序流为true)继续流程。 并行网关:用来切分或同步相关的进入或外出顺序流。 包容网关:可以看做排他网关与并行网关的组合,选择或合并一条或多条路径。 事件网关:基于事件的网关,该网关不基于数据进行路由,而是根据接下来发生的事件进行路由。 复杂网关:允许根据特定业务场景的需要,自定义路径拆分和收回算法。 3、事件 EVENT 事件通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。三种主要类型的事件: 开始事件:表示一个流程的开始。 中间事件:发生在开始和结束事件之间,影响处理的流程。比如定时器事件、触发事件、传播事件等。中间事件既可以抛出也可以捕获。 结束事件:表示该流程结束。 4、辅助 AUXILIARY 为了让复杂的业务更加清晰的表达,BPMN也提出了一些辅助组件的使用。注意:这些辅助组件只是为了更好的表达业务模型,并不是必须的。 连接对象:将流对象连接起来形成一个业务流程的基本结构,包括顺序流、消息流、关联等。 注释与组:为了流程图做一些补充说明,不会影响执行语义。 数据存储:一个显示活动是如何需要或产生数据的,它们通过关联与活动连接起来。 泳道:对主要的建模元素进行分组,将活动划分到不同的可视化类别中来描述由不同的参与者的责任与职责。
BPMNJS bpmn.js是一个BPMN2.0渲染工具包和web建模器。它使用JavaScript编写,在不需要后端服务器支持的前提下向现代浏览器内嵌入BPMN2.0流程图。简单来说, 就是能使用前端来画流程图。 1、基本使用 BASIC CDN引入 npm安装 Vue中使用bpmn.js 2、自定义 CUSTOMIZE 先来看一下使用bpmn.js画图都有哪些内容: 图片来源于网络 那么在实际应用场景中,我们可以自定义哪些内容呢? 自定义Palette(左侧工具栏) 在默认的Palette基础上修改或新增新的项 1) 首先定义核心代码CustomPalette.js: 2) 定义完CustomPalette.js之后, 我们需要在其同级的index.js中将它导出: 3) 同时要在页面中使用它: 实现的效果如下图: 图片来源于网络 完全自定义Palette 需要重写BpmnModeler这个类,实现自己独有的一套modeler。 1) 编写核心代码CustomPalette.js: 2) 将自定义的Palette导出: 3) 最重要的一步, 编写CustomModeler: 4) 将原本通过BpmnModeler创建的对象改为通过自定义的CustomModeler来创建: 实现的效果如下图: 图片来源于网络 自定义Renderer(画布上的图形) 原理:编写核心代码customRender.js,直接修改原型链中的drawShape方法就可以了。然后在customModeler/custom/index.js中将其导出。代码类似自定义Palette,省略。 图片来源于网络 自定义ContextPad(小弹窗) 原理:定义一个ContextPadProvider类, 然后引入一些我们后面要用到的方法或者属性。通过$inject注入进来。重写原型链上的getContextPadEntries方法。代码类似自定义Palette,省略。 实现效果如下: 图片来源于网络
<script src=\"https://unpkg.com/bpmn-js@6.0.2/dist/bpmn-viewer.development.js\"></script>
npm i bpmn-js --save-D
<template>
<div class=\"containers\">
<div ref=\"bpmnRef\" class=\"bpmnRef\" />
</div>
</template>
<script>
// 引入相关的依赖
import BpmnModeler from \'bpmn-js/lib/Modeler\';
import {
xmlStr
} from \'../mock/xmlStr\'; // 这里是直接引用了xml字符串
export default {
name: \'\',
components: {},
data() {
return {
// bpmn建模器
bpmnModeler: null
};
},
mounted() {
this.init();
},
methods: {
init() {
// 获取到属性ref为\"bpmnRef\"的dom节点
const bpmnRef = this.$refs.bpmnRef;
// 建模
this.bpmnModeler = new BpmnModeler({
container: bpmnRef
});
this.createNewDiagram();
},
createNewDiagram() {
// 将字符串转换成图显示出来
this.bpmnModeler.importXML(xmlStr, (err) => {
if (err) {
// console.error(err)
} else {
// 这里是成功之后的回调, 可以在这里做一系列事情
this.success();
}
});
},
success() {
// console.log(\'创建成功!\')
}
}
};
</script>
// CustomPalette.js
export default class CustomPalette {
constructor(bpmnFactory, create, elementFactory, palette, translate) {
this.bpmnFactory = bpmnFactory;
this.create = create;
this.elementFactory = elementFactory;
this.translate = translate;
palette.registerProvider(this);
}
getPaletteEntries(element) {
const {
bpmnFactory,
create,
elementFactory,
translate
} = this;
function createTask() {
return function(event) {
const businessObject = bpmnFactory.create(\'bpmn:Task\');
const shape = elementFactory.createShape({
type: \'bpmn:Task\',
businessObject
});
create.start(event, shape);
};
}
return {
\'create.custom-task\': {
group: \'model\',
className: \'icon-custom custom-task\',
title: translate(\'创建一个类型为custom-task的任务节点\'),
action: {
dragstart: createTask(),
click: createTask()
}
}
};
}
}
CustomPalette.$inject = [
\'bpmnFactory\',
\'create\',
\'elementFactory\',
\'palette\',
\'translate\'
];
// index.js
import CustomPalette from \'./CustomPalette\';
export default {
__init__: [\'customPalette\'],
customPalette: [\'type\', CustomPalette]
}
<!--custom-palette.vue-->
<script>
import BpmnModeler from \'bpmn-js/lib/Modeler\';
import propertiesProviderModule from \'bpmn-js-properties-panel/lib/provider/camunda\';
import customModule from \'./custom\';
this.bpmnModeler = new BpmnModeler({
additionalModules: [
// 左边工具栏以及节点
propertiesProviderModule,
// 自定义的节点
customModule
]
});
</script>
/**
* A palette that allows you to create BPMN _and_ custom elements.
*/
export default function PaletteProvider(palette, create, elementFactory, globalConnect) {
this.create = create;
this.elementFactory = elementFactory;
this.globalConnect = globalConnect;
palette.registerProvider(this);
}
PaletteProvider.$inject = [
\'palette\',
\'create\',
\'elementFactory\',
\'globalConnect\'
];
PaletteProvider.prototype.getPaletteEntries = function(element) { // 此方法和上面案例的一样
const {
create,
elementFactory
} = this;
function createTask() {
return function(event) {
const shape = elementFactory.createShape({
type: \'bpmn:Task\'
});
console.log(shape); // 只在拖动或者点击时触发
create.start(event, shape);
};
}
return {
\'create.custom-task\': {
group: \'model\',
className: \'icon-custom custom-task\',
title: \'创建一个类型为custom-task的任务节点\',
action: {
dragstart: createTask(),
click: createTask()
}
}
};
};
// index.js
import CustomPalette from \'./CustomPalette\';
export default {
__init__: [\'paletteProvider\'],
paletteProvider: [\'type\', CustomPalette]
};
// customModeler/index.js
import Modeler from \'bpmn-js/lib/Modeler\';
import inherits from \'inherits\';
import CustomModule from \'./custom\';
export default function CustomModeler(options) {
Modeler.call(this, options);
this._customElements = [];
}
inherits(CustomModeler, Modeler);
CustomModeler.prototype._modules = [].concat(
CustomModeler.prototype._modules, [
CustomModule
]
);
<!--custom-modeler.vue-->
<script>
import CustomModeler from \'./customModeler\';
this.bpmnModeler = new CustomModeler({ // 原本是用BpmnModeler
additionalModules: [] // 可以不用引用任何东西
});
</script>
总结 通过以上介绍,在业务场景中,如果需要用到前端来设计或显示流程图,我们可以使用BPMNJS。简单场景,可以直接使用。复杂场景,支持对操作栏、展示元素、弹窗等进行自定义操作。BPMNJS可以满足前端流程图相关的多种需求。
原创文章,作者:EBCloud,如若转载,请注明出处:https://www.sudun.com/ask/32493.html