Bpmn.js自定义描述文件说明

简介: Bpmn.js自定义描述文件说明

前言


在使用 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: []
}


自定义说明文件demo


说明文件 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>


后记


由于工作需要(其实不是很需要),在公司项目的基础上开源了一个基于 bpmn-js + Vue 2.x + ElementUI 的一个流程编辑器 Bpmn Process Designer, 预览地址 MiyueFE blog, 欢迎 fork 和 star。


目录
相关文章
|
开发框架 前端开发 JavaScript
在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表
在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表
|
前端开发 JavaScript
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
|
存储 前端开发 JavaScript
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
230 0
|
存储 设计模式 监控
如何构建自定义 Node.js 事件发射器
如何构建自定义 Node.js 事件发射器
867 2
|
移动开发 JavaScript 前端开发
原生js如何获取dom元素的自定义属性
原生js如何获取dom元素的自定义属性
734 4
|
前端开发 微服务 API
微服务浪潮下的JSF革新:如何在分散式架构中构建统一而强大的Web界面
【8月更文挑战第31天】随着微服务架构的兴起,企业将应用拆分成小型、独立的服务以提高系统可维护性和可扩展性。本文探讨如何在微服务架构下构建和部署JavaServer Faces (JSF) 应用,通过RESTful服务实现前后端分离,提升灵活性和适应性。
342 1
|
JavaScript NoSQL Serverless
函数计算产品使用问题之如何创建一个自定义运行时并指定Node.js版本
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
416 8
|
前端开发 程序员
HTML+CSS+JavaScript制作动态七夕表白网页(含音乐+自定义文字)
一年一度的520情人节/七夕情人节/女朋友生日/程序员表白,是不是要给女朋友或者正在追求的妹子一点小惊喜呢,今天这篇博客就分享下前端代码如何实现HTML+CSS+JavaScript制作七夕表白网页(含音乐+自定义文字)。赶紧学会了,来制作属于我们程序员的浪漫吧!
699 0
HTML+CSS+JavaScript制作动态七夕表白网页(含音乐+自定义文字)
|
JavaScript
Vue.js中实现自定义组件的双向绑定
Vue.js中实现自定义组件的双向绑定