bpmnjs Properties-panel拓展(ExtensionElements拓展篇)

news2025/1/21 5:54:55

接上文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:exectionListener
    return 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) => {
        // 按顺序给个id
        const id = element.id + '-executionListener-' + index;
        // 构建item
        return {
            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 }
                }
            });
        }

        // 构建exectionListener
        const newExecutionListener = createElement('activiti:executionListener', {
            name: nextId('ExecutionListener_'),
            event: 'start', // 这边其实可以改成下拉框
            delegateExpression: ''
        }, extensionElements, bpmnFactory);

        // 增加至extensionElements
        commands.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:ExecutionListener
      if(is(element, 'bpmn:ExclusiveGateway')){
        groups.push(createExtensionExclusiveGateway(element, injector, translate));
      }

// 构建extensionElement下的exectionListener
function createExtensionExclusiveGateway(element, injector, translate){
  // 构建group list
  const 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,感兴趣可以看一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/943238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vLLM 实战

引言 随着人工智能技术的飞速发展&#xff0c;以及今年以来 ChatGPT 的爆火&#xff0c;大语言模型 (Large Language Model, LLM) 受到越来越多的关注。 为了实现 LLM 部署时的推理优化&#xff0c;全球各地有众多团队做出了各种优化框架。本文以加州大学伯克利分校开发的 vLLM…

R语言之基础绘图

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 R语言 也可获取。 文章目录 1. 函数 plot( )2.直方图和密度曲线图3.条形图4. 饼图5. 箱线图和小提琴图6. 克利夫兰点图7. 导出图形小结 R 的基础绘图系…

大模型开发05:PDF 翻译工具开发实战

大模型开发实战05:PDF 翻译工具开发实战 PDF-Translator 机器翻译是最广泛和基础的 NLP 任务 PDF-Translator PDF 翻译器是一个使用 AI 大模型技术将英文 PDF 书籍翻译成中文的工具。这个工具使用了大型语言模型 (LLMs),如 ChatGLM 和 OpenAI 的 GPT-3 以及 GPT-3.5 Turbo 来…

【通用消息通知服务】0x4 - 目前进展 阶段复盘

【通用消息通知服务】0x4 - 阶段复盘 达成 基本的API已经写完✍️了(消息查看发送, 模板crud,终端crud,发送渠道crud,计划crud,计划执行查看)拆分server, executor, planner三个入口, 方便针对性水平扩展整体架构初步形成&#xff0c;通过队列实现了事件驱动模型和消息订阅发…

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【六】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【六】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…

Apache RocketMQ 5.0 消息进阶:如何支撑复杂的业务消息场景?

作者&#xff1a;隆基 一致性 首先来看 RocketMQ 的第一个特性-事务消息&#xff0c;事务消息是 RocketMQ 与一致性相关的特性&#xff0c;也是 RocketMQ 有别于其他消息队列的最具区分度的特性。 以大规模电商系统为例&#xff0c;付款成功后会在交易系统中订单数据库将订单…

三---开关稳压器

通过控制系统反馈&#xff0c;当电压上升时通过反馈降低&#xff0c;当电压下降时通过反馈升高&#xff1b;形成一个控制环路&#xff1b;控制电路&#xff1a;PWM&#xff08;脉宽调制&#xff09;&#xff0c;PFM&#xff08;频率控制方式&#xff09;&#xff0c;移相控制方…

2023开学季有哪些电容笔值得买?平价电容笔推荐

在日常生活中&#xff0c;这支电容笔的使用范围很广&#xff0c;不管是和电脑、IPAD、手机一起使用&#xff0c;都可以说是一种很好的办公工具。首先要弄清楚自己的需求&#xff0c;再根据自己的需求来挑选合适的商品。苹果的Pencil有一种独特的重力压感&#xff0c;让人在上面…

【MTK平台】根据kernel log分析wifi scan的时候流程

一 概要: 本文主要讲解根据kernel log分析下 当前路径下(vendor/mediatek/kernel_modules/connectivity/wlan/core/gen4m/)wifi scan的时候代码流程 二. Log分析: 先看Log: 2.1)在Framework层WifiManager.java 方法中,做了一个标记,可以精准的确认时间 这段log可以…

基于Qt5开发图形界面——WiringPi调用Linux单板电脑IO

