feat: 对接虚拟化平台管理
This commit is contained in:
@@ -39,12 +39,18 @@
|
||||
<span class="host-addr">{{ row.ip || '-' }}:{{ row.port || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Token" min-width="160" show-overflow-tooltip>
|
||||
<el-table-column label="Token" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.token" class="token-mask">{{ maskToken(row.token) }}</span>
|
||||
<span v-else class="text-muted">未设置</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="延迟" width="100">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row._delay != null" :style="{ color: row._delay > 500000000 ? '#F56C6C' : row._delay > 100000000 ? '#E6A23C' : '#67C23A' }">{{ formatDelay(row._delay) }}</span>
|
||||
<span v-else class="text-muted">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="260" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||
@@ -118,12 +124,10 @@
|
||||
</el-form>
|
||||
<div v-if="vmVncResult" class="vnc-result">
|
||||
<el-descriptions :column="1" border size="small">
|
||||
<el-descriptions-item v-for="(val, key) in vmVncResult" :key="key" :label="key">
|
||||
<template v-if="typeof val === 'string' && (val.startsWith('http') || val.startsWith('ws'))">
|
||||
<el-link type="primary" :href="val" target="_blank">{{ val }}</el-link>
|
||||
</template>
|
||||
<template v-else>{{ val }}</template>
|
||||
<el-descriptions-item label="VNC地址">
|
||||
<el-link type="primary" :href="vmVncResult.url" target="_blank">{{ vmVncResult.url }}</el-link>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="过期时间">{{ formatTimestamp(vmVncResult.expire_at) }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -145,6 +149,7 @@ import {
|
||||
getVncNodeList, getVmVnc, addVncNode, testVncNode, updateVncNode, deleteVncNode,
|
||||
getRemoteHostList
|
||||
} from '@/api/admin/kvmService'
|
||||
import { extractApiError } from '@/utils/kvmErrorUtil'
|
||||
import VmSelectorPopup from '@/components/admin/VmSelectorPopup.vue'
|
||||
|
||||
const route = useRoute()
|
||||
@@ -169,6 +174,20 @@ const maskToken = (token) => {
|
||||
return token.substring(0, 4) + '****' + token.substring(token.length - 4)
|
||||
}
|
||||
|
||||
const formatTimestamp = (ts) => {
|
||||
if (!ts) return '-'
|
||||
if (typeof ts === 'object' && ts.seconds) return new Date(Number(ts.seconds) * 1000).toLocaleString('zh-CN')
|
||||
if (typeof ts === 'string' || typeof ts === 'number') { const d = new Date(ts); return isNaN(d.getTime()) ? String(ts) : d.toLocaleString('zh-CN') }
|
||||
return '-'
|
||||
}
|
||||
|
||||
const formatDelay = (ns) => {
|
||||
if (!ns && ns !== 0) return '-'
|
||||
const ms = ns / 1000000
|
||||
if (ms >= 1000) return (ms / 1000).toFixed(2) + ' s'
|
||||
return ms.toFixed(2) + ' ms'
|
||||
}
|
||||
|
||||
const loadHostOptions = async () => {
|
||||
try {
|
||||
const res = await getRemoteHostList({ service_id: serviceId.value, page: 1, page_size: 100 })
|
||||
@@ -241,8 +260,8 @@ const handleSubmit = () => {
|
||||
ElMessage.success(formType.value === 'add' ? '创建成功' : '修改成功')
|
||||
formDialogVisible.value = false
|
||||
loadList()
|
||||
} else ElMessage.error(res?.data?.message || '操作失败')
|
||||
} catch (e) { ElMessage.error('操作失败') } finally { submitLoading.value = false }
|
||||
} else ElMessage.error(extractApiError(res?.data, '操作失败'))
|
||||
} catch (e) { ElMessage.error(extractApiError(e?.response?.data, '操作失败')) } finally { submitLoading.value = false }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,8 +272,8 @@ const handleDelete = (row) => {
|
||||
try {
|
||||
const res = await deleteVncNode({ service_id: serviceId.value, id: row.id })
|
||||
if (res?.data?.code === 200) { ElMessage.success('删除成功'); loadList() }
|
||||
else ElMessage.error(res?.data?.message || '删除失败')
|
||||
} catch (e) { ElMessage.error('删除失败') }
|
||||
else ElMessage.error(extractApiError(res?.data, '删除失败'))
|
||||
} catch (e) { ElMessage.error(extractApiError(e?.response?.data, '删除失败')) }
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
@@ -279,9 +298,15 @@ const submitTest = async () => {
|
||||
try {
|
||||
const res = await testVncNode({ service_id: serviceId.value, id: testTarget.value.id, host_id: testHostId.value })
|
||||
if (res?.data?.code === 200) {
|
||||
testResult.value = { success: true, message: '连接测试成功' }
|
||||
const d = res.data.data || {}
|
||||
const delay = d.delay
|
||||
if (delay != null && testTarget.value) {
|
||||
const idx = nodeList.value.findIndex(n => n.id === testTarget.value.id)
|
||||
if (idx >= 0) nodeList.value[idx]._delay = delay
|
||||
}
|
||||
testResult.value = { success: true, message: '连接测试成功' + (delay != null ? `,延迟:${formatDelay(delay)}` : '') }
|
||||
} else {
|
||||
testResult.value = { success: false, message: res?.data?.message || '连接测试失败' }
|
||||
testResult.value = { success: false, message: extractApiError(res?.data, '连接测试失败') }
|
||||
}
|
||||
} catch (e) {
|
||||
testResult.value = { success: false, message: '连接测试异常: ' + (e?.message || '未知错误') }
|
||||
@@ -315,9 +340,9 @@ const submitVmVnc = async () => {
|
||||
if (res?.data?.code === 200 && res?.data?.data) {
|
||||
vmVncResult.value = res.data.data
|
||||
} else {
|
||||
ElMessage.error(res?.data?.message || '获取VNC连接信息失败')
|
||||
ElMessage.error(extractApiError(res?.data, '获取VNC连接信息失败'))
|
||||
}
|
||||
} catch (e) { ElMessage.error('获取失败') } finally { vmVncLoading.value = false }
|
||||
} catch (e) { ElMessage.error(extractApiError(e?.response?.data, '获取VNC连接信息失败')) } finally { vmVncLoading.value = false }
|
||||
}
|
||||
|
||||
const goBack = () => { router.push('/virtualization/kvm-service') }
|
||||
|
||||
Reference in New Issue
Block a user