feat: 完善虚拟机列表信息展示
Build and Deploy Vue3 / build (push) Successful in 1m27s
Build and Deploy Vue3 / deploy (push) Successful in 59s

This commit is contained in:
shiran
2026-08-04 12:55:59 +08:00
parent d373e10097
commit f10c8fc920
2 changed files with 62 additions and 0 deletions
+45
View File
@@ -75,6 +75,25 @@
<span style="color:#909399;font-size:12px"> (ID:{{ row.userId || row.user_id || '-' }})</span>
</template>
</el-table-column>
<el-table-column label="主机名" min-width="160" show-overflow-tooltip>
<template #default="{ row }">
<span>{{ getRowVm(row)?.hostname || getRowVm(row)?.name || row.itemName || '-' }}</span>
<span v-if="row.itemId" class="vm-secondary-text"> #{{ row.itemId }}</span>
</template>
</el-table-column>
<el-table-column label="配置" min-width="210">
<template #default="{ row }">
<div v-if="getRowVm(row)" class="vm-spec-list">
<el-tag size="small" type="info">{{ getRowVm(row).vcpu || 0 }} </el-tag>
<el-tag size="small" type="info">{{ formatMemory(getRowVm(row).memory) }}</el-tag>
<el-tag v-if="getRowVm(row).system_size" size="small" type="info">{{ getRowVm(row).system_size }} GB </el-tag>
</div>
<span v-else class="vm-secondary-text">-</span>
</template>
</el-table-column>
<el-table-column label="IP 地址" min-width="200" show-overflow-tooltip>
<template #default="{ row }">{{ formatVmIps(getRowVm(row)) || '-' }}</template>
</el-table-column>
<el-table-column label="绑定状态" width="90">
<template #default="{ row }">
<el-tag :type="row.itemId ? 'success' : 'info'" size="small">
@@ -972,6 +991,29 @@ const formatMemory = (kb) => {
return kb + ' KB'
}
const getRowVm = (row) => row?._vm || row?.vm?.data || row?.vm || row?.user_vm || null
const formatVmIps = (vm) => {
if (!vm) return ''
if (Array.isArray(vm.ips)) return vm.ips.filter(Boolean).join(', ')
if (typeof vm.ips === 'string' && vm.ips.trim()) return vm.ips.split(',').map(ip => ip.trim()).filter(Boolean).join(', ')
const networks = Array.isArray(vm.networks) ? vm.networks : []
return networks.flatMap(network => {
if (Array.isArray(network.ips)) return network.ips
return [network.ip, network.address].filter(Boolean)
}).filter(Boolean).join(', ')
}
const loadVmSummaries = async (rows) => {
const targets = rows.filter(row => row?.id && (row.itemId || row.item_id) && !getRowVm(row))
await Promise.allSettled(targets.map(async row => {
const res = await getUserVmDetail({ user_goods_id: row.id })
if (res?.data?.code !== 200 || !res?.data?.data) return
const detail = res.data.data
row._vm = detail.vm?.data ?? detail.vm ?? null
}))
}
const formatExpireTime = (t) => {
if (!t) return '-'
const d = dayjs(t)
@@ -1007,6 +1049,7 @@ const loadList = async () => {
const d = res.data.data
list.value = d.data || (Array.isArray(d) ? d : [])
total.value = d.meta?.count ?? d.all_count ?? d.total ?? list.value.length
await loadVmSummaries(list.value)
} else {
list.value = []
total.value = 0
@@ -1857,6 +1900,8 @@ onMounted(() => {
.action-bar { display: flex; gap: 12px; flex-shrink: 0; flex-wrap: wrap; align-items: center; }
.table-section { padding: 0; }
.vm-spec-list { display: flex; flex-wrap: wrap; gap: 4px; }
.vm-secondary-text { color: #909399; font-size: 12px; }
.pagination { padding: 16px 20px; border-top: 1px solid #e1e8ed; background: #fafbfc; justify-content: flex-end; }
+17
View File
@@ -68,6 +68,12 @@
<span v-else class="text-muted">-</span>
</template>
</el-table-column>
<el-table-column label="IP 地址" min-width="190" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="formatVmIps(row)" class="vm-ip-text">{{ formatVmIps(row) }}</span>
<span v-else class="text-muted">-</span>
</template>
</el-table-column>
<el-table-column label="状态" width="180">
<template #default="{ row }">
<template v-if="row.migrating">
@@ -900,6 +906,17 @@ const formatMemKB = (kb) => {
}
const formatMemory = formatMemKB
const formatVmIps = (vm) => {
if (!vm) return ''
if (Array.isArray(vm.ips)) return vm.ips.filter(Boolean).join(', ')
if (typeof vm.ips === 'string' && vm.ips.trim()) return vm.ips.split(',').map(ip => ip.trim()).filter(Boolean).join(', ')
const networks = Array.isArray(vm.networks) ? vm.networks : []
return networks.flatMap(network => {
if (Array.isArray(network.ips)) return network.ips
return [network.ip, network.address].filter(Boolean)
}).filter(Boolean).join(', ')
}
const formatTimestamp = (ts) => {
if (!ts) return '-'
if (typeof ts === 'object' && ts.seconds) {