From d2763dc044c08022e5f7e6c6c4c60b55f9c5dd8e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 25 May 2026 00:43:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(iot):=20=E4=BF=AE=E5=A4=8D=20IoT=20?= =?UTF-8?q?=E5=A4=8D=E8=AF=84=E5=90=8E=E7=BB=AD=E5=AF=B9=E9=BD=90=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补齐设备详情子设备、Modbus 操作权限 - 修复属性搜索清空、模拟器空参数、告警处理备注校验 - 修复 HTTP 数据目的 URL 回显、Redis Stream 密码必填 - 优化固件上传读取时机,补充 isEmptyVal 并复用 JSON 参数校验 - 修正场景产品状态字典和 antd ValueInput 图标导入 --- .../src/components/upload/file-upload.vue | 8 ++-- .../src/components/upload/input-upload.vue | 1 + apps/web-antd/src/components/upload/typing.ts | 1 + .../src/views/iot/alert/record/index.vue | 4 -- .../device/detail/modules/modbus-config.vue | 16 ++++++- .../device/detail/modules/simulator.vue | 48 ++++++++++--------- .../device/detail/modules/sub-device.vue | 3 ++ .../detail/modules/thing-model-property.vue | 8 ++++ .../src/views/iot/ota/firmware/index.vue | 8 +++- .../data/sink/config/http-config-form.vue | 28 +++++++---- .../sink/config/redis-stream-config-form.vue | 6 ++- .../scene/form/inputs/json-params-input.vue | 7 ++- .../rule/scene/form/inputs/value-input.vue | 1 + .../scene/form/selectors/product-selector.vue | 2 +- .../src/components/upload/file-upload.vue | 8 ++-- .../src/components/upload/input-upload.vue | 1 + apps/web-ele/src/components/upload/typing.ts | 1 + .../src/views/iot/alert/record/index.vue | 6 --- .../device/detail/modules/modbus-config.vue | 16 ++++++- .../device/detail/modules/simulator.vue | 48 ++++++++++--------- .../device/detail/modules/sub-device.vue | 3 ++ .../detail/modules/thing-model-property.vue | 1 + .../src/views/iot/ota/firmware/index.vue | 8 +++- .../data/sink/config/http-config-form.vue | 28 +++++++---- .../sink/config/redis-stream-config-form.vue | 6 ++- .../scene/form/inputs/json-params-input.vue | 7 ++- .../scene/form/selectors/product-selector.vue | 2 +- 27 files changed, 178 insertions(+), 98 deletions(-) diff --git a/apps/web-antd/src/components/upload/file-upload.vue b/apps/web-antd/src/components/upload/file-upload.vue index 3838642ea..85afc3b9d 100644 --- a/apps/web-antd/src/components/upload/file-upload.vue +++ b/apps/web-antd/src/components/upload/file-upload.vue @@ -32,6 +32,7 @@ const props = withDefaults(defineProps(), { multiple: false, api: undefined, resultField: '', + returnText: false, showDescription: false, }); const emit = defineEmits([ @@ -147,9 +148,6 @@ function handleUploadError(error: any) { * @returns 是否允许上传 */ async function beforeUpload(file: File) { - const fileContent = await file.text(); - emit('returnText', fileContent); - // 检查文件数量限制 if (fileList.value!.length >= props.maxNumber) { message.error($t('ui.upload.maxNumber', [props.maxNumber])); @@ -176,6 +174,10 @@ async function beforeUpload(file: File) { // 只有在验证通过后才增加计数器 uploadNumber.value++; + if (props.returnText) { + const fileContent = await file.text(); + emit('returnText', fileContent); + } return true; } diff --git a/apps/web-antd/src/components/upload/input-upload.vue b/apps/web-antd/src/components/upload/input-upload.vue index 90b2f4f7c..88f00f1cf 100644 --- a/apps/web-antd/src/components/upload/input-upload.vue +++ b/apps/web-antd/src/components/upload/input-upload.vue @@ -58,6 +58,7 @@ const textareaProps = computed(() => { const fileUploadProps = computed(() => { return { ...props.fileUploadProps, + returnText: true, }; }); diff --git a/apps/web-antd/src/components/upload/typing.ts b/apps/web-antd/src/components/upload/typing.ts index f3c16bc4d..990aa7d8a 100644 --- a/apps/web-antd/src/components/upload/typing.ts +++ b/apps/web-antd/src/components/upload/typing.ts @@ -27,6 +27,7 @@ export interface FileUploadProps { maxSize?: number; // 文件最大多少MB multiple?: boolean; // 是否支持多选 resultField?: string; // support xxx.xxx.xx + returnText?: boolean; // 是否返回文件文本内容 showDescription?: boolean; // 是否显示下面的描述 value?: string | string[]; } diff --git a/apps/web-antd/src/views/iot/alert/record/index.vue b/apps/web-antd/src/views/iot/alert/record/index.vue index d3d8f9d17..b5c59a7a8 100644 --- a/apps/web-antd/src/views/iot/alert/record/index.vue +++ b/apps/web-antd/src/views/iot/alert/record/index.vue @@ -45,10 +45,6 @@ function handleProcess(row: AlertRecordApi.AlertRecord) { }), ]), async onOk() { - if (!processRemark.value) { - message.warning('请输入处理原因'); - throw new Error('请输入处理原因'); - } const hideLoading = message.loading({ content: '正在处理...', duration: 0, diff --git a/apps/web-antd/src/views/iot/device/device/detail/modules/modbus-config.vue b/apps/web-antd/src/views/iot/device/device/detail/modules/modbus-config.vue index 672915a01..ce4d907d8 100644 --- a/apps/web-antd/src/views/iot/device/device/detail/modules/modbus-config.vue +++ b/apps/web-antd/src/views/iot/device/device/detail/modules/modbus-config.vue @@ -14,7 +14,7 @@ import { computed, h, onMounted, ref } from 'vue'; import { confirm, useVbenModal } from '@vben/common-ui'; import { DICT_TYPE, ModbusFunctionCodeOptions } from '@vben/constants'; -import { Button, message } from 'ant-design-vue'; +import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { getModbusConfig } from '#/api/iot/device/modbus/config'; @@ -307,7 +307,16 @@ onMounted(async () => { @@ -320,6 +329,7 @@ onMounted(async () => { label: '新增点位', type: 'primary', icon: ACTION_ICON.ADD, + auth: ['iot:device:create'], onClick: handleAddPoint, }, ]" @@ -331,12 +341,14 @@ onMounted(async () => { { label: '编辑', type: 'link', + auth: ['iot:device:update'], onClick: () => handleEditPoint(row), }, { label: '删除', type: 'link', danger: true, + auth: ['iot:device:delete'], popConfirm: { title: `确定要删除点位【${row.name}】吗?`, confirm: () => handleDeletePoint(row), diff --git a/apps/web-antd/src/views/iot/device/device/detail/modules/simulator.vue b/apps/web-antd/src/views/iot/device/device/detail/modules/simulator.vue index ebfa9087c..8a58ce5f7 100644 --- a/apps/web-antd/src/views/iot/device/device/detail/modules/simulator.vue +++ b/apps/web-antd/src/views/iot/device/device/detail/modules/simulator.vue @@ -312,13 +312,15 @@ async function handleEventPost(row: ThingModelApi.ThingModel) { const valueStr = formData.value[row.identifier!]; let eventValue: any; - if (valueStr) { - try { - eventValue = JSON.parse(valueStr); - } catch { - message.error('事件参数格式错误,请输入有效的JSON格式'); - return; - } + if (valueStr === undefined || valueStr === null || valueStr === '') { + message.warning('请输入事件参数'); + return; + } + try { + eventValue = JSON.parse(valueStr); + } catch { + message.error('事件参数格式错误,请输入有效的JSON格式'); + return; } // 与后端 IotDeviceEventPostReqDTO 对齐 :{ identifier, value, time } @@ -399,21 +401,23 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) { const valueStr = formData.value[row.identifier!]; let inputParams: any = {}; - if (valueStr) { - try { - inputParams = JSON.parse(valueStr); - } catch { - message.error('服务参数格式错误,请输入有效的JSON格式'); - return; - } - if ( - typeof inputParams !== 'object' || - inputParams === null || - Array.isArray(inputParams) - ) { - message.error('服务参数必须是 JSON 对象'); - return; - } + if (valueStr === undefined || valueStr === null || valueStr === '') { + message.warning('请输入服务参数'); + return; + } + try { + inputParams = JSON.parse(valueStr); + } catch { + message.error('服务参数格式错误,请输入有效的JSON格式'); + return; + } + if ( + typeof inputParams !== 'object' || + inputParams === null || + Array.isArray(inputParams) + ) { + message.error('服务参数必须是 JSON 对象'); + return; } // 与后端 IotDeviceServiceInvokeReqDTO 对齐 :{ identifier, inputParams } diff --git a/apps/web-antd/src/views/iot/device/device/detail/modules/sub-device.vue b/apps/web-antd/src/views/iot/device/device/detail/modules/sub-device.vue index 36d1fc372..8515630fa 100644 --- a/apps/web-antd/src/views/iot/device/device/detail/modules/sub-device.vue +++ b/apps/web-antd/src/views/iot/device/device/detail/modules/sub-device.vue @@ -317,6 +317,7 @@ watch( label: '添加子设备', type: 'primary', icon: ACTION_ICON.ADD, + auth: ['iot:device:update'], onClick: openAddModal, }, { @@ -324,6 +325,7 @@ watch( type: 'primary', danger: true, icon: ACTION_ICON.DELETE, + auth: ['iot:device:update'], disabled: isEmpty(checkedIds), onClick: handleUnbindBatch, }, @@ -342,6 +344,7 @@ watch( label: '解绑', type: 'link', danger: true, + auth: ['iot:device:update'], onClick: () => handleUnbind(row), }, ]" diff --git a/apps/web-antd/src/views/iot/device/device/detail/modules/thing-model-property.vue b/apps/web-antd/src/views/iot/device/device/detail/modules/thing-model-property.vue index c73ebe2d8..e0ce9dc6c 100644 --- a/apps/web-antd/src/views/iot/device/device/detail/modules/thing-model-property.vue +++ b/apps/web-antd/src/views/iot/device/device/detail/modules/thing-model-property.vue @@ -207,6 +207,13 @@ function handleQuery() { } } +/** 搜索关键词变化 */ +function handleKeywordChange(event: Event) { + if (!(event.target as HTMLInputElement).value) { + handleQuery(); + } +} + /** 视图切换 */ async function handleViewModeChange(mode: 'card' | 'list') { if (viewMode.value === mode) { @@ -281,6 +288,7 @@ onBeforeUnmount(() => { allow-clear placeholder="请输入属性名称、标识符" style="width: 240px" + @change="handleKeywordChange" @press-enter="handleQuery" />