feat: 对接虚拟化平台管理
This commit is contained in:
@@ -69,14 +69,8 @@
|
||||
<!-- 子模块Tab -->
|
||||
<el-card class="tabs-card" shadow="never">
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick" class="custom-tabs">
|
||||
<el-tab-pane label="宿主机组映射" name="host-group">
|
||||
<HostGroupMapping v-if="tabLoaded['host-group']" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="远程宿主机组" name="remote-host-group">
|
||||
<RemoteHostGroupManage v-if="tabLoaded['remote-host-group']" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="宿主机管理" name="host">
|
||||
<HostManage v-if="tabLoaded['host']" />
|
||||
<HostTreeManage v-if="tabLoaded['host']" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="镜像管理" name="image">
|
||||
<ImageManage v-if="tabLoaded['image']" />
|
||||
@@ -96,6 +90,12 @@
|
||||
<el-tab-pane label="VNC节点" name="vnc">
|
||||
<VncNodeManage v-if="tabLoaded['vnc']" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="快照管理" name="snapshot">
|
||||
<SnapshotManage v-if="tabLoaded['snapshot']" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="备份管理" name="backup">
|
||||
<BackupManage v-if="tabLoaded['backup']" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
@@ -128,26 +128,27 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, provide, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, provide, onMounted, onActivated, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ArrowLeft, Refresh, Edit, Delete, Monitor } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getKvmServiceDetail, updateKvmService, deleteKvmService
|
||||
} from '@/api/admin/kvmService'
|
||||
import { extractApiError } from '@/utils/kvmErrorUtil'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// 子模块组件(懒加载)
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
const HostGroupMapping = defineAsyncComponent(() => import('./HostGroupMapping.vue'))
|
||||
const HostManage = defineAsyncComponent(() => import('./HostManage.vue'))
|
||||
const HostTreeManage = defineAsyncComponent(() => import('./HostTreeManage.vue'))
|
||||
const ImageManage = defineAsyncComponent(() => import('./ImageManage.vue'))
|
||||
const NetworkManage = defineAsyncComponent(() => import('./NetworkManage.vue'))
|
||||
const VolumeManage = defineAsyncComponent(() => import('./VolumeManage.vue'))
|
||||
const VmManage = defineAsyncComponent(() => import('./VmManage.vue'))
|
||||
const SecurityGroupManage = defineAsyncComponent(() => import('./SecurityGroupManage.vue'))
|
||||
const VncNodeManage = defineAsyncComponent(() => import('./VncNodeManage.vue'))
|
||||
const RemoteHostGroupManage = defineAsyncComponent(() => import('./RemoteHostGroupManage.vue'))
|
||||
const SnapshotManage = defineAsyncComponent(() => import('./SnapshotManage.vue'))
|
||||
const BackupManage = defineAsyncComponent(() => import('./BackupManage.vue'))
|
||||
|
||||
// 引入tagsViewStore
|
||||
import { useTagsViewStore } from '@/store/tagsViewStore'
|
||||
@@ -169,11 +170,9 @@ const submitLoading = ref(false)
|
||||
const serviceInfo = ref({})
|
||||
|
||||
// Tab 管理
|
||||
const activeTab = ref('host-group')
|
||||
const activeTab = ref('host')
|
||||
const tabLoaded = reactive({
|
||||
'host-group': true, // 默认加载第一个
|
||||
'remote-host-group': false,
|
||||
'host': false,
|
||||
'host': true,
|
||||
'image': false,
|
||||
'network': false,
|
||||
'volume': false,
|
||||
@@ -182,6 +181,7 @@ const tabLoaded = reactive({
|
||||
'vnc': false
|
||||
})
|
||||
|
||||
|
||||
const handleTabClick = (tab) => {
|
||||
const name = tab.props.name
|
||||
if (!tabLoaded[name]) {
|
||||
@@ -190,6 +190,7 @@ const handleTabClick = (tab) => {
|
||||
localStorage.setItem('kvmDetailActiveTab', name)
|
||||
}
|
||||
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (t) => {
|
||||
if (!t) return '-'
|
||||
@@ -210,7 +211,7 @@ const fetchServiceInfo = async () => {
|
||||
if (body?.code === 200 && body?.data) {
|
||||
serviceInfo.value = body.data
|
||||
} else {
|
||||
ElMessage.error(body?.message || '获取服务详情失败')
|
||||
ElMessage.error(extractApiError(body, '获取服务详情失败'))
|
||||
// 使用 query 参数中的基本信息做兜底
|
||||
serviceInfo.value = { Id: serviceId.value, Name: serviceName.value }
|
||||
}
|
||||
@@ -269,10 +270,10 @@ const handleSubmitEdit = () => {
|
||||
editDialogVisible.value = false
|
||||
fetchServiceInfo()
|
||||
} else {
|
||||
ElMessage.error(body?.message || '更新失败')
|
||||
ElMessage.error(extractApiError(body, '更新失败'))
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('更新失败: ' + (e?.response?.data?.message || e.message))
|
||||
ElMessage.error(extractApiError(e?.response?.data, '更新失败'))
|
||||
} finally { submitLoading.value = false }
|
||||
})
|
||||
}
|
||||
@@ -291,22 +292,46 @@ const handleDeleteService = () => {
|
||||
ElMessage.success('删除成功')
|
||||
goBack()
|
||||
} else {
|
||||
ElMessage.error(body?.message || '删除失败')
|
||||
ElMessage.error(extractApiError(body, '删除失败'))
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('删除失败')
|
||||
ElMessage.error(extractApiError(e?.response?.data, '删除失败'))
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchServiceInfo()
|
||||
// 恢复上次选中的 Tab
|
||||
// 记录当前已加载的 serviceId,用于判断是否需要刷新
|
||||
let loadedServiceId = null
|
||||
|
||||
const initPage = () => {
|
||||
if (!serviceId.value || loadedServiceId === serviceId.value) return
|
||||
loadedServiceId = serviceId.value
|
||||
|
||||
// 重置所有 tab 加载状态,使子组件在切换后重新拉取数据
|
||||
Object.keys(tabLoaded).forEach(k => { tabLoaded[k] = false })
|
||||
const savedTab = localStorage.getItem('kvmDetailActiveTab')
|
||||
if (savedTab && tabLoaded.hasOwnProperty(savedTab)) {
|
||||
activeTab.value = savedTab
|
||||
tabLoaded[savedTab] = true
|
||||
} else {
|
||||
activeTab.value = 'host'
|
||||
}
|
||||
tabLoaded[activeTab.value] = true
|
||||
|
||||
fetchServiceInfo()
|
||||
}
|
||||
|
||||
watch(serviceId, () => {
|
||||
initPage()
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
if (loadedServiceId !== serviceId.value) {
|
||||
initPage()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initPage()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -502,4 +527,5 @@ onMounted(() => {
|
||||
.custom-tabs :deep(.vnc-node-container) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user