flowable 设置自定义属性教程

news2024/10/7 18:32:12

概述

        由于工作需要给flowable工作流设计器添加自定义属性,以满足功能实现。所以这篇文章介绍下用flowable 开源的的flowable-ui 前端添加自定义属性,后端解析属性值的例子。

技术栈

序号技术点名称版本
1Flowable6.8.0

使用的是flowable6.8.0 版的代码

GitHub - flowable/flowable-engine at flowable-release-6.8.0icon-default.png?t=N7T8https://github.com/flowable/flowable-engine/tree/flowable-release-6.8.0然后依照下面链接启动flowable-ui项目

手把手教大家编译 flowable 源码-腾讯云开发者社区-腾讯云松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。----要说这个编译源码其实没什么技术含量,但是由于国内的网络问题,Spring 等各种常...icon-default.png?t=N7T8https://cloud.tencent.com/developer/article/2108059

添加flowable-ui前端属性

添加boolean 属性

找到flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-logic\src\main\resources\stencilset_bpmn.json 路径文件 这个json 就是设计器的所有内容,

\flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\i18n\zh-CN.json 文件是汉化文件

下面是stencilset_bpmn.json 的文件格式:

{
    "title": "BPMN 2.0标准工具",
    "namespace": "http://b3mn.org/stencilset/bpmn2.0#",
    "description": "BPMN process editor",
    "propertyPackages": [{
        "name": "overrideidpackage",
        "properties": [{
            "id": "overrideid",
            "type": "String",
            "title": "Id",
            "value": "",
            "description": "元素的唯一标识.",
            "popular": true
        }]
    }, {
        "name": "namepackage",
        "properties": [{
            "id": "name",
            "type": "String",
            "title": "名称",
            "value": "",
            "description": "BPMN元素的描述名称.",
            "popular": true,
            "refToView": "text_name"
        }]
    }],
    "stencils": [{
        "type": "node",
        "id": "UserTask",
        "title": "用户活动",
        "description": "分配给特定人的任务 ",
        "view": "此处代码已省略,请查看本书配套资源内容",
        "groups": ["活动列表"],
        "propertyPackages": ["overrideidpackage", "namepackage", 
            "documentationpackage", "asynchronousdefinitionpackage", 
            "exclusivedefinitionpackage", "executionlistenerspackage", 
            "multiinstance_typepackage", "multiinstance_cardinalitypackage", 
            "multiinstance_collectionpackage", "multiinstance_variablepackage", 
            "multiinstance_conditionpackage", "isforcompensationpackage", 
            "usertaskassignmentpackage", "formkeydefinitionpackage", 
            "formreferencepackage", "duedatedefinitionpackage", 
            "prioritydefinitionpackage", "formpropertiespackage", "tasklistenerspackage"],
        "hiddenPropertyPackages": [],
        "roles": ["Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all"]
    }]
}

从以上配置文件内容中可以看出,最顶层有五个元素:title,namespace,description,

propertyPackages和stencils,分别代表标题,命名空间,描述,属性集合,节点属性,其中

propertyPackages表示的是设计器下栏的各个属性。通过propertyPackages 可以设置属性的名称,样式,字段类型。

 

type 对应的是当前属性的类型,和flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\editor-app\configuration\properties.js

里面的内容一一对应

stencils.propertyPackages 的值可以表示哪些活动使用哪些属性。

第一步:添加允许催办属性

第二步:将允许催办属性添加到用户属性下

第三步:重启服务

就可以看到用户任务下有允许催办属性了。

添加下拉框样式属性

上面我们完成了通过设置type 为boolean,添加允许催办属性,那么string,text属性大家也都可以在properties.js 文件中看到,按需添加即可。

如果是添加下拉框属性,我们可以仿照多实例的下拉框属性实现。

第一步:在stencilset_bpmn.json 文件的propertyPackages 下添加下拉属性的内容

,{
      "name" : "usertaskovertimehandlertypepackage",
      "properties" : [{
        "id" :"overtimehandlertype",
        "type" : "fd-overtimehandlertype",
        "title" : "逾期处理方式",
        "value" : "0",
        "description" : "逾期处理方式",
        "popular" : true
      }]
    }

注意id 和type ,我们去properties.js 文件下添加该类

第二步:在properties.js 文件下添加类型

注意1:properties.js 文件下的自定义名称为: oryx-上面的id-上面的type

注意2:不要用驼峰格式命名。

第三步:定义html

这些步骤我都是抄多实例怎么实现的。

下面是html 的下拉框格式,ng-controller 是用的angular.js 语言 下面红框里的内容我们自己定义

第四步:定义js 文件 

在 flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\index.html 文件下设置自定义的js路径

下面图片是js的内容,注意除默认值外其他两个字段需要和第二步html 里的值保持一致。

第五步:重启服务

