diff --git a/src/views/user-vm/UserVmList.vue b/src/views/user-vm/UserVmList.vue index f0a4e31..0bdc491 100644 --- a/src/views/user-vm/UserVmList.vue +++ b/src/views/user-vm/UserVmList.vue @@ -75,6 +75,25 @@ (ID:{{ row.userId || row.user_id || '-' }}) + + + {{ getRowVm(row)?.hostname || getRowVm(row)?.name || row.itemName || '-' }} + #{{ row.itemId }} + + + + + + {{ getRowVm(row).vcpu || 0 }} 核 + {{ formatMemory(getRowVm(row).memory) }} + {{ getRowVm(row).system_size }} GB 盘 + + - + + + + {{ formatVmIps(getRowVm(row)) || '-' }} + @@ -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; } diff --git a/src/views/virtualization/VmManage.vue b/src/views/virtualization/VmManage.vue index e995c3c..cbf2f2e 100644 --- a/src/views/virtualization/VmManage.vue +++ b/src/views/virtualization/VmManage.vue @@ -68,6 +68,12 @@ - + + + {{ formatVmIps(row) }} + - + + @@ -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) {