From 0e8771c22eaf45f63b61166222f9549f1423c4f1 Mon Sep 17 00:00:00 2001 From: hwj Date: Fri, 13 Mar 2026 11:18:27 +0800 Subject: [PATCH] =?UTF-8?q?style=EF=BC=9A=E8=AE=BE=E5=A4=87=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E5=8F=82=E6=95=B0=E5=88=86=E6=9E=90-=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=8E=A7=E4=BB=B6=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/deviceParamAnalysis/index.vue | 143 ++++++++++++++------ 1 file changed, 104 insertions(+), 39 deletions(-) diff --git a/src/views/iot/deviceParamAnalysis/index.vue b/src/views/iot/deviceParamAnalysis/index.vue index 2508c84b..722a5e53 100644 --- a/src/views/iot/deviceParamAnalysis/index.vue +++ b/src/views/iot/deviceParamAnalysis/index.vue @@ -33,15 +33,19 @@ - +
+ +
@@ -131,45 +135,37 @@ const keyword = ref('') const treeProps = { children: 'children', label: 'label', disabled: 'disabled' } const treeData = ref([]) +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' +const MAX_DATE_RANGE_HOURS = 8 +const MAX_DATE_RANGE_MS = MAX_DATE_RANGE_HOURS * 60 * 60 * 1000 +const lastValidDateRange = new Map() + +const disableFutureDate = (date: Date) => { + return dayjs(date).isAfter(dayjs(), 'day') +} + const buildDefaultDateRange = (): [string, string] => { const end = dayjs() const start = end.subtract(2, 'hour') - return [start.format('YYYY-MM-DD HH:mm:ss'), end.format('YYYY-MM-DD HH:mm:ss')] + return [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)] } -const dateShortcuts = [ - { - text: t('DataCollection.DeviceParamAnalysis.shortcutLast7Days'), - value: () => { - const end = dayjs().endOf('day').toDate() - const start = dayjs().subtract(6, 'day').startOf('day').toDate() - return [start, end] - } - }, - { - text: t('DataCollection.DeviceParamAnalysis.shortcutLastWeek'), - value: () => { - const start = dayjs().subtract(1, 'week').startOf('week').toDate() - const end = dayjs().subtract(1, 'week').endOf('week').toDate() - return [start, end] - } - }, - { - text: t('DataCollection.DeviceParamAnalysis.shortcutLastMonth'), - value: () => { - const start = dayjs().subtract(1, 'month').startOf('month').toDate() - const end = dayjs().subtract(1, 'month').endOf('month').toDate() - return [start, end] - } - }, - { - text: t('DataCollection.DeviceParamAnalysis.shortcutLast3Months'), +const createLastHoursShortcut = (hours: number) => { + return { + text: `最近${hours}小时`, value: () => { - const end = dayjs().endOf('day').toDate() - const start = dayjs().subtract(3, 'month').startOf('day').toDate() + const end = dayjs().toDate() + const start = dayjs().subtract(hours, 'hour').toDate() return [start, end] } } +} + +const dateShortcuts = [ + createLastHoursShortcut(1), + createLastHoursShortcut(2), + createLastHoursShortcut(4), + createLastHoursShortcut(8) ] type ChartState = 'idle' | 'loading' | 'empty' | 'ready' @@ -346,10 +342,78 @@ const loadTree = async () => { } } +const normalizeDateRangeValue = (value: any): [string, string] | undefined => { + if (!Array.isArray(value) || value.length !== 2) return undefined + const start = value[0] + const end = value[1] + if (!start || !end) return undefined + return [String(start), String(end)] +} + +const ensureDateRangeWithin8Hours = (group: SelectedGroup, dateRange: [string, string]) => { + const now = dayjs() + let start = dayjs(dateRange[0]) + let end = dayjs(dateRange[1]) + if (!start.isValid() || !end.isValid()) return dateRange + + if (start.isAfter(now) && end.isAfter(now)) { + end = now + start = now.subtract(2, 'hour') + } else { + if (end.isAfter(now)) end = now + if (start.isAfter(now)) start = end.subtract(2, 'hour') + } + + const diffMs = end.valueOf() - start.valueOf() + if (diffMs < 0) { + end = now + start = now.subtract(2, 'hour') + const nextRange: [string, string] = [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)] + return nextRange + } + if (diffMs <= MAX_DATE_RANGE_MS) { + return [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)] + } + const clampedEnd = start.add(MAX_DATE_RANGE_HOURS, 'hour') + const finalEnd = clampedEnd.isAfter(now) ? now : clampedEnd + return [start.format(DATE_TIME_FORMAT), finalEnd.format(DATE_TIME_FORMAT)] +} + const ensureDateRange = (group: SelectedGroup) => { if (!group.dateRange || group.dateRange.length !== 2) { group.dateRange = buildDefaultDateRange() + lastValidDateRange.set(group.id, group.dateRange) + return + } + const normalized = normalizeDateRangeValue(group.dateRange) + if (!normalized) { + group.dateRange = buildDefaultDateRange() + lastValidDateRange.set(group.id, group.dateRange) + return + } + const nextRange = ensureDateRangeWithin8Hours(group, normalized) + group.dateRange = nextRange + lastValidDateRange.set(group.id, nextRange) +} + +const handleDateRangeChange = (group: SelectedGroup, value: any) => { + const normalized = normalizeDateRangeValue(value) || normalizeDateRangeValue(group.dateRange) + if (!normalized) return + + const now = dayjs() + const selectedStart = dayjs(normalized[0]) + const selectedEnd = dayjs(normalized[1]) + const hasFuture = (selectedStart.isValid() && selectedStart.isAfter(now)) || (selectedEnd.isValid() && selectedEnd.isAfter(now)) + + const nextRange = ensureDateRangeWithin8Hours(group, normalized) + const isClamped = nextRange[0] !== normalized[0] || nextRange[1] !== normalized[1] + if (hasFuture) { + message.warning('不能选择未来日期') + } else if (isClamped) { + message.warning('时间范围最多只能选择 8 小时') } + group.dateRange = nextRange + lastValidDateRange.set(group.id, nextRange) } const resetChartData = (group: SelectedGroup) => { @@ -536,6 +600,7 @@ const syncGroupsByCheckedNodes = (checkedNodes: DeviceTreeNode[]) => { chartRenderKey: 0 } selectedGroups.value.push(group) + lastValidDateRange.set(group.id, group.dateRange) addedGroups.push(group) } return addedGroups