fix(iot): 修复 6 处 bug(P1×5 + P3×1)

- product/product/data.ts: 网关子设备不显示联网方式
  show 条件由 != GATEWAY 改为 != GATEWAY_SUB(原写法漏判子设备)
- home/message-trend-card.vue: onMounted 兜底首次拉取
  ShortcutDateRangePicker 早期 emit 触发的请求落在 useEcharts
  isActiveRef=false 阶段会被静默丢弃;并加 isFirstMount guard 跳过
  子组件首次 emit,消除首次进入的双请求
- ota/firmware/data.ts: FileUpload accept 改回 ['bin','zip','pdf']
  并同步 helpText,对齐 vue3 源约定
- device/device/index.vue: 批量删除补 confirm 二次确认弹窗,
  与 system 模块批删风格一致,避免一键误删
- device/device/detail/modules/modbus-point-form.vue: 字节序仅在
  「为空 / 不属于新 rawDataType 合法选项」才重置,避免编辑回填时
  setValues 触发 handleValuesChange 把已保存字节序覆盖

antd + ele 两端同步。
pull/348/head
YunaiV 2026-05-23 22:04:08 +08:00
parent 152964395d
commit ef57c96b2f
10 changed files with 62 additions and 14 deletions

View File

@ -246,10 +246,20 @@ const [Form, formApi] = useVbenForm({
if (option && option.registerCount > 0) {
await formApi.setFieldValue('registerCount', option.registerCount);
}
//
// rawDataType
// setValues
const byteOrderOptions = getByteOrderOptions(rawDataType);
if (byteOrderOptions.length > 0) {
await formApi.setFieldValue('byteOrder', byteOrderOptions[0]!.value);
const currentByteOrder = values.byteOrder;
const isCurrentValid =
!!currentByteOrder &&
byteOrderOptions.some((opt) => opt.value === currentByteOrder);
if (!isCurrentValid) {
await formApi.setFieldValue(
'byteOrder',
byteOrderOptions[0]!.value,
);
}
}
}
}

View File

