From eea1e1eca936c2794ea1d3b550577123a880ba16 Mon Sep 17 00:00:00 2001 From: yhl186 <9033283+yhl186@user.noreply.gitee.com> Date: Wed, 14 Jan 2026 22:45:26 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E7=89=A9=E8=81=94=E7=BD=91iot?= =?UTF-8?q?=E3=80=91=EF=BC=9A=E6=96=B0=E5=A2=9Etcp/mqtt=E9=80=8F=E4=BC=A0m?= =?UTF-8?q?odbus=20rtu/modbus=20tcp=EF=BC=8C=E6=94=AF=E6=8C=81=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E8=BD=AE=E8=AF=A2=EF=BC=8C=E6=9F=A5=E7=9C=8Bmodbus=20?= =?UTF-8?q?rtu=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/product/product/index.ts | 2 + src/api/iot/thingmodel/index.ts | 18 ++ .../detail/DeviceDetailsThingModelEvent.vue | 12 + .../DeviceDetailsThingModelProperty.vue | 13 ++ .../detail/DeviceDetailsThingModelService.vue | 11 + src/views/iot/product/product/ProductForm.vue | 65 +++++- .../ThingModelModbusCommandDialog.vue | 206 ++++++++++++++++++ .../iot/thingmodel/ThingModelProperty.vue | 200 ++++++++++++++++- .../iot/thingmodel/ThingModelService.vue | 68 +++++- src/views/iot/thingmodel/index.vue | 37 +++- src/views/iot/utils/constants.ts | 36 +++ 11 files changed, 662 insertions(+), 6 deletions(-) create mode 100644 src/views/iot/thingmodel/ThingModelModbusCommandDialog.vue diff --git a/src/api/iot/product/product/index.ts b/src/api/iot/product/product/index.ts index c9f273ebe..c2a047ca9 100644 --- a/src/api/iot/product/product/index.ts +++ b/src/api/iot/product/product/index.ts @@ -16,6 +16,8 @@ export interface ProductVO { locationType: number // 设备类型 netType: number // 联网方式 codecType: string // 数据格式(编解码器类型) + protocolType?: string // 协议类型(STANDARD, MODBUS_RTU, MODBUS_TCP) + modbusSlaveId?: number // Modbus从站ID(1-247) deviceCount: number // 设备数量 createTime: Date // 创建时间 } diff --git a/src/api/iot/thingmodel/index.ts b/src/api/iot/thingmodel/index.ts index bcf9e0707..27ef6c544 100644 --- a/src/api/iot/thingmodel/index.ts +++ b/src/api/iot/thingmodel/index.ts @@ -78,6 +78,18 @@ export interface ThingModelProperty { description?: string dataSpecs?: ThingModelProperty dataSpecsList?: ThingModelProperty[] + modbusConfig?: ModbusConfig +} + +/** Modbus 配置 */ +export interface ModbusConfig { + collectionMode?: number // 数据采集模式:1-定时轮询,2-主动上报 + functionCode?: number // 功能码:0x03-读保持寄存器,0x04-读输入寄存器等(默认0x03) + registerAddress?: number // 寄存器地址(低位字节) + registerCount?: number // 寄存器数量 / 线圈数量(默认1) + pollingInterval?: number // 采集频率(秒) + fullFrame?: string // 完整的数据帧(自动生成的HEX字符串) + crcHex?: string // CRC 校验码(自动生成的HEX字符串) } /** 物模型事件 */ @@ -101,6 +113,7 @@ export interface ThingModelService { inputParams?: ThingModelParam[] outputParams?: ThingModelParam[] method?: string + modbusConfig?: ModbusConfig // 添加 Modbus 配置 } /** 物模型参数 */ @@ -197,6 +210,11 @@ export const ThingModelApi = { // 删除产品物模型 deleteThingModel: async (id: number) => { return await request.delete({ url: `/iot/thing-model/delete?id=` + id }) + }, + + // 计算 Modbus 命令(用于前端自动生成) + calculateModbusCommand: async (data: { productId: number; registerAddress: number; functionCode?: number }) => { + return await request.post({ url: `/iot/thing-model/calculate-modbus-command`, data }) } } diff --git a/src/views/iot/device/device/detail/DeviceDetailsThingModelEvent.vue b/src/views/iot/device/device/detail/DeviceDetailsThingModelEvent.vue index 04f9a9f53..5178ed7e8 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsThingModelEvent.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsThingModelEvent.vue @@ -131,6 +131,7 @@ const getList = async () => { if (!props.deviceId) return loading.value = true try { + queryParams.deviceId = props.deviceId const data = await DeviceApi.getDeviceMessagePairPage(queryParams) list.value = data.list total.value = data.length @@ -139,6 +140,17 @@ const getList = async () => { } } +/** 监听 deviceId 变化 */ +watch( + () => props.deviceId, + (val) => { + if (val) { + queryParams.deviceId = val + getList() + } + } +) + /** 搜索按钮操作 */ const handleQuery = () => { queryParams.pageNo = 1 diff --git a/src/views/iot/device/device/detail/DeviceDetailsThingModelProperty.vue b/src/views/iot/device/device/detail/DeviceDetailsThingModelProperty.vue index 438b529d6..e63b8d112 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsThingModelProperty.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsThingModelProperty.vue @@ -171,6 +171,9 @@ const queryFormRef = ref() // 搜索的表单 /** 查询列表 */ const getList = async () => { + if (!props.deviceId) { + return + } loading.value = true try { const params = { @@ -185,6 +188,16 @@ const getList = async () => { } } +/** 监听 deviceId 变化 */ +watch( + () => props.deviceId, + (val) => { + if (val) { + getList() + } + } +) + /** 前端筛选数据 */ const handleFilter = () => { if (!queryParams.keyword.trim()) { diff --git a/src/views/iot/device/device/detail/DeviceDetailsThingModelService.vue b/src/views/iot/device/device/detail/DeviceDetailsThingModelService.vue index fd8456162..37d0f780f 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsThingModelService.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsThingModelService.vue @@ -146,6 +146,7 @@ const getList = async () => { if (!props.deviceId) return loading.value = true try { + queryParams.deviceId = props.deviceId const data = await DeviceApi.getDeviceMessagePairPage(queryParams) list.value = data.list total.value = data.length @@ -154,6 +155,16 @@ const getList = async () => { } } +/** 监听 deviceId 变化 */ +watch( + () => props.deviceId, + (val) => { + if (val) { + queryParams.deviceId = val + getList() + } + } +) /** 搜索按钮操作 */ const handleQuery = () => { queryParams.pageNo = 1 diff --git a/src/views/iot/product/product/ProductForm.vue b/src/views/iot/product/product/ProductForm.vue index 5247e9258..2623973dd 100644 --- a/src/views/iot/product/product/ProductForm.vue +++ b/src/views/iot/product/product/ProductForm.vue @@ -83,6 +83,28 @@ {{ dict.label }} +
Modbus 协议自动使用 HEX 格式
+ + + + + + + + + + +
默认值:1
@@ -132,7 +154,9 @@ const formData = ref({ deviceType: undefined, locationType: undefined, netType: undefined, - codecType: CodecTypeEnum.ALINK + codecType: CodecTypeEnum.ALINK, + protocolType: 'STANDARD', + modbusSlaveId: 1 }) const formRules = reactive({ productKey: [{ required: true, message: 'ProductKey 不能为空', trigger: 'blur' }], @@ -151,7 +175,30 @@ const formRules = reactive({ }) const formRef = ref() const categoryList = ref([]) // 产品分类列表 +// 计算属性:是否为 Modbus 协议 +const isModbusProtocol = computed(() => { + return ( + formData.value.protocolType === 'MODBUS_RTU' || formData.value.protocolType === 'MODBUS_TCP' + ) +}) +// 处理协议类型变化 +const handleProtocolTypeChange = (value: string) => { + if (value === 'MODBUS_RTU' || value === 'MODBUS_TCP') { + // Modbus 协议自动设置数据格式为 HEX + // 查找已存在的 HEX 选项(忽略大小写) + const options = getStrDictOptions(DICT_TYPE.IOT_CODEC_TYPE) + const hexOption = options.find((item) => item.value.toUpperCase() === 'HEX') + formData.value.codecType = hexOption ? hexOption.value : 'HEX' // 如果存在则使用存在的 options 值,否则使用 'HEX' + // 设置默认从站ID + if (!formData.value.modbusSlaveId) { + formData.value.modbusSlaveId = 1 + } + } else { + // 其他协议使用 Alink 格式 + formData.value.codecType = CodecTypeEnum.ALINK + } +} /** 打开弹窗 */ const open = async (type: string, id?: number) => { dialogVisible.value = true @@ -208,7 +255,9 @@ const resetForm = () => { deviceType: undefined, locationType: undefined, netType: undefined, - codecType: CodecTypeEnum.ALINK + codecType: CodecTypeEnum.ALINK, + protocolType: 'STANDARD', + modbusSlaveId: 1 } formRef.value?.resetFields() } @@ -218,3 +267,15 @@ const generateProductKey = () => { formData.value.productKey = generateRandomStr(16) } + + diff --git a/src/views/iot/thingmodel/ThingModelModbusCommandDialog.vue b/src/views/iot/thingmodel/ThingModelModbusCommandDialog.vue new file mode 100644 index 000000000..4177181df --- /dev/null +++ b/src/views/iot/thingmodel/ThingModelModbusCommandDialog.vue @@ -0,0 +1,206 @@ + + + + + + diff --git a/src/views/iot/thingmodel/ThingModelProperty.vue b/src/views/iot/thingmodel/ThingModelProperty.vue index 490f364e8..acd7a4b47 100644 --- a/src/views/iot/thingmodel/ThingModelProperty.vue +++ b/src/views/iot/thingmodel/ThingModelProperty.vue @@ -93,6 +93,91 @@ + +
+ Modbus 配置 + + + + + {{ mode.label }} + + + + + + + + + + + + + + + + + + + + + + + + {{ order.label }} + + + + + + + + + + +
diff --git a/src/views/iot/thingmodel/ThingModelService.vue b/src/views/iot/thingmodel/ThingModelService.vue index 35f7c9888..01cb6a0a2 100644 --- a/src/views/iot/thingmodel/ThingModelService.vue +++ b/src/views/iot/thingmodel/ThingModelService.vue @@ -27,6 +27,49 @@ :direction="IoTThingModelParamDirectionEnum.OUTPUT" /> + + Modbus 配置(可选) + + +
如果配置了完整帧,将直接使用该帧发送命令(推荐用于固定命令)
+
+ + + + + + + + + + + + + + {{ order.label }} + + +