# 8Multi协议设备接入技术方案 ## 一、项目背景 在现有8ADPRO设备接入系统的基础上,新增8Multi协议设备的接入支持。需要保持原有8ADPRO协议功能完全不受影响,通过扩展现有架构实现新协议的兼容。 ## 二、协议对比分析 ### 2.1 原8ADPRO协议格式 ``` +YAV:设备号,温度,电流,计数1,计数2,模拟1,模拟2,模拟3,模拟4,模拟5,模拟6,模拟7,数字1,数字2,数字3,数字4,数字5,数字6,EEFF ``` - **字段数量**: 19个字段 - **特点**: 简单直接,所有值都是实际物理量 ### 2.2 新8Multi协议格式 ``` +YAV:id,电流1,电流2,质量1,质量2,温度,湿度,工作停机故障清零,频率1,计数1,频率2,计数2,供电报警软启动停止,从机数据1,从机数据2,触摸屏,EEFF ``` **C格式**: `+YAV:%d,%d,%d,%d,%d,%.1f,%.1f,%d,%d,%d,%d,%d,%d,%d,%d,0,EEFF` - **字段数量**: 16个字段(不含帧头+YAV和帧尾EEFF) - **特点**: - 包含设备ID字段(g_tDevParam.Address) - 电流1/2:AI1/AI2,范围0-20A,需量程转换(0-65535映射) - 质量1/2:AI3/AI4,需量程转换(0-65535映射) - 温湿度:保留1位小数的实际值 - 4路DI复合状态(工作/停机/故障/清零) - 2路频率+计数 - 2路继电器+2路DO复合状态(供电/报警/软启动/停止) - 485从机数据2路 - 触摸屏数据(固定发送0) ### 2.3 关键差异点 | 项目 | 8ADPRO | 8Multi | |------|--------|--------| | 设备识别 | 第1字段:设备号 | 第1字段:设备ID | | 电流采集 | 1路电流(实际值) | 2路电流(需量程校准) | | 质量采集 | 无 | 2路质量(需量程校准) | | 温湿度 | 仅温度 | 温度+湿度 | | 状态位 | 6个独立数字量 | 4个复合状态字段(位运算) | | 计数器 | 2路计数 | 2路频率+计数 | | 状态上传 | 无 | 2路继电器+2路DO状态 | | 扩展功能 | 无 | 485从机+触摸屏 | **说明**:8Multi协议的继电器和DO字段为下位机上传的状态,不涉及下发控制功能。 ## 三、数据库设计方案 ### 3.1 设备主表扩展 (device) **新增字段**: ```sql ALTER TABLE `device` ADD COLUMN `protocol_type` ENUM('8ADPRO', '8MULTI') NOT NULL DEFAULT '8ADPRO' COMMENT '协议类型(8ADPRO=原协议,8MULTI=新协议),根据device_no自动判断:>200为8MULTI,<=200为8ADPRO' AFTER `device_code`, ADD COLUMN `current1_range_start` DECIMAL(10,3) DEFAULT 0 COMMENT '电流1量程起点(A)' AFTER `protocol_type`, ADD COLUMN `current1_range_end` DECIMAL(10,3) DEFAULT NULL COMMENT '电流1量程终点(A),用于0-65535映射,8Multi设备必填' AFTER `current1_range_start`, ADD COLUMN `current2_range_start` DECIMAL(10,3) DEFAULT 0 COMMENT '电流2量程起点(A)' AFTER `current1_range_end`, ADD COLUMN `current2_range_end` DECIMAL(10,3) DEFAULT NULL COMMENT '电流2量程终点(A),用于0-65535映射,8Multi设备必填' AFTER `current2_range_start`, ADD COLUMN `quality1_range_start` DECIMAL(10,3) DEFAULT 0 COMMENT '质量1量程起点' AFTER `current2_range_end`, ADD COLUMN `quality1_range_end` DECIMAL(10,3) DEFAULT NULL COMMENT '质量1量程终点,用于0-65535映射,8Multi设备必填' AFTER `quality1_range_start`, ADD COLUMN `quality1_unit` VARCHAR(10) DEFAULT NULL COMMENT '质量1单位(前端配置,如kg/g)' AFTER `quality1_range_end`, ADD COLUMN `quality2_range_start` DECIMAL(10,3) DEFAULT 0 COMMENT '质量2量程起点' AFTER `quality1_unit`, ADD COLUMN `quality2_range_end` DECIMAL(10,3) DEFAULT NULL COMMENT '质量2量程终点,用于0-65535映射,8Multi设备必填' AFTER `quality2_range_start`, ADD COLUMN `quality2_unit` VARCHAR(10) DEFAULT NULL COMMENT '质量2单位(前端配置,如kg/g)' AFTER `quality2_range_end`, ADD COLUMN `current_unit` VARCHAR(10) DEFAULT 'A' COMMENT '电流单位(前端配置,如A/mA)' AFTER `quality2_unit`; ``` **字段说明**: - `protocol_type`: 区分设备使用的协议类型,根据`device_no`自动判断(>200为8MULTI,<=200为8ADPRO) - `current1_range_start` / `current1_range_end`: 电流1量程起点和终点,8Multi设备必填 - `current2_range_start` / `current2_range_end`: 电流2量程起点和终点,8Multi设备必填 - `quality1_range_start` / `quality1_range_end`: 质量1量程起点和终点,8Multi设备必填 - `quality2_range_start` / `quality2_range_end`: 质量2量程起点和终点,8Multi设备必填 - `quality1_unit` / `quality2_unit`: 质量单位(前端配置,如kg/g) - `current_unit`: 电流单位(前端配置,如A/mA) **协议类型判断规则**: - `device_no > 200`: 自动设置为8MULTI协议 - `device_no <= 200`: 自动设置为8ADPRO协议 - 同一设备不能在两种协议之间切换 **量程转换公式**: ``` 量程范围 = 量程终点 - 量程起点 实际值 = (原始值 / 65535.0) * 量程范围 + 量程起点 ``` **设备状态判断**: - 电流1实际值 >= 2A **且** 电流2实际值 >= 2A:设备开启状态(与运算) - 其他情况:设备关闭状态 ### 3.2 数据表扩展 (device_data) **新增字段**: ```sql ALTER TABLE `device_data` ADD COLUMN `current1_raw` INT UNSIGNED DEFAULT NULL COMMENT '电流1原始值(0-65535)' AFTER `current_value`, ADD COLUMN `current2_raw` INT UNSIGNED DEFAULT NULL COMMENT '电流2原始值(0-65535)' AFTER `current1_raw`, ADD COLUMN `current1_value` DECIMAL(10,3) DEFAULT NULL COMMENT '电流1实际值(A,经量程转换)' AFTER `current2_raw`, ADD COLUMN `current2_value` DECIMAL(10,3) DEFAULT NULL COMMENT '电流2实际值(A,经量程转换)' AFTER `current1_value`, ADD COLUMN `quality1_raw` INT UNSIGNED DEFAULT NULL COMMENT '质量1原始值(0-65535)' AFTER `current2_value`, ADD COLUMN `quality2_raw` INT UNSIGNED DEFAULT NULL COMMENT '质量2原始值(0-65535)' AFTER `quality1_raw`, ADD COLUMN `quality1_value` DECIMAL(10,3) DEFAULT NULL COMMENT '质量1实际值(kg,经量程转换)' AFTER `quality2_raw`, ADD COLUMN `quality2_value` DECIMAL(10,3) DEFAULT NULL COMMENT '质量2实际值(kg,经量程转换)' AFTER `quality1_value`, ADD COLUMN `humidity` DECIMAL(10,3) DEFAULT NULL COMMENT '湿度值(%RH)' AFTER `quality2_value`, ADD COLUMN `status_work` TINYINT(1) DEFAULT NULL COMMENT '工作状态(0=停止,1=工作)' AFTER `humidity`, ADD COLUMN `status_stop` TINYINT(1) DEFAULT NULL COMMENT '停机状态(0=运行,1=停机)' AFTER `status_work`, ADD COLUMN `status_fault` TINYINT(1) DEFAULT NULL COMMENT '故障状态(0=正常,1=故障)' AFTER `status_stop`, ADD COLUMN `status_reset` TINYINT(1) DEFAULT NULL COMMENT '清零状态(0=正常,1=清零)' AFTER `status_fault`, ADD COLUMN `frequency1` INT DEFAULT NULL COMMENT '频率1原始值' AFTER `status_reset`, ADD COLUMN `frequency2` INT DEFAULT NULL COMMENT '频率2原始值' AFTER `frequency1`, ADD COLUMN `counter1_current` INT DEFAULT NULL COMMENT '计数1当前累计值(下位机传值)' AFTER `frequency2`, ADD COLUMN `counter1_delta` INT DEFAULT NULL COMMENT '计数1增量值(当前值-上次值)' AFTER `counter1_current`, ADD COLUMN `counter2_current` INT DEFAULT NULL COMMENT '计数2当前累计值(下位机传值)' AFTER `counter1_delta`, ADD COLUMN `counter2_delta` INT DEFAULT NULL COMMENT '计数2增量值(当前值-上次值)' AFTER `counter2_current`, ADD COLUMN `counter1_total_8multi` BIGINT UNSIGNED DEFAULT NULL COMMENT '计数1累计总数(8Multi专用,从清零基准值开始累计)' AFTER `counter2_delta`, ADD COLUMN `counter2_total_8multi` BIGINT UNSIGNED DEFAULT NULL COMMENT '计数2累计总数(8Multi专用,从清零基准值开始累计)' AFTER `counter1_total_8multi`, ADD COLUMN `relay_power` TINYINT(1) DEFAULT NULL COMMENT '继电器-供电状态(0=断开,1=闭合)' AFTER `counter2_total_8multi`, ADD COLUMN `relay_alarm` TINYINT(1) DEFAULT NULL COMMENT '继电器-报警状态(0=正常,1=报警)' AFTER `relay_power`, ADD COLUMN `do_soft_start` TINYINT(1) DEFAULT NULL COMMENT 'DO-软启动(0=关,1=开)' AFTER `relay_alarm`, ADD COLUMN `do_stop` TINYINT(1) DEFAULT NULL COMMENT 'DO-停止(0=关,1=开)' AFTER `do_soft_start`, ADD COLUMN `slave_data1` INT DEFAULT NULL COMMENT '485从机数据1' AFTER `do_stop`, ADD COLUMN `slave_data2` INT DEFAULT NULL COMMENT '485从机数据2' AFTER `slave_data1`, ADD COLUMN `touchscreen_data` INT DEFAULT NULL COMMENT '触摸屏数据' AFTER `slave_data2`; ``` ### 3.3 动态字段配置扩展 (device_field_header_config) **修改字段枚举**: ```sql ALTER TABLE `device_field_header_config` MODIFY COLUMN `field_key` ENUM( 'analog1','analog2','analog3','analog4','analog5','analog6','analog7', 'digital1','digital2','digital3','digital4','digital5','digital6', 'current1','current2','quality1','quality2','humidity', 'frequency1','frequency2','slave_data1','slave_data2','touchscreen_data' ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '字段标识(支持8ADPRO和8Multi协议字段)'; ``` ### 3.4 计数器字段设计(避免触发器冲突) **问题**:现有触发器`update_counter_totals_on_insert`处理8ADPRO的`counter1_total`/`counter2_total`字段。 **解决方案**:为8Multi添加独立的计数器总计字段,不修改触发器 **字段对比**: | 协议 | 当前值字段 | 增量值字段 | 总计字段 | 触发器 | |------|-----------|-----------|---------|--------| | 8ADPRO | counter1/counter2 | - | counter1_total/counter2_total | ✅ 使用 | | 8Multi | counter1_current/counter2_current | counter1_delta/counter2_delta | counter1_total_8multi/counter2_total_8multi | ❌ 不使用 | **8Multi计数器逻辑**(修订版): ```java // 1. 获取当前累计值(下位机传值) int currentCounter1 = parseInt(parts[10]); // 2. 获取清零基准值(baseline) long baseline1 = device.getCounter1Baseline() != null ? device.getCounter1Baseline() : 0L; // 3. 计算累计值(下位机当前值 - 清零基准值) long total1 = (long)currentCounter1 - baseline1; if (total1 < 0) total1 = 0L; // 负值保护 // 4. 计算增量值(当前值 - 上次值) int delta1 = currentCounter1 - lastCounter1; if (delta1 < 0) delta1 = 0; // 负值归零(下位机可能重置) // 5. 存储 deviceData.setCounter1Current(currentCounter1); // 下位机当前累计值 deviceData.setCounter1Delta(delta1); // 本次增量 deviceData.setCounter1Total8multi(total1); // 累计总值(= 下位机值 - baseline) ``` **关键设计说明**: - **累计值 = 下位机当前值 - baseline**(不是累加增量!) - **第一条数据**:累计值 = 下位机当前值(因为baseline默认为0) - **清零功能**:设置baseline = 当前下位机值,累计值重新从0开始 - **优点**:即使下位机重置归零,累计值仍能正确计算 **优点**: - ✅ 不修改现有触发器,8ADPRO功能完全不受影响 - ✅ 8Multi使用独立字段,逻辑清晰 - ✅ 两种协议完全隔离,互不干扰 ## 四、数据解析规则 ### 4.1 量程映射转换 **电流/质量原始值转换公式**: ``` 实际值 = (原始值 / 65535.0) * 量程 ``` **示例**: - 电流1量程设置为100A - 接收到原始值32768 - 实际电流1 = (32768 / 65535.0) * 100 = 50.0A ### 4.2 复合状态位解析 #### 4.2.1 DI状态字段解析(工作/停机/故障/清零) ``` 字段值: U16格式,例如 0x004F 解析规则: 取最后一个F(低4位),然后取反 ``` **解析代码示例**: ```java int diValue = parseInt(parts[8]); // 例如 0x004F int lastNibble = diValue & 0x0F; // 取最后4位 = 0xF = 15 int inverted = (~lastNibble) & 0x0F; // 取反并保留4位 = 0x0 = 0 // 解析各个DI状态 boolean work = (inverted & 0x01) != 0; // DI1: 工作 boolean stop = (inverted & 0x02) != 0; // DI2: 停机 boolean fault = (inverted & 0x04) != 0; // DI3: 故障 boolean reset = (inverted & 0x08) != 0; // DI4: 清零 ``` #### 4.2.2 继电器+DO状态字段解析(供电/报警/软启动/停止) ``` 字段值: U16格式,例如 0x004F 解析规则: 取最后一个F(低4位),然后取反(与DI状态相同) 下发格式: DO=0_1(0为通道号,1为值) ``` **解析代码示例**: ```java int doValue = parseInt(parts[12]); // 例如 0x004F int lastNibble = doValue & 0x0F; // 取最后4位 = 0xF = 15 int inverted = (~lastNibble) & 0x0F; // 取反并保留4位 = 0x0 = 0 // 解析各个继电器和DO状态 boolean power = (inverted & 0x01) != 0; // 继电器1: 供电 boolean alarm = (inverted & 0x02) != 0; // 继电器2: 报警 boolean softStart = (inverted & 0x04) != 0; // DO1: 软启动 boolean stopDo = (inverted & 0x08) != 0; // DO2: 停止 ``` **下发控制示例**: ``` DO=0_1 // 通道0(供电),值为1(开启) DO=1_0 // 通道1(报警),值为0(关闭) ``` ### 4.3 计数器处理逻辑(修订版) **核心设计原则**: - 下位机传输的是累计值 - 累计值 = 下位机当前值 - 清零基准值(baseline) - 增量值 = 当前值 - 上次值 **完整处理流程**: ```java // 1. 获取下位机传来的当前累计值 int counter1Current = parseInt(parts[10]); // 计数器1 int counter2Current = parseInt(parts[12]); // 计数器2 // 2. 获取清零基准值(用于计算累计值) Long baseline1 = device.getCounter1Baseline() != null ? device.getCounter1Baseline() : 0L; Long baseline2 = device.getCounter2Baseline() != null ? device.getCounter2Baseline() : 0L; // 3. 计算累计值(显示在前端卡片上的大数字) Long total1 = (long)counter1Current - baseline1; Long total2 = (long)counter2Current - baseline2; if (total1 < 0) total1 = 0L; // 负值保护 if (total2 < 0) total2 = 0L; // 4. 查询上次累计值(用于计算增量) DeviceData lastData = selectLastByDeviceId(deviceId); Integer lastCounter1 = lastData != null ? lastData.getCounter1Current() : 0; Integer lastCounter2 = lastData != null ? lastData.getCounter2Current() : 0; // 5. 计算增量值(显示在前端卡片上的小字) int delta1 = counter1Current - lastCounter1; int delta2 = counter2Current - lastCounter2; if (delta1 < 0) delta1 = 0; // 负值归零(下位机可能重置) if (delta2 < 0) delta2 = 0; // 6. 存储到数据库 deviceData.setCounter1Current(counter1Current); // 下位机原始值 deviceData.setCounter1Delta(delta1); // 增量 deviceData.setCounter1Total8multi(total1); // 累计值 deviceData.setCounter2Current(counter2Current); deviceData.setCounter2Delta(delta2); deviceData.setCounter2Total8multi(total2); ``` **清零功能实现**: - 前端提供清零按钮 - 点击清零:`UPDATE device SET counter1_baseline = 当前下位机值 WHERE id = ?` - 清零后:累计值 = 下位机值 - baseline,重新从0开始 - 下位机继续传累计值,不受影响 **数据库字段**: ```sql ALTER TABLE `device` ADD COLUMN `counter1_baseline` INT DEFAULT 0 COMMENT '计数1基准值(清零后的基准)', ADD COLUMN `counter2_baseline` INT DEFAULT 0 COMMENT '计数2基准值(清零后的基准)', ADD COLUMN `voltage1` DECIMAL(10,3) DEFAULT NULL COMMENT '电压1配置(V),用于功率1计算', ADD COLUMN `voltage2` DECIMAL(10,3) DEFAULT NULL COMMENT '电压2配置(V),用于功率2计算'; ``` **示例场景**: ``` 时间线: 下位机值: 100 → 150 → 200 → [清零,baseline=200] → 250 → 300 累计值: 100 → 150 → 200 → 0 → 50 → 100 增量值: 0 → 50 → 50 → 0 → 50 → 50 ``` ## 五、接口设计方案 ### 5.1 数据上报接口(复用现有) **接口路径**: `POST /equipment/info/ingest/raw` **请求示例**: ``` +YAV:1001,32768,16384,49152,8192,25.5,65.0,15,5000,100,3000,50,3,1000,2000,0,EEFF ``` **字段映射**: 1. 帧头: +YAV(固定) 2. id: 1001(设备ID,对应g_tDevParam.Address) 3. 电流1原始值: 32768(AI1,0-65535,对应usSRegHoldBuf[0]) 4. 电流2原始值: 16384(AI2,0-65535,对应usSRegHoldBuf[1]) 5. 质量1原始值: 49152(AI3,0-65535,对应usSRegHoldBuf[2]) 6. 质量2原始值: 8192(AI4,0-65535,对应usSRegHoldBuf[3]) 7. 温度: 25.5°C(保留1位小数) 8. 湿度: 65.0%RH(保留1位小数) 9. DI状态复合: 15(工作/停机/故障/清零,对应usSRegHoldBuf[DI_REG]) 10. 频率1: 5000Hz(对应freq1) 11. 计数1: 100(对应num_count1) 12. 频率2: 3000Hz(对应freq2) 13. 计数2: 50(对应num_count2) 14. 继电器+DO状态复合: 3(供电/报警/软启动/停止,对应usSRegHoldBuf[DO_REG]) 15. 从机数据1: 1000(对应usSRegHoldBuf[DATA_REG_1]) 16. 从机数据2: 2000(对应usSRegHoldBuf[DATA_REG_1+1]) 17. 触摸屏: 0(固定发送0) 18. 帧尾: EEFF(固定) ### 5.2 设备配置接口(扩展现有) **新增量程配置接口**: `PUT /equipment/info/device/range` **请求参数**: ```json { "id": 1, "current1_range": 100.0, "current2_range": 50.0, "quality1_range": 1000.0, "quality2_range": 500.0, "calibration_offset": 0.5, "calibration_factor": 1.02 } ``` **响应**: ```json { "code": 200, "msg": "量程配置成功" } ``` ### 5.3 设备创建接口(扩展现有) **接口路径**: `POST /equipment/info/device` **请求参数扩展**: ```json { "deviceNo": 1001, "deviceName": "8Multi设备1", "protocol_type": "8MULTI", "current1_range": 100.0, "current2_range": 50.0, "quality1_range": 1000.0, "quality2_range": 500.0, "image_url": "/profile/upload/device.png", "headers": { "current1": "主电流", "current2": "辅助电流", "quality1": "主质量", "quality2": "辅助质量", "humidity": "环境湿度", "frequency1": "主频率", "frequency2": "辅助频率" } } ``` ## 六、前端界面扩展 ### 6.1 设备卡片展示 **8ADPRO设备卡片** (保持不变): - 温度、电流、功率、状态 - 计数器1、计数器2 **8Multi设备卡片** (新增): - 温度、湿度 - 电流1、电流2 - 质量1、质量2 - 工作/停机/故障状态指示灯 - 频率1、频率2 - 计数器1、计数器2 ### 6.2 设备详情抽屉 **新增8Multi专属字段**: - 电流1/电流2(显示原始值和实际值) - 质量1/质量2(显示原始值和实际值) - 湿度 - 工作状态、停机状态、故障状态、清零状态 - 频率1、频率2 - 继电器状态(供电、报警) - DO状态(软启动、停止) - 从机数据1、从机数据2 - 触摸屏数据 ### 6.3 设备配置对话框 **新增配置项**: 1. **协议类型选择**: 8ADPRO / 8Multi 2. **量程配置** (仅8Multi显示): - 电流1量程 (A) - 电流2量程 (A) - 质量1量程 (kg) - 质量2量程 (kg) 3. **校准配置**: - 校准偏移量 - 校准系数 ## 七、实现步骤 ### 7.1 数据库变更 1. ✅ 执行device表ALTER语句,新增协议类型和量程字段 2. ✅ 执行device_data表ALTER语句,新增8Multi专属字段 3. ✅ 修改device_field_header_config表枚举,支持新字段 ### 7.2 后端开发(已完成) #### 7.2.1 实体类扩展 1. ✅ **MesDevice.java** - 添加17个8Multi字段 ```java // 协议类型、量程起点/终点、单位、计数器基准值、电压1/电压2 private String protocolType; private BigDecimal current1RangeStart, current1RangeEnd; private BigDecimal current2RangeStart, current2RangeEnd; private BigDecimal quality1RangeStart, quality1RangeEnd; private String quality1Unit, quality2Unit, currentUnit; private Integer counter1Baseline, counter2Baseline; private BigDecimal voltage1, voltage2; // 辅助方法 public boolean is8Multi() { return "8MULTI".equals(this.protocolType); } public boolean is8ADPRO() { return "8ADPRO".equals(this.protocolType) || this.protocolType == null; } ``` 2. ✅ **DeviceData.java** - 添加29个8Multi字段 ```java // 电流/质量原始值和实际值、湿度、状态位、频率、计数器、继电器、DO、从机数据 private Integer current1Raw, current2Raw; private BigDecimal current1Value, current2Value; private Integer quality1Raw, quality2Raw; private BigDecimal quality1Value, quality2Value; private BigDecimal humidity; private Integer statusWork, statusStop, statusFault, statusReset; private Integer frequency1, frequency2; private Integer counter1Current, counter1Delta, counter2Current, counter2Delta; private Long counter1Total8multi, counter2Total8multi; private Integer relayPower, relayAlarm, doSoftStart, doStop; private Integer slaveData1, slaveData2, touchscreenData; ``` #### 7.2.2 Service层 3. ✅ **Multi8ProtocolService.java** - 8Multi协议解析服务 - `parse8MultiProtocol()` - 协议解析方法 - `convertRangeValue()` - 量程转换方法 - `resetCounter()` - 计数器清零方法 #### 7.2.3 Controller层 4. ✅ **Multi8Controller.java** - 8Multi设备控制器 - `POST /equipment/multi8/resetCounter` - 计数器清零 - `PUT /equipment/multi8/updateDeviceConfig` - 更新设备配置 - `GET /equipment/multi8/getDeviceDetail/{id}` - 获取设备详情 #### 7.2.4 Mapper层 5. ✅ **DeviceDataMapper.java** - 添加方法 ```java DeviceData selectLastByDeviceId(@Param("deviceId") Long deviceId); ``` 6. ✅ **MesDeviceMapper.java** - 添加方法 ```java MesDevice selectByDeviceNo(@Param("deviceNo") Integer deviceNo); ``` ### 7.3 前端开发(需手动实现) **文件位置**:`e:\Yavii_P3\MES\mes-ui\src\views\mes\equipment\info\index.vue`(1178行) **修改原则**: ⚠️ **在现有8ADPRO代码基础上扩展,不删除任何8ADPRO功能** ⚠️ **通过`v-if`判断协议类型,动态渲染不同UI** ⚠️ **所有8Multi字段都要做空值处理** #### 7.3.1 设备卡片扩展 通过`v-if`判断协议类型,动态渲染不同UI: ```vue