From 67af0c66fd906724a1aebcf648f604c6d5ae9eac Mon Sep 17 00:00:00 2001 From: shiran Date: Tue, 4 Aug 2026 18:57:01 +0800 Subject: [PATCH] fix: improve VM migration state and chain details --- src/views/virtualization/VmDetail.vue | 22 +++++------ .../virtualization/VmMigrationRecord.vue | 38 ++++++++++++++++++- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/views/virtualization/VmDetail.vue b/src/views/virtualization/VmDetail.vue index 908d009..5764ac7 100644 --- a/src/views/virtualization/VmDetail.vue +++ b/src/views/virtualization/VmDetail.vue @@ -2048,15 +2048,17 @@ const loadDetail = async () => { const handleDetailMigrateState = () => { const vm = detail.value if (!vm) return - if (vm.migrating && vm.migrate_task_id) { - dataMigrateTaskId.value = vm.migrate_task_id - if (!dataMigrationId.value) dataMigrationId.value = vm.migrate_task_id - if (!migratePollingTimer) { - loadDataMigrateProgress() - startMigratePolling() + if (vm.migrating === true) { + if (vm.migrate_task_id) { + dataMigrateTaskId.value = vm.migrate_task_id + if (!dataMigrationId.value) dataMigrationId.value = vm.migrate_task_id + if (!migratePollingTimer) { + loadDataMigrateProgress() + startMigratePolling() + } } startDetailAutoRefresh() - } else if (!vm.migrating) { + } else { stopDetailAutoRefresh() if (migratePollingTimer) { stopMigratePolling() @@ -2905,11 +2907,7 @@ const loadDataMigrateProgress = async () => { const currentMigrateStage = computed(() => dataMigrateProgressData.value?.status || dataMigrateProgressData.value?.stage || '') -const isMigrating = computed(() => { - if (detail.value?.migrating) return true - const stage = currentMigrateStage.value - return stage && !MIGRATE_DONE_STAGES.includes(stage) -}) +const isMigrating = computed(() => detail.value?.migrating === true) const migrateStageLabel = (stage) => ({ exporting: '导出中', importing: '导入中', transferring: '传输中', diff --git a/src/views/virtualization/VmMigrationRecord.vue b/src/views/virtualization/VmMigrationRecord.vue index 2341424..742bf53 100644 --- a/src/views/virtualization/VmMigrationRecord.vue +++ b/src/views/virtualization/VmMigrationRecord.vue @@ -91,7 +91,27 @@
链路 ID:{{ chainData.chain_id || '-' }}
-
#{{ item.id }} · 第 {{ item.chain_seq || 1 }} 步 · {{ typeLabel(item.migration_type) }}{{ statusLabel(item.status) }}
服务 {{ item.source_service_id || '-' }} / VM {{ item.source_vm_id || '-' }} → 服务 {{ item.target_service_id || '-' }} / VM {{ item.target_vm_id || '-' }}
查看详情
+ +
#{{ item.id }} · 第 {{ item.chain_seq || 1 }} 步 · {{ typeLabel(item.migration_type) }}{{ statusLabel(item.status) }}
+
+
+ 源虚拟机 + {{ chainVmName(item, 'source') || `VM #${item.source_vm_id}` }} + {{ chainVmName(item, 'source') || '-' }} + 服务 #{{ item.source_service_id || '-' }} · VM #{{ item.source_vm_id || '-' }} + IP:{{ chainVmIps(item, 'source') || '-' }} +
+ +
+ 目标虚拟机 + {{ chainVmName(item, 'target') || `VM #${item.target_vm_id}` }} + {{ chainVmName(item, 'target') || '-' }} + 服务 #{{ item.target_service_id || '-' }} · VM #{{ item.target_vm_id || '-' }} + IP:{{ chainVmIps(item, 'target') || '-' }} +
+
+ 查看详情 +
@@ -138,6 +158,20 @@ const resetFilters = () => { Object.assign(filters,{ keyword:'',migration_type:' const detailVisible=ref(false), detailLoading=ref(false), currentRecord=ref(null) const snapshotFields=[{key:'request_snapshot',label:'请求参数'},{key:'before_snapshot',label:'迁移前快照'},{key:'after_snapshot',label:'迁移后快照'},{key:'manifest_snapshot',label:'迁移清单'},{key:'warning_snapshot',label:'警告'}] const prettySnapshot = value => { if(!value) return '暂无数据'; try { return JSON.stringify(typeof value==='string'?JSON.parse(value):value,null,2) } catch { return String(value) } } +const parseSnapshot = value => { if (!value) return {}; if (typeof value === 'object') return value; try { return JSON.parse(value) } catch { return {} } } +const chainVmSnapshot = (record, side) => parseSnapshot(side === 'source' ? record.before_snapshot : record.after_snapshot) +const chainVmName = (record, side) => { + const snapshot = chainVmSnapshot(record, side) + return record[`${side}_vm_name`] || snapshot.vm_detail?.data?.name || snapshot.vm_summary?.vm_name || '' +} +const chainVmIps = (record, side) => { + const snapshot = chainVmSnapshot(record, side) + const directIps = snapshot.vm_detail?.data?.ips + const values = directIps + ? String(directIps).split(',') + : [...(snapshot.ip_addresses?.ipv4 || []), ...(snapshot.ip_addresses?.ipv6 || [])] + return [...new Set(values.map(ip => String(ip).trim()).filter(Boolean))].join(', ') +} const openDetail = async row => { detailVisible.value=true; currentRecord.value=row; detailLoading.value=true; try { const res=await getVmMigrationRecordDetail({id:row.id}); if(res?.data?.code!==200) throw new Error(extractApiError(res?.data,'加载详情失败')); currentRecord.value=res.data.data?.record||res.data.data||row } catch(e){ ElMessage.error(e.message||extractApiError(e?.response?.data,'加载详情失败')) } finally { detailLoading.value=false } } const chainVisible=ref(false), chainLoading=ref(false), chainData=reactive({chain_id:'',records:[]}) const openChain = async row => { chainVisible.value=true; chainLoading.value=true; Object.assign(chainData,{chain_id:row.chain_id||'',records:[]}); try { const params=row.chain_id?{chain_id:row.chain_id}:{id:row.id}; const res=await getVmMigrationRecordChain(params); if(res?.data?.code!==200) throw new Error(extractApiError(res?.data,'加载迁移链失败')); Object.assign(chainData,res.data.data||{}) } catch(e){ ElMessage.error(e.message||extractApiError(e?.response?.data,'加载迁移链失败')) } finally { chainLoading.value=false } } @@ -154,5 +188,5 @@ onMounted(async () => { -- 2.54.0