@ -9,7 +9,7 @@ import type { IotProductApi } from '#/api/iot/product/product';
import { nextTick, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
@ -169,6 +169,7 @@ async function handleDeleteBatch() {
message.warning('请选择要删除的设备');
return;
}
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
const hideLoading = message.loading({
content: $t('ui.actionMessage.deletingBatch'),
duration: 0,

View File

@ -3,7 +3,7 @@ import type { Dayjs } from 'dayjs';
import type { IotStatisticsApi } from '#/api/iot/statistics';
import { computed, nextTick, reactive, ref } from 'vue';
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
@ -26,6 +26,7 @@ const loading = ref(false); // 加载状态
const messageData = ref<IotStatisticsApi.DeviceMessageSummaryByDateRespVO[]>(
[],
); //
const isFirstMount = ref(true); // mount emit
/** 时间范围(仅日期,不包含时分秒) */
const dateRange = ref<[string, string]>([
@ -74,6 +75,11 @@ function handleDateRangeChange(times?: [Dayjs, Dayjs]) {
];
// 00:00:00 23:59:59
queryParams.times = formatDateRangeWithTime(dateRange.value);
if (isFirstMount.value) {
// ShortcutDateRangePicker mount emit fetch
// onMounted
return;
}
handleQuery();
}
@ -123,6 +129,13 @@ async function renderChartWhenReady() {
initChart();
}
//
// ShortcutDateRangePicker emit useEcharts isActiveRef = false renderEcharts
// handleDateRangeChange isFirstMount=true fetch
onMounted(() => {
fetchMessageData();
isFirstMount.value = false;
});
</script>
<template>

View File

@ -101,9 +101,9 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'FileUpload',
componentProps: {
maxNumber: 1,
accept: ['bin', 'hex', 'zip'],
accept: ['bin', 'zip', 'pdf'],
maxSize: 50,
helpText: '支持上传 .bin、.hex、.zip 格式的固件文件,最大 50MB',
helpText: '支持上传 .bin、.zip、.pdf 格式的固件文件,最大 50MB',
},
rules: 'required',
dependencies: {

View File

@ -131,7 +131,7 @@ export function useBasicFormSchema(
// 网关子设备走网关联网,不需要联网方式
dependencies: {
triggerFields: ['deviceType'],
show: (values) => values.deviceType !== DeviceTypeEnum.GATEWAY,
show: (values) => values.deviceType !== DeviceTypeEnum.GATEWAY_SUB,
},
rules: 'required',
},

View File

@ -241,10 +241,20 @@ const [Form, formApi] = useVbenForm({
if (option && option.registerCount > 0) {
await formApi.setFieldValue('registerCount', option.registerCount);
}
//
// rawDataType
// setValues
const byteOrderOptions = getByteOrderOptions(rawDataType);
if (byteOrderOptions.length > 0) {
await formApi.setFieldValue('byteOrder', byteOrderOptions[0]!.value);
const currentByteOrder = values.byteOrder;
const isCurrentValid =
!!currentByteOrder &&
byteOrderOptions.some((opt) => opt.value === currentByteOrder);
if (!isCurrentValid) {
await formApi.setFieldValue(
'byteOrder',
byteOrderOptions[0]!.value,
);
}
}
}
}

View File

@ -9,7 +9,7 @@ import type { IotProductApi } from '#/api/iot/product/product';
import { nextTick, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
@ -169,6 +169,7 @@ async function handleDeleteBatch() {
ElMessage.warning('请选择要删除的设备');
return;
}
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
const loadingInstance = ElLoading.service({
text: $t('ui.actionMessage.deletingBatch'),
});

View File

@ -3,7 +3,7 @@ import type { Dayjs } from 'dayjs';
import type { IotStatisticsApi } from '#/api/iot/statistics';
import { computed, nextTick, reactive, ref } from 'vue';
import { computed, nextTick, onMounted, reactive, ref } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
@ -26,6 +26,7 @@ const loading = ref(false); // 加载状态
const messageData = ref<IotStatisticsApi.DeviceMessageSummaryByDateRespVO[]>(
[],
); //
const isFirstMount = ref(true); // mount emit
/** 时间范围(仅日期,不包含时分秒) */
const dateRange = ref<[string, string]>([
@ -74,6 +75,11 @@ function handleDateRangeChange(times?: [Dayjs, Dayjs]) {
];
// 00:00:00 23:59:59
queryParams.times = formatDateRangeWithTime(dateRange.value);
if (isFirstMount.value) {
// ShortcutDateRangePicker mount emit fetch
// onMounted
return;
}
handleQuery();
}
@ -123,6 +129,13 @@ async function renderChartWhenReady() {
initChart();
}
//
// ShortcutDateRangePicker emit useEcharts isActiveRef = false renderEcharts
// handleDateRangeChange isFirstMount=true fetch
onMounted(() => {
fetchMessageData();
isFirstMount.value = false;
});
</script>
<template>

View File

@ -101,9 +101,9 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'FileUpload',
componentProps: {
maxNumber: 1,
accept: ['bin', 'hex', 'zip'],
accept: ['bin', 'zip', 'pdf'],
maxSize: 50,
helpText: '支持上传 .bin、.hex、.zip 格式的固件文件,最大 50MB',
helpText: '支持上传 .bin、.zip、.pdf 格式的固件文件,最大 50MB',
},
rules: 'required',
dependencies: {

View File

@ -128,7 +128,7 @@ export function useBasicFormSchema(
// 网关子设备走网关联网,不需要联网方式
dependencies: {
triggerFields: ['deviceType'],
show: (values) => values.deviceType !== DeviceTypeEnum.GATEWAY,
show: (values) => values.deviceType !== DeviceTypeEnum.GATEWAY_SUB,
},
rules: 'required',
},