由于工作需要(其实不是很需要),在公司项目的基础上开源了一个基于 bpmn-js + Vue 2.x + ElementUI 的一个流程编辑器 Bpmn Process Designer, 预览地址 MiyueFE blog, 欢迎 fork 和 star。
在使用 bpmn-js
绘制流程图时,可能会存在需要开发者自己定义属性或者元素的情况,为了保证符合官方定义,对官方文档进行了汉化说明。以下说明基于个人理解,可能与真实作用有出入,希望大家指出不正确或者意义不明的地方,我好加以改正,谢谢!
原文见
bpmn
官方仓库 bpmn-io/moddle 。
definitionJson = {
"name": "self",
"uri": "https://self",
"prefix": "se", // 前缀
"xml": {
"tagAlias": "lowerCase" // xml 标签转为小写驼峰
},
"types": [ // 自定义标签类型数组
{
// name: 自定义标签名,在xml中显示为 se:attrOne
"name": "AttrOne",
// isAbstract: 规定在实例文档中是否可以使用复杂类型。
// 如果该值为 true,则元素不能直接使用该复杂类型,而是必须使用从该复杂类型派生的复杂类型。
"isAbstract": true,
/**
* extends: Some meta-models require it to plug-in new properties that to certain existing model elements.
* This can be acomplished using the extends field
* 一些元模型要求它为某些现有模型元素插入新属性。可以使用扩展字段来完成
* 比如 camunda 中的 camunda:FormalExpression extends => bpmn:FormalExpression,
* 并且在camunda:FormalExpression 中声明的属性 Properties: { name: "resource", type: "String", isAttr: true }
* 则创建的连线条件 moddle.create("bpmn:FormalExpression") 可以设置新定义属性 resource
* 打印结果如下: businessObject: {
* $type: "bpmn:SequenceFlow"
* conditionExpression: {
* $type: "bpmn:FormalExpression"
* language: "123123"
* resource: "123123123"
* }
* }
*/
"extends": [], // 扩展选中的类型属性,每次创建数组内的元素实例时都会自动插入新的属性AttrOne
/**
* superClass: Types can inherit from one or more super types by specifying the superClass property.
* 指定向上继承所有超类的属性。
* 例如 camunda:FormalExpression extends
* => bpmn:FormalExpression superClass
* => bpmn:Expression superClass
* => bpmn:BaseElement
* 按照类型结构层级顺序,依次将属性添加到该类型上
* 如果继承其他自定义配置文件的属性(比如 b.json [ prefix: "b", types: [{ name: "TextB" }] ])
* 则当前文件的superClass必须写完整的带前缀的名称 superClass: [ "b:TextB" ]
* 如果要将该类型作为标签插入到xml中,继承的superClass超类中必须包含 BaseElement 或者 Element 类型
*/
"superClass": [
"Element"
],
// 自定义标签属性
"properties": [
{
// name: 属性名
"name": "name",
// type: 属性值类型,可以为任意基础类型或者其他自定义类型。
// 比如属性值需要设置为另一个自定义类型 AttrTwo时,则 "type": "AttrTwo"
"type": "String",
// isAttr: 作为标签属性,体现为<se:attrOne name="xxx"></se:attrOne>
"isAttr": true
// isBody: 属性值插入到标签内部,体现为<se:attrOne>xxx</se:attrOne>;
// 另外 isBody 为 true 时,name 只能设置为 value
// "isBody": false
// isMany: 属性值是否用数组保存,注意与其他配置的互斥:type不能为String、Number等简单类型,isAttr不能为true等等
// "isMany": true
// default: 默认值
// "default": "xxx"
// redefines: 重新定义从超类型继承的属性、重写名称、类型和限定符
// "redefines": String
// isReference: 是否通过其 id 属性引用另一个对象作为属性值,通常在任务节点/网关等设置默认路径时使用
// "isReference": false
// "xml": {
// serialize: 添加关于如何序列化的额外注释。支持的值:xsi -- 类型序列化为数据类型,而不是元素
// "serialize": "xsi:type"
// }
},
{
"name": "value",
"type": "Number",
"isAttr": "true",
"default": 2
}
]
},
{
"name": "AttrTwo",
"superClass": [
"Element"
],
"meta": {
"allowedIn": [ "*" ] // 允许进入哪些元素标签内
},
"properties": [
{
"name": "value",
"type": "String",
"isBody": true // 作为内容填充,体现为<se:attrOne>xxx</se:attrOne>
}
]
}
],
// The enumerations and associations properties are reserved for future use.
// 枚举和关联属性保留供将来使用。
enumerations: [],
associations: []
}
SelfDescriptor.json
{
"name": "self",
"uri": "https://self",
"prefix": "se",
"xml": {
"tagAlias": "lowerCase"
},
"types": [
{
"name": "AttrOne",
"superClass": [
"Element"
],
"properties": [
{
"name": "name",
"type": "String",
"isAttr": "true"
},
{
"name": "values",
"type": "AttrOneProp",
"isMany": true
}
]
},
{
"name": "AttrOneProp",
"superClass": [
"Element"
],
"meta": {
"allowedIn": [ "*" ]
},
"properties": [
{
"name": "propName",
"type": "String",
"isAttr": true
},
{
"name": "value",
"type": "String",
"isAttr": true
}
]
},
{
"name": "AttrTwo",
"superClass": [
"Element"
],
"meta": {
"allowedIn": [ "*" ]
},
"properties": [
{
"name": "value",
"type": "String",
"isBody": true
}
]
}
]
}
import $ from 'jquery';
import BpmnModeler from 'bpmn-js/lib/Modeler';
// 侧边栏
import propertiesPanelModule from 'bpmn-js-properties-panel';
// camunda 侧边栏内容构建器
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda';
// camunda 属性解析文件
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda.json';
// 自定义的属性解析文件
import SelfDescriptor from "./SelfDescriptor.json";
// 省略部分内容...
// 初始化 modeler
var bpmnModeler = new BpmnModeler({
container: canvas,
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
// 使用引入的属性解析文件
camunda: camundaModdleDescriptor,
self: SelfDescriptor
}
});
// 使用与创建自定义属性标签
bpmnModeler.on("element.click", function (event, eventObj) {
const moddle = bpmnModeler.get("moddle");
// 自定义属性1
const attrOne = moddle.create("se:AttrOne", { name: "testAttrOne", values: [] });
// 自定义属性子属性
const attrOneProp = moddle.create("se:AttrOneProp", {propName: "propName1", value: "propValue1"})
// 自定义属性2
const attrTwo = moddle.create("se:AttrTwo", { value: "testAttrTwo" })
// 原生属性Properties
const props = moddle.create("camunda:Properties", { values: [] });
// 原生属性Properties的子属性
const propItem = moddle.create("camunda:Property", { name: "原生子属性name", values: "原生子属性value" });
// 原生扩展属性数组
const extensions = moddle.create("bpmn:ExtensionElements", { values: [] })
// 开始节点插入原生属性
if (eventObj.element.type === "bpmn:StartEvent") {
props.values.push(propItem);
extensions.values.push(props);
}
// 任务节点插入多种属性
if (eventObj.element.type === "bpmn:Task") {
props.values.push(propItem, propItem);
attrOne.values.push(attrOneProp);
extensions.values.push(props, attrOne, attrTwo);
}
// root插入自定义属性
if (eventObj.element.type === "bpmn:Process") {
attrOne.values.push(attrOneProp, attrOneProp);
extensions.values.push(attrOne);
}
bpmnModeler.get("modeling").updateProperties(eventObj.element, {
extensionElements: extensions
});
})
只截取了流程相关的部分
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:extensionElements>
<se:attrOne name="testAttrOne">
<se:attrOneProp propName="propName1" value="propValue1" />
<se:attrOneProp propName="propName1" value="propValue1" />
</se:attrOne>
</bpmn2:extensionElements>
<bpmn2:startEvent id="StartEvent_1">
<bpmn2:extensionElements>
<camunda:properties>
<camunda:property name="原生子属性name" values="原生子属性value" />
</camunda:properties>
</bpmn2:extensionElements>
<bpmn2:outgoing>Flow_066c7c5</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:task id="Activity_0ghpzc3" name="1">
<bpmn2:extensionElements>
<camunda:properties>
<camunda:property name="原生子属性name" values="原生子属性value" />
<camunda:property name="原生子属性name" values="原生子属性value" />
</camunda:properties>
<se:attrOne name="testAttrOne">
<se:attrOneProp propName="propName1" value="propValue1" />
</se:attrOne>
<se:attrTwo>testAttrTwo</se:attrTwo>
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_066c7c5</bpmn2:incoming>
<bpmn2:outgoing>Flow_0qmpzc7</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="Flow_066c7c5" sourceRef="StartEvent_1" targetRef="Activity_0ghpzc3" />
<bpmn2:task id="Activity_1gm4zj6" name="2">
<bpmn2:extensionElements>
<camunda:properties>
<camunda:property name="原生子属性name" values="原生子属性value" />
<camunda:property name="原生子属性name" values="原生子属性value" />
</camunda:properties>
<se:attrOne name="testAttrOne">
<se:attrOneProp propName="propName1" value="propValue1" />
</se:attrOne>
<se:attrTwo>testAttrTwo</se:attrTwo>
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_0qmpzc7</bpmn2:incoming>
<bpmn2:outgoing>Flow_03hry06</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="Flow_0qmpzc7" sourceRef="Activity_0ghpzc3" targetRef="Activity_1gm4zj6" />
<bpmn2:task id="Activity_0ahhdt5" name="3">
<bpmn2:extensionElements>
<camunda:properties>
<camunda:property name="原生子属性name" values="原生子属性value" />
<camunda:property name="原生子属性name" values="原生子属性value" />
</camunda:properties>
<se:attrOne name="testAttrOne">
<se:attrOneProp propName="propName1" value="propValue1" />
</se:attrOne>
<se:attrTwo>testAttrTwo</se:attrTwo>
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_03hry06</bpmn2:incoming>
<bpmn2:outgoing>Flow_1h7pp7l</bpmn2:outgoing>
</bpmn2:task>
<bpmn2:sequenceFlow id="Flow_03hry06" sourceRef="Activity_1gm4zj6" targetRef="Activity_0ahhdt5" />
<bpmn2:endEvent id="Event_1eofx2i">
<bpmn2:incoming>Flow_1h7pp7l</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="Flow_1h7pp7l" sourceRef="Activity_0ahhdt5" targetRef="Event_1eofx2i" />
</bpmn2:process>
本文首发于“掘金”
作者:MiyueFE
链接:https://juejin.cn/post/6912331982701592590
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。