bpmnjs Properties-panel拓展(ExtensionElements拓展篇)
接上文bpmnjs Properties-panel拓展(属性设置篇),继续记录下第三个拓展需求的实现。
需求简述
在ExclusiveGateway标签的extensionElements标签中增加子标签<activiti:executionListener>子标签,可增加复数子标签。子标签中包含event属性和delegateExpression属性可进行设置,并实现name属性的自动生成。event属性默认设为start。
那么最终的结构可表示为:
- exclusiveGateway- extensionElements- activiti:exectionListener (event, name, delegateExpression)
json属性设置
在activiti.json中增加要拓展的属性
{"name": "executionListener","superClass": [ "Element" ],"isMany": true,"properties": [{"name": "event","isAttr":true,"type": "String"},{"name": "delegateExpression","isAttr": true,"type": "String"}]}
补充executionListener的具体定义,主要的是superClass,设为Element,这样会被归到extensionElements里。
ExtensionExecutionListener组件
用来构建单条的executionListener。
ExtensionExecutionListener.js
import { TextFieldEntry } from '@bpmn-io/properties-panel';import { useService } from 'bpmn-js-properties-panel';// 构建list中的一层,包括event设置和delegateExpression设置
export default function ExtensionExecutionListener(props) {const {idPrefix,element,executionListener} = props;const entries = [{// idPrefix是外部传进来的element id,所以增加一个后缀来进行区分id: idPrefix + '-event',component: event,idPrefix,executionListener},{id: idPrefix + '-delegateExpression',component: delegateExpression,idPrefix,executionListener}];return entries;
}// 设置event属性
function event(props) {// 要注意的是executionListener,需要它来进行属性的修改 const {idPrefix,element,executionListener} = props;const commandStack = useService('commandStack');const translate = useService('translate');const debounce = useService('debounceInput');const setValue = (value) => {commandStack.execute('element.updateModdleProperties', {element,moddleElement: executionListener,properties: {event: value}});};const getValue = (executionListener) => {return executionListener.event;};// 也可使用html拼接return TextFieldEntry({element: executionListener,id: idPrefix + '-event',label: translate('event'),getValue,setValue,debounce});
}// 设置delegateExpression属性
function delegateExpression(props) {const {idPrefix,element,executionListener} = props;const commandStack = useService('commandStack');const translate = useService('translate');const debounce = useService('debounceInput');const setValue = (value) => {commandStack.execute('element.updateModdleProperties', {element,moddleElement: executionListener,properties: {delegateExpression: value}});};// exectionListener获取属性const getValue = (executionListener) => {return executionListener.delegateExpression;};// 也可使用html拼接return TextFieldEntry({element: executionListener,id: idPrefix + '-delegateExpression',label: translate('delegateExpression'),getValue,setValue,debounce});
}
主要是构建了包含event和delegateExpression的entries。需要注意的是,和前文bpmnjs Properties-panel拓展(属性设置篇)中不同,这里使用了commandStack命令栈去直接执行update,这种方法后面也会用到,好处是能将数个指令存到array中一起执行,比较方便写,不过错误提示会变成一坨,可能是我用的不对吧。
ExtensionExecutionListenerGroup
需要在ExtensionElements中塞进多个ExecutionListener,因此需要构建其组成的list。
import {getBusinessObject
} from 'bpmn-js/lib/util/ModelUtil';import { without } from 'min-dash';
import ExtensionExecutionListener from './ExtensionExecutionListener';import Ids from 'ids';function nextId(prefix) {const ids = new Ids([32, 32, 1]);return ids.nextPrefixed(prefix);
}function createElement(elementType, properties, parent, factory) {const element = factory.create(elementType, properties);if (parent) {element.$parent = parent;}return element;
}
首先是几个工具方法,getId随机构建不重复的id信息,createElement方法利用bpmnFactory来构建bpmnElement,是一种bpmnjs定义的结构体,用于后续插入整体的xml中。
// 获取element的extensionElment下的所有ExecutionListener
function getExtensionExecutionListeners(element) {const businessObject = getBusinessObject(element);// 不存在就算了if (!businessObject.extensionElements) {return null;}// 存在则使用filter找出所有的activiti:exectionListenerreturn businessObject.extensionElements.values.filter(function (e) {return e.$instanceOf("activiti:executionListener");});
}
工具方法,找executionListener。executionListener是在extensionElement下的,所以从那里利用filter找,返回是一个array或空。
// 关键方法,构建listener list
export default function ExtensionExecutionListenerGroup({ element, injector }) {// 防空const executionListeners = getExtensionExecutionListeners(element) || [];console.log(executionListeners);const bpmnFactory = injector.get('bpmnFactory'),commandStack = injector.get('commandStack');// 对list中的每个item进行构建const items = executionListeners.map((executionListener, index) => {// 按顺序给个idconst id = element.id + '-executionListener-' + index;// 构建itemreturn {id,label: executionListener.get('event') + '---' + executionListener.get('delegateExpression') || '',entries: ExtensionExecutionListener({idPrefix: id,element,executionListener}),autoFocusEntry: id + '-el',remove: removeFactory({ commandStack, element, executionListener })};});return {items,add: addFactory({ element, bpmnFactory, commandStack })};
}
主要是进行组件的构建。需要注意的是设置remove方法和add方法,分别是在可视化界面中进行组件增加和删除时调用的方法。
// 去除item时执行的方法,先获取extensionElement,之后进行without处理,最后更新
function removeFactory({ commandStack, element, executionListener }) {return function (event) {event.stopPropagation();const executionListeners = getExtensionExecutionListeners(element);if (!executionListeners) {return;}const businessObject = getBusinessObject(element);// 利用without将当前item对应的信息剔除console.log(executionListeners);const executionListenersAfter = without(executionListeners, executionListener);console.log(executionListenersAfter);// 更新剔除后的信息commandStack.execute('element.updateModdleProperties', {element,moddleElement: businessObject.get('extensionElements'),properties: {values: executionListenersAfter}});};
}
remove中主要工作就是先找到所有executionListener组成的array,之后通过without方法去除要删除的对象,最后进行update。
// 增加item时执行的方法
function addFactory({ element, bpmnFactory, commandStack }) {return function (event) {event.stopPropagation();// 存放处理命令,最后使用commandStack执行const commands = [];const businessObject = getBusinessObject(element);let extensionElements = businessObject.get('extensionElements');// extensionElements是bpmn自带的属性,不存在则先创建if (!extensionElements) {extensionElements = createElement('bpmn:ExtensionElements',{ values: [] },businessObject,bpmnFactory);commands.push({cmd: 'element.updateModdleProperties',context: {element,moddleElement: businessObject,properties: { extensionElements }}});}// 构建exectionListenerconst newExecutionListener = createElement('activiti:executionListener', {name: nextId('ExecutionListener_'),event: 'start', // 这边其实可以改成下拉框delegateExpression: ''}, extensionElements, bpmnFactory);// 增加至extensionElementscommands.push({cmd: 'element.updateModdleProperties',context: {element,moddleElement: extensionElements,properties: {// 使新增的显示在下面values: [newExecutionListener, ...extensionElements.get('values')]}}});commandStack.execute('properties-panel.multi-command-executor', commands);};
}
增加item主要分为三步,新增extensionElements,构建executionListener并给出随机id,update。
注册到可视化面板
在ActivitiPropertiesProvider.js中将组件进行注册
// 网关增加extensionElement:ExecutionListenerif(is(element, 'bpmn:ExclusiveGateway')){groups.push(createExtensionExclusiveGateway(element, injector, translate));}// 构建extensionElement下的exectionListener
function createExtensionExclusiveGateway(element, injector, translate){// 构建group listconst elGroup = {id: 'ExtensionExectionListener',label: translate('对应监听实现类设置'),component: ListGroup,...ExtensionExecutionListenerGroup({ element, injector })};return elGroup;
}
实现效果

list增删成员
xml成功修改
总结
实现了增加ExtensionElements中标签成员的需求,其实实现逻辑还是比较清晰的,构建组件,组件list,注册三步走。不过写的时候还是踩了不少坑,调了蛮久,还得多练啊。项目已上传至Github https://github.com/huiluczP/huiluczp-activiti-properties-panel-extension,感兴趣可以看一下。
相关文章:
bpmnjs Properties-panel拓展(ExtensionElements拓展篇)
接上文bpmnjs Properties-panel拓展(属性设置篇),继续记录下第三个拓展需求的实现。 需求简述 在ExclusiveGateway标签的extensionElements标签中增加子标签<activiti:executionListener>子标签,可增加复数子标签。子标签…...
虚拟机的使用
首先需要安装VMware软件,这是虚拟机,在里面可以实现在windows的笔记本上运行包括,windows11和linux系统的开发和研究。 VMware是一种虚拟化技术,可以让你在一台物理计算机上运行多个操作系统和应用程序,而不需要重启或…...
CSS Flex布局
前言 Flex布局(弹性盒子布局) 是一种用于在容器中进行灵活和自适应布局的CSS布局模型。通过使用Flex布局,可以更方便地实现各种不同尺寸和比例的布局,使元素在容器内自动调整空间分配。 Flex-组成 Flex布局由以下几个主要组成部分…...
Virtual
虚拟接口可以用作编写操作系统和驱动程序独立测试的一种方式。任何连接到同一通道(来自同一Python进程)的VirtualBus实例都将相互接收消息。 如果消息应跨进程或主机边界发送,请考虑使用多播IP接口,并参考虚拟接口对不同虚拟接口进行比较和一般性讨论。 Example import …...
6、监测数据采集物联网应用开发步骤(5.2)
监测数据采集物联网应用开发步骤(5.1) 包含4个类数据库连接(com.zxy.db_Self.ConnectionPool_Self.py)、数据库操作类(com.zxy.db_Self.Db_Common_Self.py)、数据库管理类(com.zxy.db_Self.DBManager_Self.py…...
解释 Git 的基本概念和使用方式
该文为AI自动生成,InsCode AI 创作助手 Git 是一种版本控制工具,用于跟踪代码或文件的更改历史记录。以下是 Git 的基本概念和使用方式: 仓库 (Repository):仓库是一个存储项目代码和历史记录的地方,可以在本地或远程…...
不同ubuntu系统下的不同ros系统可以互相通讯吗
可以的,不同版本的Ubuntu系统和ROS版本的机器仍然可以实现ROS节点之间的通信。 主要的原因有:1. ROS节点间通信是通过ROS master实现的。不同机器上的ROS节点都可以连接到同一个ROS master,从而实现通信。 2. ROS消息系统可以兼容不同的ROS版本。即使节点使用的ROS版本不同,也…...
数学建模-模型详解(2)
微分模型 当谈到微分模型时,通常指的是使用微分方程来描述某个系统的动态行为。微分方程是描述变量之间变化率的数学方程。微分模型可以用于解决各种实际问题,例如物理学、工程学、生物学等领域。 微分模型可以分为两类:常微分方程和偏微分…...
IT运维:使用数据分析平台监控DELL服务器
概述 在企业日常运维中,我们有着大量的服务器设备,设备故障一般可以通过常用的监控软件实现自动告警,但如果在管理运维中我们要做的不仅仅是发现故障,处理硬件故障,我们还需要进一步的了解,今年一共出现了多…...
Spring Cloud Alibaba-Sentinel规则
1 流控规则 流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时 对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 第1步: 点击簇点链路,我们就可以看到访…...
go http-proxy
我们这里主要讲使用HTTP/1.1协议中的CONNECT方法建立起来的隧道连接,实现的HTTP Proxy。这种代理的好处就是不用知道客户端请求的数据,只需要原封不动的转发就可以了,对于处理HTTPS的请求就非常方便了,不用解析他的内容…...
用变压器实现德-英语言翻译【01/8】:嵌入层
一、说明 本文是“用变压器实现德-英语言翻译”系列的第一篇文章。它引入了小规模的嵌入来建立感知系统。接下来是嵌入层的变压器使用。下面简要概述了每种方法,然后是德语到英语的翻译。 二、技术背景 嵌入层的目标是使模型能够详细了解单词、标记或其他输入之间的…...
【vue3.0中ref与reactive的区别及使用】
什么是ref与reactive ref与reactive都是Vue3.0中新增的API,用于响应式数据的处理。 1. ref ref是一个函数,可以用于将一个普通的数据类型转换成响应式数据。ref返回一个包含value属性的对象,通过修改value属性的值,可以触发组件…...
计算机竞赛 基于情感分析的网络舆情热点分析系统
文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…...
C++ 动态分配内存|动态数组
int** arr new int* [n]; for (int i 0; i < n; i) {arr[i] new int[2]; } 以上代码是用C动态分配了一个二维数组arr,其中arr是一个指向int指针的指针,n是一个整数。代码的目的是创建一个包含n个大小为2的整数数组的二维数组。 首先,…...
React Diff算法原理
文章目录 前言Diff算法原理 前言 👉点此(想要了解Diff算法) Diff算法原理 React Diff算法是React用于更新虚拟DOM树的一种算法。它通过比较新旧虚拟DOM树的差异,然后只对有差异的部分进行更新,从而提高性能。 Reac…...
查局域网所有占用IP
查局域网所有占用IP 按:winr 出现下面界面,在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段,下面192.168.20.%i即为你想要ping的网段,%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…...
【MySQL】引擎类型
与其他DBMS一样,MySQL有一个 具体管理和处理数据的内部引擎 。在使用create table语句时,该引擎具体创建表,而在使用select或进行其他数据库处理时,该引擎在内部处理你的请求。多数时候,引擎都隐藏在DBMS内࿰…...
springMVC之HttpMessageConverter
文章目录 前言一、RequestBody二、RequestEntity三、ResponseBody四、SpringMVC处理json五、SpringMVC处理ajax六、RestController注解七、ResponseEntity总结 前言 HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java…...
计算机网络aaaaaaa
差错检测 在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate) 11111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111…...
别光看论文!手把手带你复现CVPR 2025扩散模型加速新星:TinyFusion与DiG的代码实战
别光看论文!手把手带你复现CVPR 2025扩散模型加速新星:TinyFusion与DiG的代码实战 如果你已经厌倦了在arXiv上收藏一堆永远打不开第二次的论文链接,或是被那些充满数学符号却缺少可运行代码的"理论创新"搞得头大,那么这…...
嵌入式Linux实战:全志T3+vsftpd实现轻量级文件传输(含WinSCP连接教程)
嵌入式Linux实战:全志T3vsftpd实现轻量级文件传输(含WinSCP连接教程) 在物联网设备开发中,文件传输是一个看似简单却充满挑战的环节。当你的开发板是全志T3这样的资源受限平台时,如何在有限的存储和内存条件下搭建一个…...
【风电功率预测】到了2026年,企业为什么总输在“最后一公里”?从气象到功率再到电力交易,少赚的钱到底丢在哪
2026年,风电行业已经进入一个非常现实的新阶段。过去,很多企业讨论风电功率预测,核心问题还是“预报准不准”。而到了今天,这个问题虽然仍然重要,却已经不是决定收益高低的唯一变量。真正拉开差距的,是企业…...
在国产麒麟V10系统上,用kubeadm一步步搭建3个master节点的k8s高可用集群(含haproxy+keepalived配置)
国产麒麟V10系统上构建高可用Kubernetes集群实战指南 在信息技术自主可控的大背景下,国产操作系统正逐步成为企业级基础设施的重要选择。本文将详细介绍如何在麒麟V10(Kylin V10)操作系统上,从零开始搭建一个包含3个Master节点的高…...
MedGemma-X部署教程:一行命令启动,开启自然语言交互的影像分析
MedGemma-X部署教程:一行命令启动,开启自然语言交互的影像分析 1. 为什么选择MedGemma-X? 在医疗影像分析领域,传统CAD系统往往只能提供简单的二分类结果(如"正常/异常"),而MedGemm…...
终极解决方案:Calibre中文路径插件让书库管理回归本真
终极解决方案:Calibre中文路径插件让书库管理回归本真 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文(中文)命名 项目地址: h…...
AI系统-20AI芯片ISP视觉系统介绍
人有五感:眼睛、耳朵、鼻子、舌头和皮肤。 这些器官中的专门细胞和组织会接收原始刺激,并将其转化为神经系统可以使用的信号。 神经将信号传递到大脑,大脑将其解释为影像(视觉)、声音(听觉)、气…...
Dify工作流集成StructBERT:构建自定义文本智能处理应用
Dify工作流集成StructBERT:构建自定义文本智能处理应用 最近在做一个智能客服系统的升级项目,客户那边提了个挺实际的需求:每天有大量工单进来,希望系统能先自动判断一下问题类型,比如是“账号问题”、“支付故障”还…...
DriverStore Explorer完全指南:免费Windows驱动管理终极教程
DriverStore Explorer完全指南:免费Windows驱动管理终极教程 【免费下载链接】DriverStoreExplorer Driver Store Explorer [RAPR] 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer DriverStore Explorer是一款功能强大的Windows驱动程序管…...
Agent能为中小企业降本增效吗?深度拆解AI Agent在企业智能自动化的落地路径
在2026年这一关键的时间节点上,AI Agent能否为中小企业实现实质性的降本增效,已经从一个理论命题转变为大规模的实践成果。随着大模型技术的深度演进,AI Agent不再仅仅是简单的对话机器人,而是进化为具备自主规划、决策与执行能力…...