重启服务就可以看到flowable-ui 界面上出现下拉框的属性了。如果是其他样式的属性,可以借鉴flowable-ui  中相同的样式是如何实现的。

后端添加自定义属性解析处理类

第一步:定义UserTaskJsonConverter实现类

package org.flowable.ui.application.converter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.*;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.BpmnJsonConverterContext;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;

import java.util.List;
import java.util.Map;

/**
 * @author admin
 */
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {


    /**
     *  用户任务类型
     */
    public static final String ACTIVE_TYPE = "activetype";
    /**
     *  允许撤回
     */
    public static final String ALLOW_RECALL = "allowrecall";
    /**
     *  允许终止
     */
    public static final String ALLOW_STOP = "allowstop";
    /**
     *  允许跳过
     */
    public static final String ALLOW_SKIP = "allowskip";
    /**
     *  允许修改下一个节点参与者
     */
    public static final String ALLOW_UPDATE_NEXT_ONE = "allowupdatenextone";

    /**
     *  允许修改后续节点参与者
     */
    public static final String ALLOW_UPDATE_NEXT_ALL = "allowupdatenextall";
    /**
     *  允许上传附件
     */
    public static final String ALLOW_UPLOAD = "allowupload";
    /**
     *  工作期限(单位:天)
     */
    public static final String LIMIT_TIME = "limittime";
    /**
     *  逾期处理方式
     */
    public static final String OVER_TIME_HANDLER_TYPE = "overtimehandlertype";
    /**
     *  预警提醒(逾期前天数)
     */
    public static final String OVER_TIME_WARN_TIME = "overtimewarntime";
    /**
     *  预警提醒(逾期前天数)
     */
    public static final String CIRCULATION_WARN_TIME = "circulationwarntime";

    @Override
    protected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement, BpmnJsonConverterContext converterContext) {
        super.convertElementToJson(propertiesNode, baseElement, converterContext);
        UserTask userTask = (UserTask) baseElement;
        //解析
        Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();
        if(extensionElements != null && extensionElements.containsKey(ACTIVE_TYPE)){
            ExtensionElement e = extensionElements.get(ACTIVE_TYPE).get(0);
            setPropertyValue(ACTIVE_TYPE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_RECALL)){
            ExtensionElement e = extensionElements.get(ALLOW_RECALL).get(0);
            setPropertyValue(ALLOW_RECALL, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_STOP)){
            ExtensionElement e = extensionElements.get(ALLOW_STOP).get(0);
            setPropertyValue(ALLOW_STOP, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_SKIP)){
            ExtensionElement e = extensionElements.get(ALLOW_SKIP).get(0);
            setPropertyValue(ALLOW_SKIP, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ONE)){
            ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ONE).get(0);
            setPropertyValue(ALLOW_UPDATE_NEXT_ONE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ALL)){
            ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ALL).get(0);
            setPropertyValue(ALLOW_UPDATE_NEXT_ALL, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(ALLOW_UPLOAD)){
            ExtensionElement e = extensionElements.get(ALLOW_UPLOAD).get(0);
            setPropertyValue(ALLOW_UPLOAD, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(LIMIT_TIME)){
            ExtensionElement e = extensionElements.get(LIMIT_TIME).get(0);
            setPropertyValue(LIMIT_TIME, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(OVER_TIME_HANDLER_TYPE)){
            ExtensionElement e = extensionElements.get(OVER_TIME_HANDLER_TYPE).get(0);
            setPropertyValue(OVER_TIME_HANDLER_TYPE, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(OVER_TIME_WARN_TIME)){
            ExtensionElement e = extensionElements.get(OVER_TIME_WARN_TIME).get(0);
            setPropertyValue(OVER_TIME_WARN_TIME, e.getElementText(), propertiesNode);
        }
        if(extensionElements != null && extensionElements.containsKey(CIRCULATION_WARN_TIME)){
            ExtensionElement e = extensionElements.get(CIRCULATION_WARN_TIME).get(0);
            setPropertyValue(CIRCULATION_WARN_TIME, e.getElementText(), propertiesNode);
        }
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap, BpmnJsonConverterContext converterContext) {
        FlowElement flowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap, converterContext);
        UserTask userTask = (UserTask) flowElement;
        //解析自定义扩展属性
        this.addExtansionPropertiesElement(userTask,elementNode,ACTIVE_TYPE);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_RECALL);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_STOP);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_SKIP);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ONE);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ALL);
        this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPLOAD);
        this.addExtansionPropertiesElement(userTask,elementNode,LIMIT_TIME);
        this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_HANDLER_TYPE);
        this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_WARN_TIME);
        this.addExtansionPropertiesElement(userTask,elementNode,CIRCULATION_WARN_TIME);

        return userTask;
    }

    private void addExtansionPropertiesElement(UserTask userTask,  JsonNode elementNode, String name) {
        ExtensionElement extensionElement = new ExtensionElement();
        extensionElement.setName(name);
        //BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX
        extensionElement.setNamespacePrefix("model");
        extensionElement.setNamespace(BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE);
        String customProperties = getPropertyValueAsString(name, elementNode);
        extensionElement.setElementText(customProperties);
        userTask.addExtensionElement(extensionElement);
    }

    public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>
                                         convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends
            BaseBpmnJsonConverter>> convertersToJsonMap) {

        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>
                                             convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

    public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extends
            BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);
    }

}

