更多ruoyi-nbcio功能请看演示系统
gitee源代码地址
前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio
演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/
更多nbcio-boot功能请看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://218.75.87.38:9888
在BpmnJS 相关图形操作的属性更新上,经常会用到上面的属性更新函数,具体什么区别呢
1、updateProperties 说明与执行过程
该方法依赖UpdatePropertiesHandler 模块执行,可以看做是继承的commandHandler(之所以是看做,是因为 CommandHandler 是一个 抽象类,而 updatePropertiesHandler 实现了 CommandHanlder 类定义的所有重要方法,但是没有明显的 extends 关系)
该模块依赖 elementRegistry, moddle, translate, modeling, textRenderer 几大模块。
在属性更新的执行(execute)过程中,会校验 element 参数是否传递,并且获取到element 原来的 “所有” “与传入的新 properties 对象 key 一致的” Properties 属性组成的对象。
然后,会进行以下 updateModdleProperties 无法实现的处理:
- 如果新的 properties 对象中有 id 属性且与原 id 不一致,会更新 id
- 如果新的 properties 对象中有 default 字段,则会更新相关的连线(也就是“流”)的显示样式和对应属性
- 如有新的 properties 对象中有 DI 字段,也会更新元素的图形元素相关属性
- 最后更新元素的 businessObject 上与 新 properties 对象中的同名属性
需要注意的是,这两个 API 的更新方式都类似 Object.assign(oldProperties, newProperties) ,即 只要第一层属性名相同,就会以新的属性配置覆盖原始的属性配置,所以像更新某个数组属性的某一项时,记得保留其他的属性元素。
2、updateModdleProperties 说明与执行过程
该方法依赖UpdateModdlePropertiesHandler 模块执行,该模块与UpdatePropertiesHandler 一样也可以看做是commandHandler 的实现类
该模块只依赖 elementRegistry 模块。
当然这个方法是 专门用来更新元素中指定的某项业务属性,所以执行过程十分简单:
- 首先获取 元素的数据对象绑定,当然这个内容暂时我还没有碰到有同学使用哈
- 然后是获取 指定的 ModdleElement 中与传入的 Properties 对象 key 一致的属性组成的对象(updateProperties 方法也有这一步,主要是为了放在 EventBus 的上下文中给同名订阅事件使用)
- 然后就是更新指定 ModdleElement 中的 properties 指定属性,这里的属性更新十分粗暴,可以给大家看看源码。
function setModdleProperties(moddleElement, properties) {
forEach(properties, function(value, key) {
moddleElement.set(key, value);
});
}
3、判断属性更新方式
通过上面的两个方法的更新过程来看,除了以下情况外都可以使用 updateModdleProperties:
- 更新元素 Id 和 name
- 更新默认默认流转路径(也就是 shape 的 default 属性)
- 更新元素 DI
那么更新元素属性的 API 确定了,怎么确定如何去更新呢?就像更新更新元素的监听器、扩展属性的时候怎么判断,这里我分成这些情况来说明吧:
- 使用 camunda、flowable、activiti 这些流程引擎且没有做其他自定义属性的时候,可以通过后端或者官方的设计器设计好相应的 XML 之后导入到我们的项目中打印相关元素、查看属性结构
- 只有对应的 JSON Schema 文件,需要自己解析的时候
- 需要根据已有的 xml 和后端流程引擎的需求来定义我们的 JSON Schema 文件的时候
4、更新多实例选择项目的更新例子
const changeMultiLoopType = () => { // 取消多实例配置 if (multiLoopType.value === "Null") { bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { loopCharacteristics: null, assignee: null }); return; } multiLoopInstance.value = bpmnInstances().moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: isSequential.value }); // 更新多实例配置 bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { loopCharacteristics: toRaw(multiLoopInstance.value), assignee: '${assignee}' }); // 完成条件 let completionCondition = null; // 会签 if (multiLoopType.value === "SequentialMultiInstance") { completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances >= nrOfInstances}" }); } // 或签 if (multiLoopType.value === "ParallelMultiInstance") { completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances > 0}" }); } // 自定义会签 if (multiLoopType.value === "CustomMultiInstance") { completionCondition = bpmnInstances().moddle.create("bpmn:FormalExpression", { body: CustomCompletionCondition.value }); } // 更新模块属性信息 bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnElement.value), multiLoopInstance.value, { collection: '${multiInstanceHandler.getUserNames(execution)}', elementVariable: 'assignee', completionCondition }); }
4、效果图如下: