fix: 虚拟机详情监控模块
Build and Deploy Vue3 / build (push) Successful in 1m30s
Build and Deploy Vue3 / deploy (push) Successful in 17m15s

This commit is contained in:
2026-04-15 18:38:08 +08:00
parent cae1f847e4
commit f53f63e679
3 changed files with 174 additions and 78 deletions
+59 -18
View File
@@ -336,12 +336,19 @@
<div class="section-block">
<div class="section-header">
<h3 class="section-title">监控指标</h3>
<div style="display: flex; align-items: center; gap: 8px">
<el-select v-model="monitorInterval" size="small" style="width: 120px" @change="loadMetricsHistory">
<el-option label="1分钟" value="1m" />
<el-option label="5分钟" value="5m" />
<el-option label="1小时" value="1h" />
</el-select>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
<el-date-picker
v-model="monitorDateRange"
type="datetimerange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
style="width: 360px"
:shortcuts="monitorShortcuts"
@change="loadMetricsHistory"
/>
<span style="font-size:12px;color:#909399;white-space:nowrap">粒度: {{ currentIntervalLabel }}</span>
<el-button size="small" :icon="Refresh" @click="loadMetricsHistory" :loading="metricsLoading">刷新</el-button>
</div>
</div>
@@ -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)