第二步:定义BpmnJsonConverter实现类

package org.flowable.ui.application.converter;

import org.flowable.editor.language.json.converter.BpmnJsonConverter;

/**
 * @author admin
 */

public class CustomBpmnJsonConverter extends BpmnJsonConverter {

    static {
        //这里可以加入所有自定义的属性内容

        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

}

第三步:解析json 转成Bpmn

package org.flowable.ui.application;


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.ui.application.converter.CustomBpmnJsonConverter;
import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class RunCustomJsonConverterDemo {

    @Test
    public void runCustomJsonConverterDemo() throws Exception {
        //读取Flowable Modeler保存的Json
        InputStream processModelJsonInputStream =
                getClass().getClassLoader().getResourceAsStream("model-json/model.json");
        ObjectMapper mapper = new ObjectMapper();
        JsonNode processJsonNode = mapper.readTree(processModelJsonInputStream);
        //获取流程模型的Json
        //使用自定义转换类由Json转换为BpmnModel对象
        BpmnJsonConverter bpmnJsonConverter = new CustomBpmnJsonConverter();
        BpmnModel bpmnModel = bpmnJsonConverter.convertToBpmnModel(processJsonNode);
        Process mainProcess = bpmnModel.getMainProcess();
        UserTask userTask = (UserTask) mainProcess.getFlowElement("sid-DA2AB9F9-3CB2-40C5-945B-95B6DADFA1E1");
        //查询用户任务对象并打印属性
        Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();
        List<ExtensionElement> allowurgingExtension = extensionElements.get("allowrecall");
        if (CollectionUtils.isNotEmpty(allowurgingExtension)) {
            log.info("扩展属性activetype值为:{}", allowurgingExtension.get(0).getElementText());
        }
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);// 转xml
        log.info("bpmnBytes:"+new String(bpmnBytes));

    }
}

其中model.json 是flowable-ui点击保存传过来的

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

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

相关文章

简述MinewSemi的GNSS模块引领体育与健康科技革新

体育与健康科技领域的创新一直在推动人们更健康、更活跃的生活方式。创新微公司的GNSS模块正成为这一变革的关键推动力。本文将深入研究MinewSemi的GNSS模块在体育和健康追踪领域的创新应用&#xff0c;探讨其如何帮助个体更全面地了解和改善自己的身体状态。 1. 个性化运动轨迹…

源码梳理(2)SpringMVC的执行流程及涉及到的相关组件

文章目录 1&#xff0c;Spring MVC核心组件DispatcherServlet1.1 DispatcherServlet的继承关系1.2 DispatcherServlet的doDispatch方法 2&#xff0c;核心组件HandlerMapping&#xff08;处理器映射器&#xff09;3&#xff0c;核心组件HandlerAdapter&#xff08;处理器适配器…

iOS pod sdk开发到发布,记录

