diff --git a/src/api/admin/kvmService.js b/src/api/admin/kvmService.js index abe1bee..8fb1fe1 100644 --- a/src/api/admin/kvmService.js +++ b/src/api/admin/kvmService.js @@ -427,10 +427,8 @@ export const exitRescueVm = (data) => { } /** 删除虚拟机 */ -export const deleteVm = (data) => { - return http2.post('/api/v1/admin/server/host_service/point/vm/delete', data, { - headers: { 'Content-Type': 'multipart/form-data' } - }) +export const deleteVm = (params) => { + return http2.delete('/api/v1/admin/server/host_service/point/vm/delete', { params }) } /** @@ -456,6 +454,13 @@ export const createSecurityGroup = (data) => { }) } +/** 修改安全组 */ +export const updateSecurityGroup = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/post_group/update', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + /** 同步安全组 */ export const syncSecurityGroup = (data) => { return http2.post('/api/v1/admin/server/host_service/point/post_group/sync', data, { @@ -563,3 +568,74 @@ export const updateVncNode = (data) => { export const deleteVncNode = (params) => { return http2.delete('/api/v1/admin/server/host_service/point/vnc/delete', { params }) } + +/** 设置安全组共享状态 */ +export const setSecurityGroupShared = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/post_group/set_shared', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +// ========== 快照管理 ========== +/** 获取快照列表 */ +export const getSnapshotList = (params) => { + return http2.get('/api/v1/admin/server/host_service/point/snapshot/list', { params }) +} + +/** 获取快照任务进度 */ +export const getSnapshotProgress = (params) => { + return http2.get('/api/v1/admin/server/host_service/point/snapshot/progress', { params }) +} + +/** 创建快照 */ +export const createSnapshot = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/snapshot/create', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +/** 恢复快照 */ +export const restoreSnapshot = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/snapshot/restore', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +/** 删除快照 */ +export const deleteSnapshot = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/snapshot/delete', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +// ========== 备份管理 ========== +/** 获取备份列表 */ +export const getBackupList = (params) => { + return http2.get('/api/v1/admin/server/host_service/point/backup/list', { params }) +} + +/** 获取备份任务进度 */ +export const getBackupProgress = (params) => { + return http2.get('/api/v1/admin/server/host_service/point/backup/progress', { params }) +} + +/** 创建备份 */ +export const createBackup = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/backup/create', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +/** 恢复备份 */ +export const restoreBackup = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/backup/restore', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + +/** 删除备份 */ +export const deleteBackup = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/backup/delete', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} diff --git a/src/config/menus.js b/src/config/menus.js index fb6578d..d1bcc88 100644 --- a/src/config/menus.js +++ b/src/config/menus.js @@ -143,6 +143,10 @@ export const menus = [ { path: '/virtualization/kvm-service', title: '主控服务管理' + }, + { + path: '/virtualization/host-group-mapping', + title: '宿主机组映射管理' } ] }, diff --git a/src/router/index.js b/src/router/index.js index 0d5124a..2ceef4b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -422,9 +422,7 @@ const routes = [ name: 'HostGroupMapping', component: () => import('../views/virtualization/HostGroupMapping.vue'), meta: { - title: '宿主机组映射管理', - hidden: true, - activeMenu: '/virtualization/kvm-service' + title: '宿主机组映射管理' } }, { diff --git a/src/utils/kvmErrorUtil.js b/src/utils/kvmErrorUtil.js new file mode 100644 index 0000000..d25d11f --- /dev/null +++ b/src/utils/kvmErrorUtil.js @@ -0,0 +1,150 @@ +const ERROR_CODE_MAP = { + // 主控服务 + kvm_service_list_error: '获取主控服务列表失败', + kvm_service_detail_error: '获取主控服务详情失败', + kvm_service_create_error: '创建主控服务失败', + kvm_service_update_error: '修改主控服务失败', + kvm_service_delete_error: '删除主控服务失败', + + // 宿主机组(本地) + kvm_host_group_list_error: '获取宿主机组列表失败', + kvm_host_group_sync_error: '同步宿主机组失败', + kvm_host_group_bind_error: '绑定宿主机组失败', + kvm_host_group_update_error: '修改宿主机组失败', + kvm_host_group_delete_error: '删除宿主机组失败', + kvm_host_group_generate_error: '生成商品失败', + kvm_host_group_optimal_error: '获取最优主机失败', + + // 宿主机组(远程) + kvm_remote_host_group_list_error: '获取远程宿主机组列表失败', + kvm_remote_host_group_detail_error: '获取远程宿主机组详情失败', + kvm_remote_host_group_tree_error: '获取远程宿主机组树失败', + kvm_remote_host_group_create_error: '创建远程宿主机组失败', + kvm_remote_host_group_update_error: '修改远程宿主机组失败', + kvm_remote_host_group_delete_error: '删除远程宿主机组失败', + + // 宿主机 + kvm_host_list_error: '获取宿主机列表失败', + kvm_host_detail_error: '获取宿主机详情失败', + kvm_host_metrics_error: '获取宿主机指标失败', + kvm_host_add_error: '新增宿主机失败', + kvm_host_update_error: '修改宿主机失败', + kvm_host_delete_error: '删除宿主机失败', + + // 镜像 + kvm_image_list_error: '获取镜像列表失败', + kvm_image_detail_error: '获取镜像详情失败', + kvm_image_host_status_error: '获取镜像宿主机状态失败', + kvm_image_create_error: '创建镜像失败', + kvm_image_update_error: '修改镜像失败', + kvm_image_delete_error: '删除镜像失败', + kvm_image_reload_error: '重新下载镜像失败', + kvm_image_sync_error: '同步镜像到宿主机失败', + kvm_image_reload_host_error: '重新下载镜像到宿主机失败', + + // 网络 + kvm_network_list_error: '获取网络列表失败', + kvm_network_detail_error: '获取网络详情失败', + kvm_network_create_error: '创建网络失败', + kvm_network_update_error: '修改网络失败', + kvm_network_delete_error: '删除网络失败', + + // 数据卷 + kvm_volume_list_error: '获取数据卷列表失败', + kvm_volume_detail_error: '获取数据卷详情失败', + kvm_volume_create_error: '创建数据卷失败', + kvm_volume_resize_error: '调整数据卷大小失败', + kvm_volume_mount_error: '挂载数据卷失败', + kvm_volume_unmount_error: '卸载数据卷失败', + kvm_volume_transfer_error: '迁移数据卷失败', + kvm_volume_delete_error: '删除数据卷失败', + + // 虚拟机 + kvm_vm_list_error: '获取虚拟机列表失败', + kvm_vm_detail_error: '获取虚拟机详情失败', + kvm_vm_status_error: '获取虚拟机状态失败', + kvm_vm_metrics_error: '获取虚拟机指标失败', + kvm_vm_create_error: '创建虚拟机失败', + kvm_vm_update_error: '修改虚拟机失败', + kvm_vm_rebuild_error: '重建虚拟机失败', + kvm_vm_refactor_error: '重构虚拟机失败', + kvm_vm_update_traffic_error: '修改虚拟机带宽失败', + kvm_vm_start_error: '启动虚拟机失败', + kvm_vm_stop_error: '停止虚拟机失败', + kvm_vm_reboot_error: '重启虚拟机失败', + kvm_vm_suspend_error: '暂停虚拟机失败', + kvm_vm_resume_error: '恢复虚拟机失败', + kvm_vm_rescue_error: '进入救援系统失败', + kvm_vm_exit_rescue_error: '退出救援系统失败', + kvm_vm_delete_error: '删除虚拟机失败', + + // 安全组 + kvm_post_group_list_error: '获取安全组列表失败', + kvm_post_group_detail_error: '获取安全组详情失败', + kvm_post_group_create_error: '创建安全组失败', + kvm_post_group_update_error: '修改安全组失败', + kvm_post_group_sync_error: '同步安全组失败', + kvm_post_group_bind_error: '绑定安全组失败', + kvm_post_group_unbind_error: '解绑安全组失败', + kvm_post_group_delete_error: '删除安全组失败', + kvm_post_group_enable_whitelist_error: '开启安全组白名单失败', + kvm_post_group_disable_whitelist_error: '关闭安全组白名单失败', + kvm_post_group_create_rule_error: '新增安全组规则失败', + kvm_post_group_update_rule_error: '修改安全组规则失败', + kvm_post_group_delete_rule_error: '删除安全组规则失败', + kvm_post_group_apply_error: '应用安全组失败', + kvm_security_group_list_error: '获取安全组列表失败', + kvm_security_group_detail_error: '获取安全组详情失败', + kvm_security_group_create_error: '创建安全组失败', + kvm_security_group_update_error: '修改安全组失败', + kvm_security_group_delete_error: '删除安全组失败', + + // VNC + kvm_vnc_list_error: '获取VNC节点列表失败', + kvm_vnc_add_error: '新增VNC节点失败', + kvm_vnc_test_error: '测试VNC节点连接失败', + kvm_vnc_update_error: '修改VNC节点失败', + kvm_vnc_delete_error: '删除VNC节点失败', + kvm_vnc_vm_vnc_error: '获取VNC连接信息失败', +} + +/** + * 从嵌套的 RPC 错误字符串中提取有意义的中文描述 + */ +function parseRpcError(err) { + if (!err) return '' + const descMatch = err.match(/desc\s*=\s*(.+)/) + if (descMatch) { + const descContent = descMatch[1] + const jsonMatch = descContent.match(/body=(\{.+\})/) + if (jsonMatch) { + try { + const parsed = JSON.parse(jsonMatch[1]) + if (parsed.message) return parsed.message + } catch { /* ignore */ } + } + const clean = descContent.trim() + if (clean && !clean.startsWith('http')) return clean + } + return '' +} + +/** + * 统一提取 API 响应中的错误信息 + * @param {object} body - axios response.data (即 { code, message, error, data }) + * @param {string} fallback - 兜底文案 + * @returns {string} 中文错误描述 + */ +export function extractApiError(body, fallback = '操作失败') { + if (!body) return fallback + + const rpcMsg = parseRpcError(body.error) + if (rpcMsg) return rpcMsg + + const mapped = ERROR_CODE_MAP[body.message] + if (mapped) return mapped + + if (body.message && !/^[a-z_]+$/.test(body.message)) return body.message + + return fallback +} diff --git a/src/views/virtualization/BackupManage.vue b/src/views/virtualization/BackupManage.vue new file mode 100644 index 0000000..69cb67b --- /dev/null +++ b/src/views/virtualization/BackupManage.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/src/views/virtualization/HostDetail.vue b/src/views/virtualization/HostDetail.vue index fa578c2..a0d7d01 100644 --- a/src/views/virtualization/HostDetail.vue +++ b/src/views/virtualization/HostDetail.vue @@ -1,131 +1,186 @@ diff --git a/src/views/virtualization/HostGroupMapping.vue b/src/views/virtualization/HostGroupMapping.vue index 1c76241..94c1bd8 100644 --- a/src/views/virtualization/HostGroupMapping.vue +++ b/src/views/virtualization/HostGroupMapping.vue @@ -3,17 +3,18 @@ - -
- -
-
-

本地主机组列表

-
-
- - - - - - - - - - - - - - - - - - - - - - -
+ +
+
+

本地主机组列表

- - -
-
-

远程主机组树

- - 刷新 - -
-
- -