修复 空数据时页面组件不显示
This commit is contained in:
@@ -162,6 +162,13 @@ export const fetchServerMetricsSummary = (serverIdentity: string) => {
|
||||
})
|
||||
}
|
||||
|
||||
/** 立即拉取一次主机指标并返回最新统计卡片 */
|
||||
export const collectServerMetricsNow = (serverIdentity: string) => {
|
||||
return request.post<{ code: number; details?: HostMetricsSummary; message?: string }>('/DC-Control/v1/servers/metrics/collect', {
|
||||
server_identity: serverIdentity,
|
||||
})
|
||||
}
|
||||
|
||||
/** 近 N 小时网络收/发速率(Mbps,相邻采样字节差分) */
|
||||
export const fetchServerNetworkTraffic = (serverIdentity: string, hours = 6) => {
|
||||
return request.get<{ code: number; details?: HostNetworkTrafficPayload; message?: string }>(
|
||||
|
||||
@@ -120,6 +120,12 @@
|
||||
<icon-down />
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption :disabled="isCollecting(record) || !record.server_identity" @click="handleCollectNow(record)">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
{{ isCollecting(record) ? '采集中' : '立即采集' }}
|
||||
</a-doption>
|
||||
<a-doption @click="handleQuickConfig(record)">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
@@ -200,13 +206,7 @@ import ServerFormDialog from './components/ServerFormDialog.vue'
|
||||
import QuickConfigDialog from './components/QuickConfigDialog.vue'
|
||||
import HardwareDeviceConfigDialog from './components/HardwareDeviceConfigDialog.vue'
|
||||
import { columns as columnsConfig } from './config/columns'
|
||||
import { fetchServerList, deleteServer } from '@/api/ops/server'
|
||||
import axios from 'axios'
|
||||
|
||||
// 创建独立的 axios 实例用于请求外部 agent,绕过全局拦截器
|
||||
const agentAxios = axios.create({
|
||||
timeout: 5000,
|
||||
})
|
||||
import { fetchServerList, deleteServer, fetchServerMetricsSummary, collectServerMetricsNow, type HostMetricsSummary } from '@/api/ops/server'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -217,6 +217,7 @@ const formDialogVisible = ref(false)
|
||||
const quickConfigVisible = ref(false)
|
||||
const hardwareConfigVisible = ref(false)
|
||||
const currentRecord = ref<any>(null)
|
||||
const collectingMap = reactive<Record<string, boolean>>({})
|
||||
const formModel = ref({
|
||||
keyword: '',
|
||||
collect_on: undefined as boolean | undefined,
|
||||
@@ -394,6 +395,13 @@ const handleHardwareConfigSuccess = () => {
|
||||
fetchServers()
|
||||
}
|
||||
|
||||
const getCollectingKey = (record: any) => record.server_identity || String(record.id || '')
|
||||
|
||||
const isCollecting = (record: any) => {
|
||||
const key = getCollectingKey(record)
|
||||
return !!collectingMap[key]
|
||||
}
|
||||
|
||||
// 编辑服务器
|
||||
const handleEdit = (record: any) => {
|
||||
currentRecord.value = record
|
||||
@@ -465,74 +473,86 @@ const handleDelete = async (record: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
/** dc-host `GET agent_config`(一般为 `/dc-host/stats`)返回裸 Metrics JSON */
|
||||
// 获取所有服务器的监控指标
|
||||
const resetMetrics = (record: any) => {
|
||||
record.cpu_info = { value: 0, total: '', used: '' }
|
||||
record.memory_info = { value: 0, total: '', used: '' }
|
||||
record.disk_info = { value: 0, total: '', used: '' }
|
||||
}
|
||||
|
||||
const applyMetricsSummary = (record: any, summary?: HostMetricsSummary) => {
|
||||
if (!summary || !summary.has_data) {
|
||||
resetMetrics(record)
|
||||
return
|
||||
}
|
||||
record.cpu_info = {
|
||||
value: Number((summary.cpu?.usage_percent || 0).toFixed(2)),
|
||||
total: summary.cpu?.logical_cores_total ? `${summary.cpu.logical_cores_total}核` : '',
|
||||
used: '',
|
||||
}
|
||||
record.memory_info = {
|
||||
value: Number((summary.memory?.used_percent || 0).toFixed(2)),
|
||||
total: summary.memory?.total_bytes ? `${(summary.memory.total_bytes / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
|
||||
used: summary.memory?.used_bytes ? `${(summary.memory.used_bytes / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
|
||||
}
|
||||
record.disk_info = {
|
||||
value: Number((summary.disk_root?.used_percent || 0).toFixed(2)),
|
||||
total: summary.disk_root?.total_bytes ? `${(summary.disk_root.total_bytes / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
|
||||
used: summary.disk_root?.used_bytes ? `${(summary.disk_root.used_bytes / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
|
||||
}
|
||||
if (summary.timestamp) {
|
||||
record.last_check_time = summary.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
// 从 dc-control 获取所有服务器最新时序指标
|
||||
const getAllMetrics = async () => {
|
||||
try {
|
||||
// 遍历每个服务器记录
|
||||
const metricsPromises = tableData.value.map(async (record) => {
|
||||
// 检查是否有 agent_config 配置
|
||||
if (record.agent_config) {
|
||||
try {
|
||||
// 从 agent_config 中解析 URL
|
||||
let metricsUrl = record.agent_config
|
||||
|
||||
// 验证 URL 是否合法
|
||||
try {
|
||||
new URL(metricsUrl)
|
||||
} catch (urlError) {
|
||||
console.warn(`服务器 ${record.name} 的 agent_config 不是合法的 URL:`, metricsUrl)
|
||||
// 设置默认值 0
|
||||
record.cpu_info = { value: 0, total: '', used: '' }
|
||||
record.memory_info = { value: 0, total: '', used: '' }
|
||||
record.disk_info = { value: 0, total: '', used: '' }
|
||||
return
|
||||
}
|
||||
// 使用独立的 axios 实例请求外部 agent,绕过全局拦截器
|
||||
const response = await agentAxios.get(metricsUrl)
|
||||
console.log('获取指标数据:', response.data)
|
||||
if (response.data) {
|
||||
// 更新记录的监控数据
|
||||
record.cpu_info = {
|
||||
value: Number((response.data.cpu_usage || 0).toFixed(2)),
|
||||
total: response.data.cpu?.length ? `${response.data.cpu.length}核` : '',
|
||||
used: '',
|
||||
}
|
||||
|
||||
record.memory_info = {
|
||||
value: Number((response.data.mem_usage?.used_percent || 0).toFixed(2)),
|
||||
total: response.data.mem_usage?.total ? `${(response.data.mem_usage.total / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
|
||||
used: response.data.mem_usage?.used ? `${(response.data.mem_usage.used / 1024 / 1024 / 1024).toFixed(1)}GB` : '',
|
||||
}
|
||||
|
||||
record.disk_info = {
|
||||
value: Number((response.data.disk_usage?.used_percent || 0).toFixed(2)),
|
||||
total: response.data.disk_usage?.total ? `${(response.data.disk_usage.total / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
|
||||
used: response.data.disk_usage?.used ? `${(response.data.disk_usage.used / 1024 / 1024 / 1024).toFixed(0)}GB` : '',
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`获取服务器 ${record.name} 的监控指标失败:`, error)
|
||||
// 初始化默认值
|
||||
record.cpu_info = { value: 0, total: '', used: '' }
|
||||
record.memory_info = { value: 0, total: '', used: '' }
|
||||
record.disk_info = { value: 0, total: '', used: '' }
|
||||
}
|
||||
} else {
|
||||
// 没有配置 agent,设置默认值
|
||||
record.cpu_info = { value: 0, total: '', used: '' }
|
||||
record.memory_info = { value: 0, total: '', used: '' }
|
||||
record.disk_info = { value: 0, total: '', used: '' }
|
||||
if (!record.server_identity) {
|
||||
resetMetrics(record)
|
||||
return
|
||||
}
|
||||
try {
|
||||
const response = await fetchServerMetricsSummary(record.server_identity)
|
||||
applyMetricsSummary(record, response.details)
|
||||
} catch (error) {
|
||||
console.warn(`获取服务器 ${record.name} 的监控指标失败:`, error)
|
||||
resetMetrics(record)
|
||||
}
|
||||
})
|
||||
|
||||
// 等待所有请求完成
|
||||
await Promise.all(metricsPromises)
|
||||
} catch (error) {
|
||||
console.error('获取所有服务器监控指标失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCollectNow = async (record: any) => {
|
||||
if (!record.server_identity) {
|
||||
Message.warning('缺少服务器唯一标识,无法采集')
|
||||
return
|
||||
}
|
||||
const key = getCollectingKey(record)
|
||||
if (collectingMap[key]) {
|
||||
return
|
||||
}
|
||||
collectingMap[key] = true
|
||||
try {
|
||||
const response = await collectServerMetricsNow(record.server_identity)
|
||||
if (response.code === 0) {
|
||||
applyMetricsSummary(record, response.details)
|
||||
Message.success('采集完成')
|
||||
} else {
|
||||
Message.error(response.message || '采集失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('立即采集失败:', error)
|
||||
Message.error('采集失败')
|
||||
} finally {
|
||||
collectingMap[key] = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchServers()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user