Qt5——WiringPi Qt5WiringPi示例教程 Qt5 Qt是一种跨平台的应用程序开发框架。它被广泛应用于图形用户界面&#xff08;GUI&#xff09;开发&#xff0c;可以用于构建桌面应用程序、移动应用程序和嵌入式应用程序。Qt提供了丰富的功能和工具&#xff0c;使开发人员可以快速、高…

企业内部搭建wiki的意义大吗?到底有何价值体现?

内部Wiki也叫做企业Wiki&#xff0c;是员工可以存储、共享和协作创作的地方&#xff0c;将企业内部员工知识共享集中到一个地方&#xff0c;并且相关内容与其他团队成员协作完成&#xff0c;它可以包含企业内部的各种知识&#xff0c;从操作指南到培训手册&#xff0c;再到客户…

ipad有必要用手写笔吗?开学季实惠的电容笔推荐

iPad平板的机型经过了一次又一次的升级&#xff0c;增加了更多的功能&#xff0c;如今已有了与笔记本电脑匹敌的能力。而到了如今&#xff0c;科技的发展&#xff0c;iPad也从一个娱乐工具&#xff0c;变成了一个集学习、画画、办公于一体的强大工具。为了提高生产效率&#xf…

Linux内核学习(十二)—— 页高速缓存和页回写(基于Linux 2.6内核)

目录 一、缓存手段 二、Linux 页高速缓存 三、flusher 线程 Linux 内核实现了一个被叫做页高速缓存&#xff08;page cache&#xff09;的磁盘缓存&#xff0c;它主要用来减少对磁盘的 I/O 操作。它是通过把磁盘中的数据缓存到内存中&#xff0c;把对磁盘的访问变为对物理内…

比较器DATESHEET参数

失调电压的理解 Input Offset Voltage 理想情况下&#xff0c;如果运算放大器的两个输入电压完全相同&#xff0c;则输出应为0V。但运放内部两输入支路无法做到完全平衡&#xff0c;导致输出永远不会是0&#xff0c;具体见图1所示。此时保持放大器负输入端不变&#xff0c;而在…

火绒能一键修复所有dll缺失吗?教你快速修复dll文件

关于dll文件的缺少&#xff0c;其实大家应该都是不陌生的吧&#xff0c;毕竟只要是经常使用电脑的人&#xff0c;那么它就一定碰到过各种各样的dll文件缺失&#xff0c;因为很多程序都是需要dll文件来支撑的&#xff0c;如果dll文件丢失了&#xff0c;那么一些程序就会启动不了…

新版白话空间统计(27):从离散点到密度图

点的密度是点分析中一个很重要的方向&#xff0c;有大量的点数据的空间表达&#xff0c;基本上都是通过密度图来进行体现的&#xff0c;比如百度热力图&#xff1a; 又或者是交通车流量热力图&#xff1a; 空间点密度分析&#xff0c;把海量离散的点&#xff0c;变成高度抽象的…

Tableau可视化进阶实践-1

各类地图 符号地图特点 填充地图特点 多维地图特点 混合地图特点 符号地图 特点 符号化&#xff1a;符号地图以符号的形式表示信息&#xff0c;使用不同的符号来代表不同的地理要素或特定的地理信息。这种符号化的方式可以简化地理信息的表达&#xff0c;使人们更容易理解和识…

基于ssm+vue斗车车辆交易系统源码和论文

基于ssmvue斗车交易系统源码和论文082 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次…

一个程序员眼中的API调用(淘宝/天猫/1688/拼多多API)

在程序员眼中&#xff0c;API调用是一种重要的编程概念&#xff0c;它允许开发人员通过预先定义好的接口和规范&#xff0c;调用其他应用程序或服务的功能。API调用是现代软件开发中不可或缺的一部分&#xff0c;它使得开发人员能够快速构建出复杂的应用程序&#xff0c;同时避…

电子电路原理题目整理(1)

电子电路原理题目整理&#xff08;1&#xff09; 最近在学习《电子电路原理》&#xff0c;记录一下书后面试题目&#xff0c;答案为个人总结&#xff0c;欢迎讨论。 1.电压源和电流源的区别&#xff1f; 电压源在不同的负载电阻下可提供恒定的负载电压&#xff0c;而电流源对于…