fix
This commit is contained in:
@@ -119,6 +119,11 @@ export interface HostMetricsDiskMount {
|
||||
export interface HostMetricsCpuCard {
|
||||
usage_percent: number
|
||||
logical_cores_total: number
|
||||
socket_count?: number
|
||||
physical_cores_total?: number
|
||||
physical_threads_total?: number
|
||||
cores_per_socket?: number
|
||||
threads_per_core?: number
|
||||
}
|
||||
|
||||
export interface HostMetricsSummary {
|
||||
@@ -163,3 +168,82 @@ export const fetchServerNetworkTraffic = (serverIdentity: string, hours = 6) =>
|
||||
{ params: { server_identity: serverIdentity, hours } },
|
||||
)
|
||||
}
|
||||
|
||||
/** 虚拟机资产概览 */
|
||||
export interface VirtualOverviewPayload {
|
||||
vm_total: number
|
||||
asset_group_total: number
|
||||
online_total: number
|
||||
latest_timestamp?: string
|
||||
latest_cpu_usage_avg?: number
|
||||
latest_mem_usage_avg?: number
|
||||
}
|
||||
|
||||
/** 物理机 24h 趋势点 */
|
||||
export interface PhysicalUsagePoint {
|
||||
hour: string
|
||||
cpu_used_percent_avg: number | null
|
||||
mem_used_percent_avg: number | null
|
||||
}
|
||||
|
||||
export interface PhysicalUsageTrendPayload {
|
||||
hours: number
|
||||
points: PhysicalUsagePoint[]
|
||||
}
|
||||
|
||||
/** 资源总量项 */
|
||||
export interface ResourceTotalGroup {
|
||||
server_type: 'physical' | 'virtual'
|
||||
server_count: number
|
||||
total_vcpu: number
|
||||
total_mem_bytes: number
|
||||
}
|
||||
|
||||
/** 最新资源总量汇总 */
|
||||
export interface LatestResourceSummaryPayload {
|
||||
physical: ResourceTotalGroup
|
||||
virtual: ResourceTotalGroup
|
||||
}
|
||||
|
||||
/** 按资产聚合项 */
|
||||
export interface AssetMixedSummaryItem {
|
||||
asset_id: number
|
||||
virtual_count: number
|
||||
physical_count: number
|
||||
physical_latest_cpu_usage?: number | null
|
||||
physical_latest_mem_usage?: number | null
|
||||
}
|
||||
|
||||
export interface AssetMixedSummaryPayload {
|
||||
total: number
|
||||
data: AssetMixedSummaryItem[]
|
||||
}
|
||||
|
||||
/** 接口1:虚拟机资产概览(支持分类筛选) */
|
||||
export const fetchVirtualOverview = (category?: string) => {
|
||||
return request.get<{ code: number; details?: VirtualOverviewPayload; message?: string }>(
|
||||
'/DC-Control/v1/servers/assets/virtual/overview',
|
||||
{ params: { category } },
|
||||
)
|
||||
}
|
||||
|
||||
/** 接口2:physical 近24小时 CPU/内存趋势 */
|
||||
export const fetchPhysicalUsageTrend24h = () => {
|
||||
return request.get<{ code: number; details?: PhysicalUsageTrendPayload; message?: string }>(
|
||||
'/DC-Control/v1/servers/physical/usage/trend-24h',
|
||||
)
|
||||
}
|
||||
|
||||
/** 接口3:physical/virtual 最新资源总量 */
|
||||
export const fetchLatestResourceSummary = () => {
|
||||
return request.get<{ code: number; details?: LatestResourceSummaryPayload; message?: string }>(
|
||||
'/DC-Control/v1/servers/resources/latest/summary',
|
||||
)
|
||||
}
|
||||
|
||||
/** 接口4:按资产汇总 virtual 数量与 physical 最新指标 */
|
||||
export const fetchAssetMixedSummary = () => {
|
||||
return request.get<{ code: number; details?: AssetMixedSummaryPayload; message?: string }>(
|
||||
'/DC-Control/v1/servers/assets/mixed/summary',
|
||||
)
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ const resourcePanels = computed<OsResourcePanel[]>(() => {
|
||||
sysPanel = { ...defaultResourcePanels[1] }
|
||||
}
|
||||
|
||||
const cores = d.cpu?.logical_cores_total ?? 0
|
||||
const cores = d.cpu?.physical_threads_total ?? d.cpu?.logical_cores_total ?? 0
|
||||
const usage = d.cpu?.usage_percent ?? 0
|
||||
const usedCores = cores > 0 ? (usage / 100) * cores : 0
|
||||
const freeCores = cores > 0 ? Math.max(0, cores - usedCores) : 0
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="stats-info">
|
||||
<div class="stats-title">虚拟机总数</div>
|
||||
<div class="stats-value">{{ stats.total }}</div>
|
||||
<div class="stats-desc">跨 8 台宿主机</div>
|
||||
<div class="stats-desc">宿主机 {{ stats.assetGroups }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="stats-info">
|
||||
<div class="stats-title">运行中</div>
|
||||
<div class="stats-value">{{ stats.running }}</div>
|
||||
<div class="stats-desc text-success">90.7%</div>
|
||||
<div class="stats-desc text-success">{{ runningRateText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -38,8 +38,8 @@
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-title">CPU使用率</div>
|
||||
<div class="stats-value">{{ stats.cpuUsage }}%</div>
|
||||
<div class="stats-desc">集群平均</div>
|
||||
<div class="stats-value">{{ statsCpuUsageText }}%</div>
|
||||
<div class="stats-desc">平均</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -52,8 +52,8 @@
|
||||
</div>
|
||||
<div class="stats-info">
|
||||
<div class="stats-title">内存使用率</div>
|
||||
<div class="stats-value">{{ stats.memoryUsage }}%</div>
|
||||
<div class="stats-desc">集群平均</div>
|
||||
<div class="stats-value">{{ statsMemoryUsageText }}%</div>
|
||||
<div class="stats-desc">平均</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -85,7 +85,7 @@
|
||||
<a-col :xs="24" :lg="8">
|
||||
<a-card title="CPU资源分配" :bordered="false">
|
||||
<template #extra>
|
||||
<span class="text-muted">集群总计 256 vCPU</span>
|
||||
<span class="text-muted">总计 {{ cpuTotalText }} vCPU</span>
|
||||
</template>
|
||||
<div class="chart-container">
|
||||
<Chart :options="cpuChartOptions" height="240px" />
|
||||
@@ -93,11 +93,11 @@
|
||||
<div class="chart-legend">
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot legend-dot-1"></span>
|
||||
<span>已分配 174 vCPU</span>
|
||||
<span>已使用 {{ cpuVirtualText }} vCPU</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot legend-dot-gray"></span>
|
||||
<span>可用 82 vCPU</span>
|
||||
<span>总计 {{ cpuPhysicalText }} vCPU</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -105,7 +105,7 @@
|
||||
<a-col :xs="24" :lg="8">
|
||||
<a-card title="内存资源分配" :bordered="false">
|
||||
<template #extra>
|
||||
<span class="text-muted">集群总计 512 GB</span>
|
||||
<span class="text-muted">总计 {{ memoryTotalText }} GB</span>
|
||||
</template>
|
||||
<div class="chart-container">
|
||||
<Chart :options="memoryChartOptions" height="240px" />
|
||||
@@ -113,11 +113,11 @@
|
||||
<div class="chart-legend">
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot legend-dot-2"></span>
|
||||
<span>已使用 384 GB</span>
|
||||
<span>已使用 {{ memoryVirtualText }} GB</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot legend-dot-gray"></span>
|
||||
<span>可用 128 GB</span>
|
||||
<span>总计 {{ memoryPhysicalText }} GB</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -130,7 +130,9 @@
|
||||
<a-card class="host-card" :bordered="false">
|
||||
<div class="host-header">
|
||||
<span class="host-name">{{ host.name }}</span>
|
||||
<a-tag color="green" size="small">在线</a-tag>
|
||||
<a-tag :color="host.physicalCount > 0 ? 'green' : 'gray'" size="small">
|
||||
{{ host.physicalCount > 0 ? '有物理机' : '仅虚拟机' }}
|
||||
</a-tag>
|
||||
</div>
|
||||
<div class="host-metrics">
|
||||
<div class="metric-item">
|
||||
@@ -151,253 +153,58 @@
|
||||
<span class="metric-label">虚拟机数</span>
|
||||
<span class="metric-value-right">{{ host.vmCount }}</span>
|
||||
</div>
|
||||
<div class="metric-item metric-vm">
|
||||
<span class="metric-label">物理机数</span>
|
||||
<span class="metric-value-right">{{ host.physicalCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<!-- 虚拟机列表 -->
|
||||
<a-card title="虚拟机列表" :bordered="false">
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-select v-model="filterHost" placeholder="全部宿主机" style="width: 130px">
|
||||
<a-option value="">全部宿主机</a-option>
|
||||
<a-option value="ESXi-01">ESXi-01</a-option>
|
||||
<a-option value="ESXi-02">ESXi-02</a-option>
|
||||
<a-option value="ESXi-03">ESXi-03</a-option>
|
||||
<a-option value="ESXi-04">ESXi-04</a-option>
|
||||
</a-select>
|
||||
<a-select v-model="filterStatus" placeholder="全部状态" style="width: 120px">
|
||||
<a-option value="">全部状态</a-option>
|
||||
<a-option value="running">运行中</a-option>
|
||||
<a-option value="stopped">已停止</a-option>
|
||||
<a-option value="warning">异常</a-option>
|
||||
</a-select>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-table
|
||||
:data="filteredVMs"
|
||||
:columns="columns"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
row-key="name"
|
||||
>
|
||||
<!-- 状态列 -->
|
||||
<template #status="{ record }">
|
||||
<a-tag :color="getStatusColor(record.statusValue)" bordered>
|
||||
{{ record.statusText }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<!-- CPU列 -->
|
||||
<template #cpu="{ record }">
|
||||
<div class="progress-cell">
|
||||
<a-progress
|
||||
:percent="record.cpu / 100"
|
||||
:stroke-width="6"
|
||||
:show-text="false"
|
||||
:status="getProgressStatus(record.cpu)"
|
||||
/>
|
||||
<span class="progress-text">{{ record.cpu }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 内存列 -->
|
||||
<template #memory="{ record }">
|
||||
<div class="progress-cell">
|
||||
<a-progress
|
||||
:percent="record.memory / 100"
|
||||
:stroke-width="6"
|
||||
:show-text="false"
|
||||
:status="getProgressStatus(record.memory)"
|
||||
/>
|
||||
<span class="progress-text">{{ record.memory }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 存储列 -->
|
||||
<template #storage="{ record }">
|
||||
<div class="progress-cell">
|
||||
<a-progress
|
||||
:percent="record.storage / 100"
|
||||
:stroke-width="6"
|
||||
:show-text="false"
|
||||
:status="getProgressStatus(record.storage)"
|
||||
/>
|
||||
<span class="progress-text">{{ record.storage }}%</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
<!-- 虚拟机列表模块按需求下线(暂不渲染) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import {
|
||||
IconStorage,
|
||||
IconCheckCircleFill,
|
||||
IconCodeSquare,
|
||||
IconDriveFile,
|
||||
} from '@arco-design/web-vue/es/icon'
|
||||
import Breadcrumb from '@/components/breadcrumb/index.vue'
|
||||
import Chart from '@/components/chart/index.vue'
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'
|
||||
import {
|
||||
fetchAssetMixedSummary,
|
||||
fetchLatestResourceSummary,
|
||||
fetchPhysicalUsageTrend24h,
|
||||
fetchVirtualOverview,
|
||||
type AssetMixedSummaryItem,
|
||||
} from '@/api/ops/server'
|
||||
|
||||
// 统计数据
|
||||
const stats = ref({
|
||||
total: 86,
|
||||
running: 78,
|
||||
cpuUsage: 68,
|
||||
memoryUsage: 75,
|
||||
total: 0,
|
||||
assetGroups: 0,
|
||||
running: 0,
|
||||
cpuUsage: 0,
|
||||
memoryUsage: 0,
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const filterHost = ref('')
|
||||
const filterStatus = ref('')
|
||||
|
||||
// 表格列配置
|
||||
const columns: TableColumnData[] = [
|
||||
{
|
||||
title: '虚拟机名称',
|
||||
dataIndex: 'name',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
title: '宿主机',
|
||||
dataIndex: 'host',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '操作系统',
|
||||
dataIndex: 'os',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
slotName: 'status',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: 'CPU使用率',
|
||||
dataIndex: 'cpu',
|
||||
slotName: 'cpu',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '内存使用率',
|
||||
dataIndex: 'memory',
|
||||
slotName: 'memory',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '存储使用率',
|
||||
dataIndex: 'storage',
|
||||
slotName: 'storage',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '网络流量',
|
||||
dataIndex: 'network',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
|
||||
// 虚拟机数据
|
||||
const vmData = ref([
|
||||
{
|
||||
name: 'VM-Web-01',
|
||||
host: 'ESXi-01',
|
||||
os: 'CentOS 7.9',
|
||||
statusValue: 'running',
|
||||
statusText: '运行中',
|
||||
cpu: 65,
|
||||
memory: 72,
|
||||
storage: 45,
|
||||
network: '1.2 Gbps',
|
||||
},
|
||||
{
|
||||
name: 'VM-DB-01',
|
||||
host: 'ESXi-01',
|
||||
os: 'Ubuntu 22.04',
|
||||
statusValue: 'running',
|
||||
statusText: '运行中',
|
||||
cpu: 85,
|
||||
memory: 88,
|
||||
storage: 78,
|
||||
network: '850 Mbps',
|
||||
},
|
||||
{
|
||||
name: 'VM-App-01',
|
||||
host: 'ESXi-02',
|
||||
os: 'Windows Server 2022',
|
||||
statusValue: 'running',
|
||||
statusText: '运行中',
|
||||
cpu: 42,
|
||||
memory: 55,
|
||||
storage: 35,
|
||||
network: '450 Mbps',
|
||||
},
|
||||
{
|
||||
name: 'VM-Cache-01',
|
||||
host: 'ESXi-02',
|
||||
os: 'CentOS 8',
|
||||
statusValue: 'warning',
|
||||
statusText: '高负载',
|
||||
cpu: 92,
|
||||
memory: 95,
|
||||
storage: 60,
|
||||
network: '2.1 Gbps',
|
||||
},
|
||||
{
|
||||
name: 'VM-Dev-01',
|
||||
host: 'ESXi-03',
|
||||
os: 'Ubuntu 20.04',
|
||||
statusValue: 'stopped',
|
||||
statusText: '已停止',
|
||||
cpu: 0,
|
||||
memory: 0,
|
||||
storage: 25,
|
||||
network: '-',
|
||||
},
|
||||
{
|
||||
name: 'VM-Test-01',
|
||||
host: 'ESXi-03',
|
||||
os: 'Debian 11',
|
||||
statusValue: 'running',
|
||||
statusText: '运行中',
|
||||
cpu: 28,
|
||||
memory: 35,
|
||||
storage: 42,
|
||||
network: '320 Mbps',
|
||||
},
|
||||
])
|
||||
|
||||
// 过滤后的虚拟机列表
|
||||
const filteredVMs = computed(() => {
|
||||
let result = vmData.value
|
||||
|
||||
if (filterHost.value) {
|
||||
result = result.filter((vm) => vm.host === filterHost.value)
|
||||
}
|
||||
|
||||
if (filterStatus.value) {
|
||||
result = result.filter((vm) => vm.statusValue === filterStatus.value)
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
// 宿主机状态
|
||||
const hostStatus = ref([
|
||||
{ name: 'ESXi-01', cpu: 65, memory: 78, vmCount: 24 },
|
||||
{ name: 'ESXi-02', cpu: 72, memory: 85, vmCount: 22 },
|
||||
{ name: 'ESXi-03', cpu: 45, memory: 52, vmCount: 18 },
|
||||
{ name: 'ESXi-04', cpu: 58, memory: 68, vmCount: 22 },
|
||||
])
|
||||
const hostStatus = ref<
|
||||
Array<{
|
||||
name: string
|
||||
cpu: number
|
||||
memory: number
|
||||
vmCount: number
|
||||
physicalCount: number
|
||||
}>
|
||||
>([])
|
||||
|
||||
// 资源使用趋势图表配置
|
||||
const performanceChartOptions = ref({
|
||||
@@ -413,7 +220,7 @@ const performanceChartOptions = ref({
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
|
||||
data: [] as string[],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
@@ -425,7 +232,7 @@ const performanceChartOptions = ref({
|
||||
name: 'CPU',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [45, 38, 72, 85, 78, 55, 42],
|
||||
data: [] as number[],
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: '#165DFF',
|
||||
@@ -438,7 +245,7 @@ const performanceChartOptions = ref({
|
||||
name: '内存',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [62, 58, 75, 82, 79, 65, 60],
|
||||
data: [] as number[],
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: '#F7BA1E',
|
||||
@@ -464,8 +271,8 @@ const cpuChartOptions = ref({
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{ value: 68, name: '已分配', itemStyle: { color: '#165DFF' } },
|
||||
{ value: 32, name: '可用', itemStyle: { color: '#E5E6EB' } },
|
||||
{ value: 0, name: 'virtual', itemStyle: { color: '#165DFF' } },
|
||||
{ value: 0, name: 'physical', itemStyle: { color: '#E5E6EB' } },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -485,34 +292,106 @@ const memoryChartOptions = ref({
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{ value: 75, name: '已使用', itemStyle: { color: '#14C9C9' } },
|
||||
{ value: 25, name: '可用', itemStyle: { color: '#E5E6EB' } },
|
||||
{ value: 0, name: 'virtual', itemStyle: { color: '#14C9C9' } },
|
||||
{ value: 0, name: 'physical', itemStyle: { color: '#E5E6EB' } },
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 获取状态颜色
|
||||
const getStatusColor = (status: string) => {
|
||||
const colorMap: Record<string, string> = {
|
||||
running: 'green',
|
||||
stopped: 'gray',
|
||||
warning: 'orange',
|
||||
}
|
||||
return colorMap[status] || 'gray'
|
||||
const cpuVirtual = ref(0)
|
||||
const cpuPhysical = ref(0)
|
||||
const memVirtualGb = ref(0)
|
||||
const memPhysicalGb = ref(0)
|
||||
|
||||
const roundToTwo = (value: number) => Math.round(value * 100) / 100
|
||||
const formatMaxTwoDecimals = (value: number) => {
|
||||
const rounded = roundToTwo(value)
|
||||
return Number.isInteger(rounded) ? String(rounded) : String(rounded)
|
||||
}
|
||||
|
||||
// 获取进度条状态
|
||||
const getProgressStatus = (value: number) => {
|
||||
if (value >= 90) return 'danger'
|
||||
if (value >= 70) return 'warning'
|
||||
return 'normal'
|
||||
const runningRateText = computed(() => {
|
||||
if (!stats.value.total) return '0%'
|
||||
return `${formatMaxTwoDecimals((stats.value.running / stats.value.total) * 100)}%`
|
||||
})
|
||||
const statsCpuUsageText = computed(() => formatMaxTwoDecimals(stats.value.cpuUsage))
|
||||
const statsMemoryUsageText = computed(() => formatMaxTwoDecimals(stats.value.memoryUsage))
|
||||
const cpuTotalText = computed(() => formatMaxTwoDecimals(cpuVirtual.value + cpuPhysical.value))
|
||||
const cpuVirtualText = computed(() => formatMaxTwoDecimals(cpuVirtual.value))
|
||||
const cpuPhysicalText = computed(() => formatMaxTwoDecimals(cpuPhysical.value))
|
||||
const memoryTotalText = computed(() => formatMaxTwoDecimals(memVirtualGb.value + memPhysicalGb.value))
|
||||
const memoryVirtualText = computed(() => formatMaxTwoDecimals(memVirtualGb.value))
|
||||
const memoryPhysicalText = computed(() => formatMaxTwoDecimals(memPhysicalGb.value))
|
||||
const toGb = (bytes: number) => bytes / 1024 / 1024 / 1024
|
||||
const safeNum = (v: number | null | undefined) => (typeof v === 'number' ? v : 0)
|
||||
const hourLabel = (v: string) => {
|
||||
const d = new Date(v)
|
||||
if (Number.isNaN(d.getTime())) return v
|
||||
return `${String(d.getHours()).padStart(2, '0')}:00`
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
const fetchData = async () => {
|
||||
// TODO: 从API获取数据
|
||||
loading.value = false
|
||||
loading.value = true
|
||||
try {
|
||||
const [overviewRes, trendRes, resourceRes, mixedRes] = await Promise.all([
|
||||
fetchVirtualOverview(),
|
||||
fetchPhysicalUsageTrend24h(),
|
||||
fetchLatestResourceSummary(),
|
||||
fetchAssetMixedSummary(),
|
||||
])
|
||||
|
||||
if (overviewRes.code !== 0 || !overviewRes.details) {
|
||||
Message.error(overviewRes.message || '加载虚拟机概览失败')
|
||||
return
|
||||
}
|
||||
const overview = overviewRes.details
|
||||
stats.value.total = overview.vm_total || 0
|
||||
stats.value.assetGroups = overview.asset_group_total || 0
|
||||
stats.value.running = overview.online_total || 0
|
||||
stats.value.cpuUsage = roundToTwo(safeNum(overview.latest_cpu_usage_avg))
|
||||
stats.value.memoryUsage = roundToTwo(safeNum(overview.latest_mem_usage_avg))
|
||||
|
||||
if (trendRes.code === 0 && trendRes.details?.points) {
|
||||
const labels = trendRes.details.points.map((p) => hourLabel(p.hour))
|
||||
const cpuSeries = trendRes.details.points.map((p) => roundToTwo(safeNum(p.cpu_used_percent_avg)))
|
||||
const memSeries = trendRes.details.points.map((p) => roundToTwo(safeNum(p.mem_used_percent_avg)))
|
||||
;(performanceChartOptions.value.xAxis as { data: string[] }).data = labels
|
||||
;(performanceChartOptions.value.series[0] as { data: number[] }).data = cpuSeries
|
||||
;(performanceChartOptions.value.series[1] as { data: number[] }).data = memSeries
|
||||
}
|
||||
|
||||
if (resourceRes.code === 0 && resourceRes.details) {
|
||||
cpuVirtual.value = roundToTwo(safeNum(resourceRes.details.virtual?.total_vcpu))
|
||||
cpuPhysical.value = roundToTwo(safeNum(resourceRes.details.physical?.total_vcpu))
|
||||
memVirtualGb.value = roundToTwo(toGb(safeNum(resourceRes.details.virtual?.total_mem_bytes)))
|
||||
memPhysicalGb.value = roundToTwo(toGb(safeNum(resourceRes.details.physical?.total_mem_bytes)))
|
||||
;(cpuChartOptions.value.series[0] as { data: Array<{ value: number; name: string }> }).data = [
|
||||
{ value: cpuVirtual.value, name: 'virtual' },
|
||||
{ value: cpuPhysical.value, name: 'physical' },
|
||||
]
|
||||
;(memoryChartOptions.value.series[0] as { data: Array<{ value: number; name: string }> }).data = [
|
||||
{ value: memVirtualGb.value, name: 'virtual' },
|
||||
{ value: memPhysicalGb.value, name: 'physical' },
|
||||
]
|
||||
}
|
||||
|
||||
if (mixedRes.code === 0 && mixedRes.details?.data) {
|
||||
hostStatus.value = (mixedRes.details.data as AssetMixedSummaryItem[]).map((item) => ({
|
||||
name: `Asset-${item.asset_id}`,
|
||||
cpu: Number(safeNum(item.physical_latest_cpu_usage).toFixed(2)),
|
||||
memory: Number(safeNum(item.physical_latest_mem_usage).toFixed(2)),
|
||||
vmCount: item.virtual_count || 0,
|
||||
physicalCount: item.physical_count || 0,
|
||||
}))
|
||||
} else {
|
||||
hostStatus.value = []
|
||||
}
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || '加载虚拟化监控数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
|
||||
Reference in New Issue
Block a user