当前位置: 首页 > news >正文

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拓展&#xff08;属性设置篇&#xff09;&#xff0c;继续记录下第三个拓展需求的实现。 需求简述 在ExclusiveGateway标签的extensionElements标签中增加子标签<activiti:executionListener>子标签&#xff0c;可增加复数子标签。子标签…...

虚拟机的使用

首先需要安装VMware软件&#xff0c;这是虚拟机&#xff0c;在里面可以实现在windows的笔记本上运行包括&#xff0c;windows11和linux系统的开发和研究。 VMware是一种虚拟化技术&#xff0c;可以让你在一台物理计算机上运行多个操作系统和应用程序&#xff0c;而不需要重启或…...

CSS Flex布局

前言 Flex布局&#xff08;弹性盒子布局&#xff09; 是一种用于在容器中进行灵活和自适应布局的CSS布局模型。通过使用Flex布局&#xff0c;可以更方便地实现各种不同尺寸和比例的布局&#xff0c;使元素在容器内自动调整空间分配。 Flex-组成 Flex布局由以下几个主要组成部分…...

Virtual

虚拟接口可以用作编写操作系统和驱动程序独立测试的一种方式。任何连接到同一通道(来自同一Python进程)的VirtualBus实例都将相互接收消息。 如果消息应跨进程或主机边界发送,请考虑使用多播IP接口,并参考虚拟接口对不同虚拟接口进行比较和一般性讨论。 Example import …...

6、监测数据采集物联网应用开发步骤(5.2)

监测数据采集物联网应用开发步骤(5.1) 包含4个类数据库连接&#xff08;com.zxy.db_Self.ConnectionPool_Self.py&#xff09;、数据库操作类&#xff08;com.zxy.db_Self.Db_Common_Self.py&#xff09;、数据库管理类&#xff08;com.zxy.db_Self.DBManager_Self.py&#xf…...

解释 Git 的基本概念和使用方式

该文为AI自动生成&#xff0c;InsCode AI 创作助手 Git 是一种版本控制工具&#xff0c;用于跟踪代码或文件的更改历史记录。以下是 Git 的基本概念和使用方式&#xff1a; 仓库 (Repository)&#xff1a;仓库是一个存储项目代码和历史记录的地方&#xff0c;可以在本地或远程…...

不同ubuntu系统下的不同ros系统可以互相通讯吗

可以的,不同版本的Ubuntu系统和ROS版本的机器仍然可以实现ROS节点之间的通信。 主要的原因有:1. ROS节点间通信是通过ROS master实现的。不同机器上的ROS节点都可以连接到同一个ROS master,从而实现通信。 2. ROS消息系统可以兼容不同的ROS版本。即使节点使用的ROS版本不同,也…...

数学建模-模型详解(2)

微分模型 当谈到微分模型时&#xff0c;通常指的是使用微分方程来描述某个系统的动态行为。微分方程是描述变量之间变化率的数学方程。微分模型可以用于解决各种实际问题&#xff0c;例如物理学、工程学、生物学等领域。 微分模型可以分为两类&#xff1a;常微分方程和偏微分…...

IT运维:使用数据分析平台监控DELL服务器

概述 在企业日常运维中&#xff0c;我们有着大量的服务器设备&#xff0c;设备故障一般可以通过常用的监控软件实现自动告警&#xff0c;但如果在管理运维中我们要做的不仅仅是发现故障&#xff0c;处理硬件故障&#xff0c;我们还需要进一步的了解&#xff0c;今年一共出现了多…...

Spring Cloud Alibaba-Sentinel规则

1 流控规则 流量控制&#xff0c;其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标&#xff0c;当达到指定的阈值时 对流量进行控制&#xff0c;以避免被瞬时的流量高峰冲垮&#xff0c;从而保障应用的高可用性。 第1步: 点击簇点链路&#xff0c;我们就可以看到访…...

go http-proxy

我们这里主要讲使用HTTP&#xff0f;1.1协议中的CONNECT方法建立起来的隧道连接&#xff0c;实现的HTTP Proxy。这种代理的好处就是不用知道客户端请求的数据&#xff0c;只需要原封不动的转发就可以了&#xff0c;对于处理HTTPS的请求就非常方便了&#xff0c;不用解析他的内容…...

用变压器实现德-英语言翻译【01/8】:嵌入层

一、说明 本文是“用变压器实现德-英语言翻译”系列的第一篇文章。它引入了小规模的嵌入来建立感知系统。接下来是嵌入层的变压器使用。下面简要概述了每种方法&#xff0c;然后是德语到英语的翻译。 二、技术背景 嵌入层的目标是使模型能够详细了解单词、标记或其他输入之间的…...

【vue3.0中ref与reactive的区别及使用】

什么是ref与reactive ref与reactive都是Vue3.0中新增的API&#xff0c;用于响应式数据的处理。 1. ref ref是一个函数&#xff0c;可以用于将一个普通的数据类型转换成响应式数据。ref返回一个包含value属性的对象&#xff0c;通过修改value属性的值&#xff0c;可以触发组件…...

计算机竞赛 基于情感分析的网络舆情热点分析系统

文章目录 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&#xff0c;其中arr是一个指向int指针的指针&#xff0c;n是一个整数。代码的目的是创建一个包含n个大小为2的整数数组的二维数组。 首先&#xff0c;…...

React Diff算法原理

文章目录 前言Diff算法原理 前言 &#x1f449;点此&#xff08;想要了解Diff算法&#xff09; Diff算法原理 React Diff算法是React用于更新虚拟DOM树的一种算法。它通过比较新旧虚拟DOM树的差异&#xff0c;然后只对有差异的部分进行更新&#xff0c;从而提高性能。 Reac…...

查局域网所有占用IP

查局域网所有占用IP 按&#xff1a;winr 出现下面界面&#xff0c;在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段&#xff0c;下面192.168.20.%i即为你想要ping的网段&#xff0c;%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…...

【MySQL】引擎类型

与其他DBMS一样&#xff0c;MySQL有一个 具体管理和处理数据的内部引擎 。在使用create table语句时&#xff0c;该引擎具体创建表&#xff0c;而在使用select或进行其他数据库处理时&#xff0c;该引擎在内部处理你的请求。多数时候&#xff0c;引擎都隐藏在DBMS内&#xff0…...

springMVC之HttpMessageConverter

文章目录 前言一、RequestBody二、RequestEntity三、ResponseBody四、SpringMVC处理json五、SpringMVC处理ajax六、RestController注解七、ResponseEntity总结 前言 HttpMessageConverter&#xff0c;报文信息转换器&#xff0c;将请求报文转换为Java对象&#xff0c;或将Java…...

计算机网络aaaaaaa

差错检测 在一段时间内&#xff0c;传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate) 11111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...