本文章记录从开发sdk到发布cocopod的问题和流程,省的每次都忘还得重新查 1:pod lib create (sdk名称) 命令创建 工程结构,然后根据命令行提示进行选择. What platform do you want to use?? [ iOS / macOS ]。~》 iOS What language do you want to use?? [ Swift / Obj…

Jmeter高级使用

文章目录 JMeter之计数器JMeter之集合点JMeter之断言JMeter之动态关联后置处理器&#xff1a;正则表达式提取器 JMeter之分布式测试JMeter之组件执行顺序元件的作用域元件的执行顺序配置元件Http Cookie管理器 多协议接口的性能测试Debug采样器Http请求中文乱码的解决Post参数设…

循环神经网络RNN专题(01/6)

一、说明 RNN用于处理序列数据。在传统的神经网络模型中&#xff0c;是从输入层到隐含层再到输出层&#xff0c;层与层之间是全连接的&#xff0c;每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题却无能无力。例如&#xff0c;你要预测句子的下一个单词是什么&a…

Netty如何解决粘包以及半包问题,以及目前最常用的LengthFieldBasedFrameDecoder

粘包&#xff08;Sticky Packets&#xff09;和半包&#xff08;Half Packets&#xff09; 粘包&#xff08;Sticky Packets&#xff09;和半包&#xff08;Half Packets&#xff09;是在网络通信中常见的两种问题&#xff0c;特别是在基于流的传输协议&#xff08;如TCP&…

基于tidevice实现iOS app自动化使用详解

目录 1、IOS自动化工具概述 2、tidevice工具的原理和使用 2.1、tidevice的原理 2.2、tidevice实现的功能 2.3、tidevice的安装 2.4、tidevice的使用 2.4.1、设备管理 1、查看已连接的设备的列表 2、检测设备连接状态 3、等待设备连接&#xff0c;只要有就连接就结束监…

《区块链简易速速上手小册》第9章:区块链的法律与监管(2024 最新版)

文章目录 9.1 法律框架和挑战9.1.1 基础知识9.1.2 主要案例&#xff1a;加密货币的监管9.1.3 拓展案例 1&#xff1a;跨国数据隐私和合规性9.1.4 拓展案例 2&#xff1a;智能合约的法律挑战 9.2 区块链的合规性问题9.2.1 基础知识9.2.2 主要案例&#xff1a;加密货币交易所的合…

【读点论文】A Survey of Deep Learning Approaches for OCR and Document Understanding

A Survey of Deep Learning Approaches for OCR and Document Understanding Abstract 文档是许多领域(如法律、金融和技术等)中许多业务的核心部分。自动理解发票、合同和简历等文件是有利可图的&#xff0c;开辟了许多新的商业途径。通过深度学习的发展&#xff0c;自然语言…

cesium-场景出图场景截屏导出图片或pdf

cesium把当前的场景截图&#xff0c;下载图片或pdf 安装 npm install canvas2image --save npm i jspdf -S 如果安装的插件Canvas2Image不好用&#xff0c;可自建js Canvas2Image.js /*** covert canvas to image* and save the image file*/ const Canvas2Image (function…

elementUI中分开的时间日期选择组件,控制日期的禁用

<el-date-picker v-model"query.startTime" type"datetime" :picker-options"startPickerOptions" format"yyyy-MM-dd HH时" popper-class"date-picker" placeholder"选择日期时间"></el-date-picker>…

【Mysql】数据库架构学习合集

目录 1. Mysql整体架构1-1. 连接层1-2. 服务层1-3. 存储引擎层1-4. 文件系统层 2. 一条sql语句的执行过程2-1. 数据库连接池的作用2-2. 查询sql的执行过程2-1. 写sql的执行过程 1. Mysql整体架构 客户端&#xff1a; 由各种语言编写的程序&#xff0c;负责与Mysql服务端进行网…

[C#][opencvsharp]opencvsharp sift和surf特征点匹配

SIFT特征和SURF特征比较 SIFT特征基本介绍 SIFT(Scale-Invariant Feature Transform)特征检测关键特征&#xff1a; 建立尺度空间&#xff0c;寻找极值关键点定位&#xff08;寻找关键点准确位置与删除弱边缘&#xff09;关键点方向指定关键点描述子 建立尺度空间&#xff0…

python爬虫实战——获取酷我音乐数据

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: 版 本&#xff1a; python 3.8 编辑器&#xff1a;pycharm 2022.3.2 模块使用: requests >>> pip install requests 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 pip install…

【数据分享】1929-2023年全球站点的逐日最低气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01; 之前我们分享过1929-2023年全球气象站…

【云原生之kubernetes系列】--污点与容忍

污点与容忍 污点&#xff08;taints)&#xff1a;用于node节点排斥Pod调度&#xff0c;与亲和效果相反&#xff0c;即taint的node排斥Pod的创建容忍&#xff08;toleration)&#xff1a;用于Pod容忍Node节点的污点信息&#xff0c;即node节点有污点&#xff0c;也将新的pod创建…

GM8775C——DSI 转双通道 LVDS 发送器

1 产品概述 GM8775C 型 DSI 转双通道 LVDS 发送器产品主要实现将 MIPI DSI 转单 / 双通道 LVDS 功能&#xff0c; MIPI 支持 1/2/3/4 通道可选&#xff0c;每通道最高支持 1Gbps 速率&#xff0c;最大支持 4Gbps 速率。 LVDS 时钟频率高达 154MHz &#xff…

数据解构+算法(第07篇):动态编程!黄袍加身!

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

【数据分享】1929-2023年全球站点的逐月最高气温数据(Shp\Excel\无需转发)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01; 之前我们分享过1929-2023年全球气象站…

vue如何使用vuedraggable实现不同面板之间的拖拽排序,拖拽复制功能?【vuedraggable】

vuedraggable官方文档链接使用说明https://www.itxst.com/vue-draggable/re7vfyfe.htmlhttps://www.itxst.com/vue-draggable/re7vfyfe.html 效果图&#xff1a; 使用vuedraggable拖动左边的字段和逻辑到右边形成不同的规则校验 <!-- ****--date 2024-02-01 11:34****-…