vue3:Table组件动态的字段(列)权限、显示隐藏和左侧固定
效果展示
根据后端接口返回,当前登录用户详情中的页面中el-table组件的显示隐藏等功能。根据菜单id查询该菜单下能后显示的列。
后端返回的数据类型:
接收到后端返回的数据后处理数据结构. Table组件文件
<!-- 自己封装的Table组件文件 -->
onMounted(()=>{
//判断页面传递过来的数据对象:PropTableS中keySrequest是否为true;为true则请求后端的table列数据,否则使用自己定义的。(因为还没有定义所有页面的 列字段权限。所有得区分开来,不然其他页面在后端中不存在数据,table显示都会是空的)if(props.PropTableS.keySrequest){tablekey()}
})onActivated(() => {
//如果不是第一次进入这个页面,可以直接拿之前第一次进入保存的数据.if(props.PropTableS.keySrequest && proxy.$router.currentRoute.value.meta.key){TabKys = proxy.$router.currentRoute.value.meta.key}
})//请求后端数据,处理数据格式
function tablekey(){proxy.$axios.get('/system/user/list_fields', {permission_id:proxy.$router.currentRoute.value.meta.id}).then((res) => {let keycopy = JSON.parse(JSON.stringify(TabKys))let list = {}res.data.map(item=>{list[item.code] = {title :item.name, //列名left_fixed:item.left_fixed == 1 ? true : false, //是否固定fixed:item.left_fixed == 1 ? 'left' : false, //默认固定左侧id:item.id, //字段idsort:item.sort, //排序status:item.status == 1 ? true : false, //显示/隐藏isshow:item.isshow, //也是显示/隐藏,这个可以在自定义的数据中传递过来,因为之前的页面都是用的isshow,后端用的是status,前面页面太多不想改了。width:keycopy[item.code].width, //自定义传递过来的列宽度type:keycopy[item.code].type, //自定义传递过来的列类型,如('text','selelct','input'等等)permission_id:proxy.$router.currentRoute.value.meta.id//提交给后端的菜单id。}})//TabKys :渲染el-table组件的列对象数据 list:处理后端数据.TabKys = list//此处理是将进入页面请求后的数据保存,可以避免切换页面,丢失当前页面的table列。出现问题的场景(进入页面A,table组件列正常显示,切换到页面B后,在回到页面A。页面A没有列的名称了。因为路由设置页页面记住缓存。)proxy.$router.options.routes[1].children.forEach(route=>{route.meta.id == proxy.$router.currentRoute.value.meta.id ? route.meta.key == undefined ? route.meta.key = TabKys : '' : ''})tablekeyindex.value++});
}
页面中定义的数据:
页面中定义的table数据let PropTableS = reactive({ tableStyle: { //table的csswidth: "99%",margin: "auto",},keySrequest:true, //是否需要后端数据渲染//自己定义的列的数据 keyS: proxy.$PublicAPI.SetTableCotentWidth({ //这不是一个完整列对象数据,因为其他值都在后端返回了。这里的意义就是可以自定义列的类型。后端中没有定义当前列类型字段,也可以不需要后端保存,可以自定义,danjuleixing: {type:'select' //类型:下拉widht:'120px' //定义的宽度 },status: {type:'select'},}),
});
Table组件中右侧定义设置的组件(小齿轮)
<template><div class="Drawer"><el-drawerz-index="12":modal="false":before-close="beforeClose"append-to="el-main"class="drawerBox"v-model="Props.DrawerObject.visible":close-on-click-modal="false":destroy-on-close="true":show-close="false"><template #header="{ close, titleId, titleClass }"><div class="deawerTitle"><span>表单固定设置</span><span><Icons @click="close" :theme="'outline'" :size="20" :is="'close'"/></span></div></template><div class="deawerScanner"><el-inputv-model="input2"@input="handelInput"class="deawerScanner_input"size="small"placeholder="搜索关键词":prefix-icon="Search"/></div><div><el-tabsv-model="TabactiveName"class="demo-tabs"@tab-click="handleTableActiveClick"><el-tab-pane label="固定列" name="0"></el-tab-pane><el-tab-pane label="隐藏/显示" name="1"></el-tab-pane></el-tabs></div><div class="deawerTop" :style="{ height: TopHeght + 'px' }"><div class="deawerTop_All"><el-checkbox@click="handelCheack"v-model="checked4"label="全部固定"/></div><div><FromDataref="From":key="formkey"@Drawer_switchChange="Drawer_switchChange"class="FromDataDom":fromlist="fromlist"style="":style="{ 'margin-top': '0px', height: domHeight + 'px' }"></FromData></div><div class="botton_but"><Buttonplain:title="'取消'"@click="ButtonClick('')":pattern="'centre'"/><Button:plain="fromlist.scannerIsPlain":type="'primary'":title="'保存'"@click="ButtonClick('save')":pattern="'centre'"/></div></div></el-drawer></div>
</template><script lang="ts" setup>
import {ref,reactive,onMounted,defineProps,watch,onActivated,getCurrentInstance,onBeforeUnmount,onUnmounted,
} from "vue";
import { Search } from "@element-plus/icons-vue";
import { FromData, Drawer, Icons, Button } from "@/components";
let Props = defineProps(["DrawerObject", "primarytablelist"]);
import { ElMessage, ElMessageBox } from "element-plus";
const primarytablelist = Props.primarytablelist;
const { proxy } = getCurrentInstance();
const From = ref(null);
let fromlist = reactive({});
let input2 = ref("");
let checked4 = ref(false);
let isEmit = ref(true);
let formkey = ref(0);
let TabactiveName = ref("0");
let domHeight = ref(0);
let TopHeght = ref(0);
onMounted(() => {GelTableTitleUpdate(Props.DrawerObject.TabKys);window.addEventListener("resize", resizeFun);setTimeout(() => {resizeFun();}, 1);});onUnmounted(() => {proxy.$bus.emit("addEvent", false);
});function resizeFun() {domHeight.value =document.querySelector(".drawerBox").offsetHeight - 41 - 39 - 54 - 84 - 50;TopHeght.value =document.querySelector(".drawerBox").offsetHeight - 41 - 39 - 64;
}function GelTableTitleUpdate(obj: object) {let index = 0;let objlength = 0;for (const key in obj) {if (key != "operate" && key != "selection" && key != "index") {objlength++;obj[key].type = "switch";obj[key].icon = "drag";if (obj[key].fixed) {index++;obj[key].value = true;} else if (obj[key].value == "" || obj[key].value == false) {delete obj[key].value;}} else if (key == "operate" || key == "selection" || key == "index") {delete obj[key];}}fromlist = {index: "2",labelwidth: 130,formInline: false,isInput: true,position: "left",component: "rigthoptins",listData: obj,newListData: JSON.parse(JSON.stringify(obj)),};handleTableActiveClick({props:{name:'0'}})proxy.$bus.emit("addEvent", true);index == objlength ? (checked4.value = true) : "";
}function ButtonClick(type: string) {let keys = Object.keys(fromlist.listData)let list = {permission_id:fromlist.listData[keys[0]].permission_id,details:[]}if (type === "save") {for (const key in fromlist.listData) {let aa ={'field_id':fromlist.listData[key].id,'status':fromlist.listData[key].status,'left_fixed':fromlist.listData[key].left_fixed}list.details.push(aa)}proxy.$axios.post('/system/user/list_set_fields', list).then((res) => {if(res.code == 200){ElMessage.success(res.message)proxy.$bus.emit('UpdataTablerowKeys')}else if(res.code == 500){ElMessage.error(res.message)}})}
}function beforeClose() {Props.DrawerObject.visible = false;proxy.$bus.emit("addEvent", false);
}proxy.$bus.on("UpdataRouterPath", (val: boolean) => {Props.DrawerObject.visible = val;
});function Drawer_switchChange(key:string,TableList:any
) {fromlist.listData[key][TabactiveName.value == '0' ? 'left_fixed' : 'status'] = TableList[key]Object.keys(TableList).length == Object.keys(fromlist.listData).length && Object.values(TableList).every(Boolean) ? checked4.value = true : checked4.value = false
}function handelCheack() {let bol = !checked4.valueFrom.value.getUpdataRigthOptions(bol);for (const key in fromlist.listData) {fromlist.listData[key][TabactiveName.value == '0' ? 'left_fixed' : 'status'] = From.value.TableList[key]}}let inputval = ref("");
function handelInput(value: string) {inputval.value = value;setTimeout(() => {aa(value);}, 1000);
}function aa(val: string) {if (inputval.value == val) {let list = JSON.parse(JSON.stringify(fromlist.newListData));for (const key in list) {if (val == "") {fromlist.listData = JSON.parse(JSON.stringify(fromlist.newListData));}if (list[key].title.indexOf(val) == -1) {delete list[key];}}fromlist.listData = list;formkey.value++;}
}function handleTableActiveClick(value: any) {TabactiveName.value = value.props.name;for (const key in fromlist.listData) {fromlist.listData[key].value = fromlist.listData[key][TabactiveName.value == '0' ? 'left_fixed' : 'status'] }checked4.value = Object.keys(fromlist.listData).every(item => fromlist.listData[item].value == true)formkey.value++;
}
</script><style lang="less" scoped>
::v-deep el-drawer {background: saddlebrown !important;
}
::v-deep .el-icon {height: none;
}::v-deep .drawerBox {.el-drawer__header {padding: 0px !important;margin-bottom: 0px !important;}.el-drawer__body {padding: 0px !important;}.el-input__wrapper {box-shadow: none !important;}.deawerScanner {border: none;width: 100%;padding: 0 9px;border-bottom: 1px solid #e8eaf2;height: 40px;.input__wrapper {box-shadow: none !important;border: none !important;}.deawerScanner_input {height: 39px !important;border: none !important;}}.elForm {max-height: none !important;}.FromDataDom {overflow: hidden;overflow-y: auto;scrollbar-width: thin; /* 设置滚动条为细条 */// scrollbar-color: #888 #f1f1f1; /* 设置滚动条和轨道的颜色 */}.deawerTop {width: 100%;height: 87%;padding: 0px 0px 0 12px;.deawerTop_All {height: 40px;display: flex;align-items: center;}}width: 244px !important;.deawerTitle {padding: 0px 15px !important;color: #5b6070 !important;font-size: 14px !important;width: 214px;height: 40px;display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #e8eaf2;}.botton_but {width: 83%;height: 84px;display: flex;justify-items: center;align-items: center;margin-left: 8%;.ButBox {display: contents;background: salmon;}}.bottonMax_but {position: fixed;bottom: 0;}
}::v-deep.elForm {padding: 0px !important;
}
::v-deep .el-drawer {height: 89%;top: 11% !important;bottom: 0 !important;
}// ::v-deep .drawerBox {
// position: absolute !important;
// top: 100 !important;
// right: 0 !important;
// bottom: 0 !important;
// z-index: 12;
// }::v-deep .drawerDiv {inset: 100% !important;position: absolute !important;top: 0 !important;right: 0 !important;bottom: 0 !important;
}
::v-deep .el-switch.is-checked .el-switch__core {background: var(--Click_Nav_FontColor) !important;
}
::v-deep .el-button--primary {background: var(--Click_Nav_FontColor) !important;
}::v-deep .el-form-item__label {display: block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}::v-deep .el-tabs__nav-wrap::after {height: 1px;
}::v-deep .el-tabs__nav {width: 100%;display: flex;justify-content: center;
}::v-deep .switchClass {display: flex;i {display: block;height: 32px;display: flex;justify-content: center;}
}
::v-deep .el-tabs__item:hover,
::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {color: var(--Click_Nav_FontColor) !important;
}
::v-deep .el-tabs__item.is-active {color: var(--Click_Nav_FontColor) !important;
}
::cv-deep .el-tabs__active-bar {background-color: var(--Click_Nav_FontColor) !important;
}
</style>
table组件
<template><div class="TableBox" id="TableBox"><div class="DateilsTitle" v-if="props.PropTableS.title">{{ props.PropTableS.title }}</div><div v-if="props.PropTableS.headerRemarks" class="headerRemarks">{{ props.PropTableS.headerRemarks }}</div><el-tablev-if="TabKys"class="singleTableRef"ref="singleTableRef":data="getTables()":key="tablekeyindex"><template v-for="(child, key, index) in TabKys"><!-- 存在显示隐藏标识的字段 控制显示列 evalRowShow--><el-table-columnv-if="props.PropTableS.keySrequest ? evalRowShow(child.status||child.isshow) : true"></el-table-column></template><!-- 小齿轮在右侧显示 --><template v-if="PropTableS.tables" class="aaaaaa"><el-table-column fixed="right" width="20px"><template #header><Icons@click="handelRightIcon(TabKys)":theme="'outline'":size="36":is="'config'"/></template></el-table-column></template></el-table><!-- 小齿轮组件 --><Drawerv-if="DrawerObject.visible":DrawerObject="DrawerObject":primarytablelist="TabKys"></Drawer></div>
</template><script setup lang="ts">onMounted(() => {//判断是否包含keySrequest ,否则去自定义传递过来的table数据对象if(props.PropTableS.keySrequest){tablekey()}
});onActivated(() => {//看看列信息是否在路由中有存起来,有值就是代表不是第一次进入该页面if(props.PropTableS.keySrequest && proxy.$router.currentRoute.value.meta.key){TabKys = proxy.$router.currentRoute.value.meta.key}
});//点击右侧设置按钮
function handelRightIcon(params: object) {DrawerObject.visible = true;DrawerObject.TabKys = JSON.parse(JSON.stringify(TabKys));
}
function evalRowShow(params:any){return eval(params);
}proxy.$bus.on('UpdataTablerowKeys',()=>{tablekey()})
function tablekey(){proxy.$axios.get('/system/user/list_fields', {permission_id:proxy.$router.currentRoute.value.meta.id}).then((res) => {let keycopy = JSON.parse(JSON.stringify(TabKys))let list = {}res.data.map(item=>{list[item.code] = {title :item.name,left_fixed:item.left_fixed == 1 ? true : false,fixed:item.left_fixed == 1 ? 'left' : false,id:item.id,sort:item.sort,status:item.status == 1 ? true : false,isshow:item.isshow,width:keycopy[item.code].width,type:keycopy[item.code].type,permission_id:proxy.$router.currentRoute.value.meta.id}})TabKys = list//进入页面将列值数据保存proxy.$router.options.routes[1].children.forEach(route=>{route.meta.id == proxy.$router.currentRoute.value.meta.id ? route.meta.key == undefined ? route.meta.key = TabKys : '' : ''})tablekeyindex.value++});
}
相关文章:

vue3:Table组件动态的字段(列)权限、显示隐藏和左侧固定
效果展示 根据后端接口返回,当前登录用户详情中的页面中el-table组件的显示隐藏等功能。根据菜单id查询该菜单下能后显示的列。 后端返回的数据类型: 接收到后端返回的数据后处理数据结构. Table组件文件 <!-- 自己封装的Table组件文件 --> onMounted(()>…...

pikachu靶场通关笔记13 XSS关卡09-XSS之href输出
目录 一、href 1、常见取值类型 2、使用示例 3、安全风险 二、源码分析 1、进入靶场 2、代码审计 3、渗透思路 三、渗透实战 1、注入payload1 2、注入payload2 3、注入payload3 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关)渗透集合ÿ…...

MCP客户端Client开发流程
1. uv工具入门使用指南 1.1 uv入门介绍 MCP开发要求借助uv进行虚拟环境创建和依赖管理。 uv 是一个Python 依赖管理工具,类似于pip 和 conda ,但它更快、更高效,并且可以更好地管理 Python 虚拟环境和依赖项。它的核心目标是 替代 pip 、…...

学习日记-day21-6.3
完成目标: 目录 知识点: 1.集合_哈希表存储过程说明 2.集合_哈希表源码查看 3.集合_哈希表无索引&哈希表有序无序详解 4.集合_TreeSet和TreeMap 5.集合_Hashtable和Vector&Vector源码分析 6.集合_Properties属性集 7.集合_集合嵌套 8.…...

C语言探索之旅:深入理解结构体的奥秘
目录 引言 一、什么是结构体? 二、结构体类型的声明和初始化 1、结构体的声明 2、结构体的初始化 3、结构体的特殊声明 4、结构体的自引用 5、结构体的重命名 三、结构体的内存对齐 1、对齐规则 2、为什么存在内存对齐? 3、修改默认对齐数 三…...
uniapp 开发企业微信小程序,如何区别生产环境和测试环境?来处理不同的服务请求
在 uniapp 开发企业微信小程序时,区分生产环境和测试环境是常见需求。以下是几种可靠的方法,帮助你根据环境处理不同的服务请求: 一、通过条件编译区分(推荐) 使用 uniapp 的 条件编译 语法,在代码中标记…...
Dockerfile常用指令介绍
Dockerfile常用指令介绍 Dockerfile是一个文本文件,用于定义Docker镜像的构建过程。下面介绍一些最常用的Dockerfile指令及其用法: 基础指令 FROM - 指定基础镜像 FROM python:3.9-slim这是Dockerfile的第一个指令,用于指定构建镜像的基础镜…...
Docker 容器化:核心技术原理与实践
哈喽,大家好,我是左手python! Docker 的基本概念与核心组件 Docker 是一个开源的容器化平台,能够将应用程序及其依赖项打包成一个容器,确保在任何环境中都能一致运行。Docker 的核心在于其容器化技术,这种…...
不确定性分析在LEAP能源-环境系统建模中的整合与应用
本内容突出与实例结合,紧密结合国家能源统计制度及《省级温室气体排放编制指南》,深入浅出地介绍针对不同级别研究对象时如何根据数据结构、可获取性、研究目的,构建合适的能源生产、转换、消费、温室气体排放(以碳排放为主&#…...

经典算法回顾之最小生成树
最小生成树(Minimum Spanning Tree,简称MST)是图论中的一个重要概念,主要用于解决加权无向图中连接所有顶点且总权重最小的树结构问题。本文对两种经典的算法即Prim算法和Kruskal算法进行回顾,并对后者的正确性给出简单…...

Ubuntu下实现nginx反向代理
1. 多个ngx实例安装 脚本已经在deepseek的指导下完成啦! deepseek写的脚本支持ubuntu/centos两种系统。 ins_prefix"/usr/local/" makefile_gen() {ngx$1 ngx_log_dir"/var/log/"$ngx"/"ngx_temp_path"/var/temp/"${ngx}…...

c++ QicsTable使用实例
效果图: #include <QicsTable.h> #include <QicsDataModelDefault.h> #include <QVBoxLayout> Demo1::Demo1(QWidget *parent) : QWidget(parent) { ui.setupUi(this); const int numRows 10; const int numCols 5; // create th…...

在WordPress上添加隐私政策页面
在如今的互联网时代,保护用户隐私已经成为每个网站管理员的责任。隐私政策不仅是法律要求,还能提高用户对网站的信任。本文将介绍两种常用方法,帮助你在WordPress上轻松创建并发布隐私政策页面。这些方法简单易行,符合中国用户的阅…...
二维 根据矩阵变换计算镜像旋转角度
在二维变换中,镜像(Reflection) 是一种特殊的线性变换,它会将图形对称地翻转到某个轴线或点。镜像的存在会显著影响圆弧变换后的参数(圆心、半径、起始角度),尤其是在角度方向和旋转方向的处理上…...
你工作中涉及的安全方面的测试有哪些怎么回答
在面试或工作总结中,回答 **“工作中涉及的安全测试”** 时,可以结合具体场景、测试方法和工具,突出你的技术广度和深度。以下是结构化回答建议: --- ### **1. 分类说明安全测试范围** #### **(1) Web 应用安全测试** - **OWASP…...

阿里云ACP云计算备考笔记 (3)——云服务器ECS
目录 第一章 整体概览 第二章 ECS简介 1、产品概念 2、ECS对比本地IDC 3、BGP机房优势 第三章 ECS实例 1、实例规格族 2、实例系列 3、应用场景推荐选型 4、实例状态 5、创建实例 ① 完成基础配置 ② 完成网络和安全组配置 ③ 完成管理配置和高级选项 ④ 确认下单…...
Eigen实现非线性最小二乘拟合 + Gauss-Newton算法
下面是使用 Eigen 实现的 非线性最小二乘拟合 Gauss-Newton 算法 的完整示例,拟合模型为: 拟合目标模型: y exp ( a x 2 b x c ) y \exp(a x^2 b x c) yexp(ax2bxc) 已知一组带噪声数据点 ( x i , y i ) (x_i, y_i) (xi,yi)&…...
区块链技术:原理、应用与发展趋势
区块链技术:原理、应用与发展趋势 引言 区块链作为一种去中心化的分布式账本技术,自2008年比特币白皮书发布以来,已经从简单的加密货币底层技术发展成为具有广泛应用前景的创新技术。区块链通过独特的数据结构和加密机制,实现了…...

从零开始:用Tkinter打造你的第一个Python桌面应用
目录 一、界面搭建:像搭积木一样组合控件 二、菜单系统:给应用装上“控制中枢” 三、事件驱动:让界面“活”起来 四、进阶技巧:打造专业级体验 五、部署发布:让作品触手可及 六、学习路径建议 在Python生态中&am…...

Web开发主流前后端框架总结
🖥 一、前端主流框架 前端框架的核心是提升用户界面开发效率,实现高交互性应用。当前三大主流框架各有侧重: React (Meta/Facebook) 核心特点:采用组件化架构与虚拟DOM技术(减少真实DOM操作,优化渲染性能&…...
Java Spring Boot 自定义注解详解与实践
目录 一、自定义注解的场景与优势1.1 场景1.2 优势 二、创建自定义注解2.1 定义注解2.2 创建注解处理器 三、使用自定义注解3.1 在业务方法上使用注解3.2 配置类加载注解 四、总结 在 Spring Boot 中,自定义注解为我们提供了一种灵活且强大的方式来简化开发、增强代…...

GlobalSign、DigiCert、Sectigo三种SSL安全证书有什么区别?
GlobalSign、DigiCert和Sectigo是三家知名的SSL证书颁发机构,其产品在安全性、功能、价格和适用场景上存在一定差异。选择SSL证书就像为你的网站挑选最合身的“安全盔甲”,核心是匹配你的实际需求,避免过度配置或防护不足。 一、核心特点对…...

力扣面试150题--二叉搜索树中第k小的元素
Day 58 题目描述 思路 直接采取中序遍历,不过我们将k参与到中序遍历中,遍历到第k个元素就结束 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* …...

SQL Server Agent 不可用怎么办?
在 SQL Server Management Studio (SSMS) 中,SQL Server Agent 通常位于对象资源管理器(Object Explorer)的树形结构中,作为 SQL Server 实例的子节点。以下是详细说明和可能的原因: 1. SQL Server Agent 的位置 默认路…...

css-塞贝尔曲线
文章目录 1、定义2、使用和解释 1、定义 cubic-bezier() 函数定义了一个贝塞尔曲线(Cubic Bezier)语法:cubic-bezier(x1,y1,x2,y2) 2、使用和解释 x1,y1,x2,y2,表示两个点的坐标P1(x1,y1),P2(x2,y2)将以一条直线放在范围只有 1 的坐标轴中,并…...
Java并发编程哲学系列汇总
文章目录 并发编程基础并发编程进阶并发编程实践 并发编程基础 Java并发编程基础小结 Java线程池知识点小结 详解JUC包下各种锁的使用 并发编程利器Java CAS原子类全解 深入理解Java中的final关键字 Java并发容器深入解析:HashMap与ArrayList线程安全问题及解…...

docker使用proxy拉取镜像
前提条件,宿主机可以访问docker hub 虚拟机上telnet 宿主机7890能正常访问 下面的才是关键,上面部分自己想办法~ 3. 编辑 /etc/docker/daemon.json {"proxies": {"http-proxy": "http://192.168.100.1:7890","ht…...

服务端定时器的学习(一)
一、定时器 1、定时器是什么? 定时器不仅存在于硬件领域,在软件层面(客户端、网页和服务端)也普遍应用,核心功能都是高效管理大量延时任务。不同应用场景下,其实现方式和使用方法有所差异。 2、定时器解…...
【前端】vue 防抖和节流
在 Vue.js 中,防抖(Debounce) 和 节流(Throttle) 是优化高频事件(如输入、滚动、点击)的核心技术,可显著提升性能与用户体验。以下是具体实现方法和最佳实践: ⏳ 一、防抖…...

Modbus转EtherNET IP网关开启节能改造新范式
在现代工业生产和能源管理中,无锡耐特森Modbus转EtherNET IP网关MCN-EN3001发挥着至关重要的作用。通过将传统的串行通信协议Modbus转换为基于以太网的EtherNET IP协议,这种网关设备不仅提高了数据传输的效率,而且为能源管理和控制系统的现代…...