From f53f63e67919d0c74cd65054c9ff15a8f1d6d8ab Mon Sep 17 00:00:00 2001 From: 2256907009 <2256907009@qq.com> Date: Wed, 15 Apr 2026 18:38:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=99=9A=E6=8B=9F=E6=9C=BA=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E7=9B=91=E6=8E=A7=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/user-vm/UserVmDetail.vue | 77 +++++++++++++++----- src/views/virtualization/HostDetail.vue | 96 +++++++++++++++---------- src/views/virtualization/VmDetail.vue | 79 ++++++++++++++------ 3 files changed, 174 insertions(+), 78 deletions(-) diff --git a/src/views/user-vm/UserVmDetail.vue b/src/views/user-vm/UserVmDetail.vue index 6d3673d..e20df1d 100644 --- a/src/views/user-vm/UserVmDetail.vue +++ b/src/views/user-vm/UserVmDetail.vue @@ -336,12 +336,19 @@

监控指标

-
- - - - - +
+ + 粒度: {{ currentIntervalLabel }} 刷新
@@ -1917,7 +1924,43 @@ let netChart = null const metricsData = ref(null) const metricsLoading = ref(false) -const monitorInterval = ref('1m') + +const makeDefaultRange = () => { + const now = new Date() + return [new Date(now.getTime() - 10 * 60 * 1000), now] +} +const monitorDateRange = ref(makeDefaultRange()) + +const monitorShortcuts = [ + { text: '最近10分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 10 * 60000), n] } }, + { text: '最近30分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 30 * 60000), n] } }, + { text: '最近1小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 3600000), n] } }, + { text: '最近6小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 6 * 3600000), n] } }, + { text: '最近12小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 12 * 3600000), n] } }, + { text: '最近1天', value: () => { const n = new Date(); return [new Date(n.getTime() - 86400000), n] } }, + { text: '最近7天', value: () => { const n = new Date(); return [new Date(n.getTime() - 7 * 86400000), n] } }, +] + +function calcInterval(startTime, endTime) { + const spanMin = (endTime.getTime() - startTime.getTime()) / 60000 + if (spanMin < 30) return '1m' + if (spanMin < 60) return '3m' + if (spanMin < 360) return '5m' + if (spanMin < 720) return '15m' + if (spanMin < 1440) return '30m' + if (spanMin < 4320) return '1h' + if (spanMin < 10080) return '2h' + if (spanMin < 43200) return '6h' + if (spanMin < 129600) return '12h' + return '1d' +} + +const intervalLabelMap = { '1m': '1分钟', '3m': '3分钟', '5m': '5分钟', '15m': '15分钟', '30m': '30分钟', '1h': '1小时', '2h': '2小时', '6h': '6小时', '12h': '12小时', '1d': '1天' } +const currentIntervalLabel = computed(() => { + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return '-' + const iv = calcInterval(new Date(monitorDateRange.value[0]), new Date(monitorDateRange.value[1])) + return intervalLabelMap[iv] || iv +}) const latestMetrics = computed(() => { const arr = metricsData.value @@ -1960,20 +2003,16 @@ const vmMemPercent = (m) => { const loadMetricsHistory = async () => { if (!userGoodsId.value) return + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return metricsLoading.value = true try { - const now = new Date() - let startTime = new Date(now) - const interval = monitorInterval.value - switch (interval) { - case '1m': startTime.setHours(now.getHours() - 1); break - case '5m': startTime.setHours(now.getHours() - 6); break - case '1h': startTime.setDate(now.getDate() - 1); break - } + const startTime = new Date(monitorDateRange.value[0]) + const endTime = new Date(monitorDateRange.value[1]) + const interval = calcInterval(startTime, endTime) const params = { user_goods_id: userGoodsId.value, start: startTime.toISOString(), - end_time: now.toISOString(), + end_time: endTime.toISOString(), interval } const res = await getUserVmMetricsHistory(params) @@ -1996,7 +2035,9 @@ const renderMetricsCharts = () => { const metrics = metricsData.value if (!Array.isArray(metrics) || !metrics.length) return - const showDate = monitorInterval.value === '1h' + const spanMs = monitorDateRange.value ? (new Date(monitorDateRange.value[1]).getTime() - new Date(monitorDateRange.value[0]).getTime()) : 600000 + const showDate = spanMs >= 86400000 + const symbolType = metrics.length < 30 ? 'circle' : 'none' const labelRotate = showDate ? 45 : 0 const times = metrics.map(m => { @@ -2014,7 +2055,7 @@ const renderMetricsCharts = () => { const baseGrid = { top: 10, right: 16, bottom: showDate ? 40 : 24, left: 50 } const makeXAxis = () => ({ type: 'category', data: times, boundaryGap: false, axisLabel: { fontSize: 10, rotate: labelRotate } }) - const makeSeries = (name, data, color) => ({ name, type: 'line', smooth: true, symbol: 'none', areaStyle: { opacity: 0.15 }, lineStyle: { width: 2, color }, itemStyle: { color }, data }) + const makeSeries = (name, data, color) => ({ name, type: 'line', smooth: true, symbol: symbolType, areaStyle: { opacity: 0.15 }, lineStyle: { width: 2, color }, itemStyle: { color }, data }) if (cpuChartRef.value) { if (!cpuChart) cpuChart = echarts.init(cpuChartRef.value) diff --git a/src/views/virtualization/HostDetail.vue b/src/views/virtualization/HostDetail.vue index d6f6320..979fb67 100644 --- a/src/views/virtualization/HostDetail.vue +++ b/src/views/virtualization/HostDetail.vue @@ -137,10 +137,19 @@

监控指标

-
- - - +
+ + 粒度: {{ currentIntervalLabel }} 刷新
@@ -710,46 +719,57 @@ const latestMetrics = computed(() => { return arr[arr.length - 1] }) -// 历史指标时间范围 -const historyTimeRange = ref('1m') // 1m, 5m, 1h, 1d -const historyTimeOptions = [ - { label: '最近1分钟', value: '1m' }, - { label: '最近5分钟', value: '5m' }, - { label: '最近1小时', value: '1h' }, - { label: '最近1天', value: '1d' }, +const makeDefaultRange = () => { + const now = new Date() + return [new Date(now.getTime() - 10 * 60 * 1000), now] +} +const monitorDateRange = ref(makeDefaultRange()) + +const monitorShortcuts = [ + { text: '最近10分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 10 * 60000), n] } }, + { text: '最近30分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 30 * 60000), n] } }, + { text: '最近1小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 3600000), n] } }, + { text: '最近6小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 6 * 3600000), n] } }, + { text: '最近12小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 12 * 3600000), n] } }, + { text: '最近1天', value: () => { const n = new Date(); return [new Date(n.getTime() - 86400000), n] } }, + { text: '最近7天', value: () => { const n = new Date(); return [new Date(n.getTime() - 7 * 86400000), n] } }, ] -// 加载历史指标数据 +function calcInterval(startTime, endTime) { + const spanMin = (endTime.getTime() - startTime.getTime()) / 60000 + if (spanMin < 30) return '1m' + if (spanMin < 60) return '3m' + if (spanMin < 360) return '5m' + if (spanMin < 720) return '15m' + if (spanMin < 1440) return '30m' + if (spanMin < 4320) return '1h' + if (spanMin < 10080) return '2h' + if (spanMin < 43200) return '6h' + if (spanMin < 129600) return '12h' + return '1d' +} + +const intervalLabelMap = { '1m': '1分钟', '3m': '3分钟', '5m': '5分钟', '15m': '15分钟', '30m': '30分钟', '1h': '1小时', '2h': '2小时', '6h': '6小时', '12h': '12小时', '1d': '1天' } +const currentIntervalLabel = computed(() => { + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return '-' + const iv = calcInterval(new Date(monitorDateRange.value[0]), new Date(monitorDateRange.value[1])) + return intervalLabelMap[iv] || iv +}) + const loadHistoricalMetrics = async () => { if (!serviceId.value || !hostId.value) return - + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return historicalMetricsLoading.value = true try { - // 计算时间范围 - const now = new Date() - let startTime = new Date() - - switch (historyTimeRange.value) { - case '1m': - startTime.setMinutes(now.getMinutes() - 1) - break - case '5m': - startTime.setMinutes(now.getMinutes() - 5) - break - case '1h': - startTime.setHours(now.getHours() - 1) - break - case '1d': - startTime.setDate(now.getDate() - 1) - break - } - + const startTime = new Date(monitorDateRange.value[0]) + const endTime = new Date(monitorDateRange.value[1]) + const interval = calcInterval(startTime, endTime) const params = { service_id: serviceId.value, host_id: hostId.value, start: startTime.toISOString(), - end_time: now.toISOString(), - interval: { '1m': '1m', '5m': '5m', '1h': '1h', '1d': '1d' }[historyTimeRange.value] || '5m' + end_time: endTime.toISOString(), + interval } const res = await getMetricsHistory(params) @@ -782,14 +802,14 @@ const renderHistoricalCharts = () => { const metrics = historicalMetricsData.value if (!Array.isArray(metrics) || !metrics.length) return - const range = historyTimeRange.value - const showDate = range === '7d' || range === '24h' - const symbolType = range === '7d' ? 'circle' : 'none' + const spanMs = monitorDateRange.value ? (new Date(monitorDateRange.value[1]).getTime() - new Date(monitorDateRange.value[0]).getTime()) : 0 + const showDate = spanMs >= 12 * 3600 * 1000 + const symbolType = spanMs >= 7 * 86400 * 1000 ? 'circle' : 'none' const labelRotate = showDate ? 45 : 0 const times = metrics.map(m => { const date = new Date(m.bucket) - if (range === '7d') return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) + if (showDate) return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) return date.toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit' }) }) diff --git a/src/views/virtualization/VmDetail.vue b/src/views/virtualization/VmDetail.vue index b78dbee..9a58e7c 100644 --- a/src/views/virtualization/VmDetail.vue +++ b/src/views/virtualization/VmDetail.vue @@ -538,10 +538,19 @@

监控指标

-
- - - +
+ + 粒度: {{ currentIntervalLabel }} 刷新
@@ -1657,14 +1666,44 @@ let isPageActive = false const historicalMetricsData = ref(null) const historicalMetricsLoading = ref(false) -const historyTimeRange = ref('1h') -const historyTimeOptions = [ - { label: '最近1分钟', value: '1m' }, - { label: '最近5分钟', value: '5m' }, - { label: '最近1小时', value: '1h' }, - { label: '最近1天', value: '1d' } + +const makeDefaultRange = () => { + const now = new Date() + return [new Date(now.getTime() - 10 * 60 * 1000), now] +} +const monitorDateRange = ref(makeDefaultRange()) + +const monitorShortcuts = [ + { text: '最近10分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 10 * 60000), n] } }, + { text: '最近30分钟', value: () => { const n = new Date(); return [new Date(n.getTime() - 30 * 60000), n] } }, + { text: '最近1小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 3600000), n] } }, + { text: '最近6小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 6 * 3600000), n] } }, + { text: '最近12小时', value: () => { const n = new Date(); return [new Date(n.getTime() - 12 * 3600000), n] } }, + { text: '最近1天', value: () => { const n = new Date(); return [new Date(n.getTime() - 86400000), n] } }, + { text: '最近7天', value: () => { const n = new Date(); return [new Date(n.getTime() - 7 * 86400000), n] } }, ] +function calcInterval(startTime, endTime) { + const spanMin = (endTime.getTime() - startTime.getTime()) / 60000 + if (spanMin < 30) return '1m' + if (spanMin < 60) return '3m' + if (spanMin < 360) return '5m' + if (spanMin < 720) return '15m' + if (spanMin < 1440) return '30m' + if (spanMin < 4320) return '1h' + if (spanMin < 10080) return '2h' + if (spanMin < 43200) return '6h' + if (spanMin < 129600) return '12h' + return '1d' +} + +const intervalLabelMap = { '1m': '1分钟', '3m': '3分钟', '5m': '5分钟', '15m': '15分钟', '30m': '30分钟', '1h': '1小时', '2h': '2小时', '6h': '6小时', '12h': '12小时', '1d': '1天' } +const currentIntervalLabel = computed(() => { + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return '-' + const iv = calcInterval(new Date(monitorDateRange.value[0]), new Date(monitorDateRange.value[1])) + return intervalLabelMap[iv] || iv +}) + const latestMetrics = computed(() => { const arr = historicalMetricsData.value if (!Array.isArray(arr) || !arr.length) return null @@ -1704,23 +1743,19 @@ const vmMemPercent = (m) => { const loadHistoricalMetrics = async () => { if (!serviceId.value || !detail.value?.name) return + if (!monitorDateRange.value || monitorDateRange.value.length < 2) return historicalMetricsLoading.value = true try { - const now = new Date() - let startTime = new Date() - switch (historyTimeRange.value) { - case '1m': startTime.setMinutes(now.getMinutes() - 1); break - case '5m': startTime.setMinutes(now.getMinutes() - 5); break - case '1h': startTime.setHours(now.getHours() - 1); break - case '1d': startTime.setDate(now.getDate() - 1); break - } + const startTime = new Date(monitorDateRange.value[0]) + const endTime = new Date(monitorDateRange.value[1]) + const interval = calcInterval(startTime, endTime) const params = { service_id: serviceId.value, host_id: vmHostId.value, vm_name: detail.value.name, start: startTime.toISOString(), - end_time: now.toISOString(), - interval: { '1m': '1m', '5m': '5m', '1h': '1h', '1d': '1d' }[historyTimeRange.value] || '5m' + end_time: endTime.toISOString(), + interval } const res = await getMetricsHistory(params) const body = res?.data @@ -1742,8 +1777,8 @@ const renderHistoricalCharts = () => { const metrics = historicalMetricsData.value if (!Array.isArray(metrics) || !metrics.length) return - const range = historyTimeRange.value - const showDate = range === '1d' + const spanMs = monitorDateRange.value ? (new Date(monitorDateRange.value[1]).getTime() - new Date(monitorDateRange.value[0]).getTime()) : 0 + const showDate = spanMs >= 12 * 3600 * 1000 const symbolType = showDate ? 'circle' : 'none' const labelRotate = showDate ? 45 : 0