diff --git a/src/App.vue b/src/App.vue index ebb004e..77c7cea 100644 --- a/src/App.vue +++ b/src/App.vue @@ -226,11 +226,16 @@ html, body { color: #3498db !important; } -/* 卡片扁平化 */ +/* 卡片扁平化 + 层次感 */ .el-card { border-radius: 0 !important; border: 1px solid #e1e8ed !important; box-shadow: none !important; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} +.el-card[shadow="hover"]:hover { + border-color: #c0c4cc !important; + box-shadow: 0 2px 12px rgba(44, 62, 80, 0.08) !important; } /* 表格扁平化 */ @@ -434,4 +439,70 @@ html, body { .el-dialog .el-form-item { margin-bottom: 20px; } + +/* Descriptions 描述列表增强 */ +.el-descriptions { + --el-descriptions-item-bordered-label-background: #fafbfc; +} +.el-descriptions__label { + color: #606266 !important; + font-weight: 500 !important; +} +.el-descriptions__content { + color: #1d2129 !important; +} + +/* Loading 遮罩增强 */ +.el-loading-mask { + background-color: rgba(255, 255, 255, 0.85) !important; +} +.el-loading-spinner .circular { + width: 36px; + height: 36px; +} +.el-loading-spinner .el-loading-text { + color: #606266 !important; + font-size: 13px; + margin-top: 8px; +} + +/* Message Box 增强 */ +.el-message-box { + border-radius: 0 !important; + box-shadow: 0 4px 16px rgba(44, 62, 80, 0.15) !important; +} +.el-message-box__header { + padding: 16px 20px 12px !important; +} +.el-message-box__title { + font-weight: 600 !important; + color: #1d2129 !important; +} +.el-message-box__btns .el-button { + border-radius: 0 !important; +} + +/* Alert 增强 */ +.el-alert { + border-radius: 0 !important; +} + +/* Tabs 增强 */ +.el-tabs__item { + transition: color 0.2s ease !important; +} +.el-tabs__item.is-active { + font-weight: 600 !important; +} + +/* Switch 开关增强 */ +.el-switch { + --el-switch-on-color: #2c3e50; +} + +/* 全局链接按钮悬浮下划线 */ +.el-button.is-link:hover, +.el-button--primary.is-link:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/src/api/admin/kvmService.js b/src/api/admin/kvmService.js index 662e95b..e22e9fd 100644 --- a/src/api/admin/kvmService.js +++ b/src/api/admin/kvmService.js @@ -145,6 +145,11 @@ export const getRemoteHostMetrics = (params) => { return http2.get('/api/v1/admin/server/host_service/point/host/metrics', { params }) } +/** 查询历史指标(宿主机或虚拟机) */ +export const getMetricsHistory = (params) => { + return http2.get('/api/v1/admin/server/host_service/point/host/metrics_history', { params }) +} + /** 新增宿主机 */ export const addRemoteHost = (data) => { return http2.post('/api/v1/admin/server/host_service/point/host/add', data, { @@ -164,6 +169,13 @@ export const deleteRemoteHost = (params) => { return http2.delete('/api/v1/admin/server/host_service/point/host/delete', { params }) } +/** 创建宿主机注册令牌 */ +export const createHostToken = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/host/create_token', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) +} + /** * ================================ * 主控服务接口 - 镜像管理 @@ -445,21 +457,28 @@ export const deleteVm = (params) => { /** 迁移虚拟机(更换宿主机) */ export const migrateVm = (data) => { - return http2.post('/api/v1/admin/service/host_service/point/vm/migrate', data, { + return http2.post('/api/v1/admin/server/host_service/point/vm/migrate', data, { headers: { 'Content-Type': 'multipart/form-data' } }) } /** 发起虚拟机数据迁移 */ export const dataMigrateVm = (data) => { - return http2.post('/api/v1/admin/service/host_service/point/vm/data_migrate', data, { + return http2.post('/api/v1/admin/server/host_service/point/vm/data_migrate', data, { headers: { 'Content-Type': 'multipart/form-data' } }) } /** 获取虚拟机数据迁移进度 */ export const getDataMigrateProgress = (params) => { - return http2.get('/api/v1/admin/service/host_service/point/vm/data_migrate/progress', { params }) + return http2.get('/api/v1/admin/server/host_service/point/vm/data_migrate/progress', { params }) +} + +/** 中断虚拟机数据迁移 */ +export const abortDataMigrate = (data) => { + return http2.post('/api/v1/admin/server/host_service/point/vm/data_migrate/abort', data, { + headers: { 'Content-Type': 'multipart/form-data' } + }) } /** diff --git a/src/api/admin/userVm.js b/src/api/admin/userVm.js index 104f664..7433c42 100644 --- a/src/api/admin/userVm.js +++ b/src/api/admin/userVm.js @@ -23,6 +23,7 @@ export const getUserVmList = (params) => http2.get(`${BASE}/list`, { params }) export const getUserVmDetail = (params) => http2.get(`${BASE}/detail`, { params }) export const getUserVmVnc = (params) => http2.get(`${BASE}/vnc`, { params }) export const getUserVmHostImages = (params) => http2.get(`${BASE}/host_images`, { params }) +export const getGoodHostGroupImages = (params) => http2.get(`${BASE}/good_host_group_images`, { params }) export const createUserVm = (data) => http2.post(`${BASE}/create`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) export const bindUserVm = (data) => http2.post(`${BASE}/bind`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) export const transferUserVm = (data) => http2.post(`${BASE}/transfer`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) @@ -102,3 +103,9 @@ export const getUserGoodsDetail = (params) => http2.get(`${GOODS_BASE}/detail`, export const createUserGoods = (data) => http2.post(`${GOODS_BASE}/create`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) export const updateUserGoods = (data) => http2.post(`${GOODS_BASE}/update`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) export const deleteUserGoods = (params) => http2.delete(`${GOODS_BASE}/delete`, { params }) + +export const getUserVmMetricsHistory = (params) => http2.get(`${BASE}/metrics_history`, { params }) + +// ========== 到期提醒 ========== +export const getExpireRemindList = (params) => http2.get(`${GOODS_BASE}/expire_remind/list`, { params }) +export const sendExpireRemind = (data) => http2.post(`${GOODS_BASE}/expire_remind/send`, data, { headers: { 'Content-Type': 'application/json' } }) diff --git a/src/api/admin/vncCommand.js b/src/api/admin/vncCommand.js new file mode 100644 index 0000000..f1ab2c3 --- /dev/null +++ b/src/api/admin/vncCommand.js @@ -0,0 +1,24 @@ +import { http2 } from '@/utils/request.js' + +const fd = (data) => { + const f = new FormData() + Object.entries(data).forEach(([k, v]) => { + if (v === undefined || v === null || v === '') return + f.append(k, v) + }) + return f +} + +const BASE_GROUP = '/api/v1/admin/server/vnc_command/group' +const BASE_ITEM = '/api/v1/admin/server/vnc_command/item' + +// 分组 +export const getVncCommandGroupList = () => http2.get(`${BASE_GROUP}/list`) +export const createVncCommandGroup = (data) => http2.post(`${BASE_GROUP}/create`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) +export const updateVncCommandGroup = (data) => http2.post(`${BASE_GROUP}/update`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) +export const deleteVncCommandGroup = (params) => http2.delete(`${BASE_GROUP}/delete`, { params }) + +// 指令项 +export const createVncCommandItem = (data) => http2.post(`${BASE_ITEM}/create`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) +export const updateVncCommandItem = (data) => http2.post(`${BASE_ITEM}/update`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) +export const deleteVncCommandItem = (params) => http2.delete(`${BASE_ITEM}/delete`, { params }) diff --git a/src/components/admin/AvatarSelector.vue b/src/components/admin/AvatarSelector.vue index 7d178a6..38e7592 100644 --- a/src/components/admin/AvatarSelector.vue +++ b/src/components/admin/AvatarSelector.vue @@ -1,20 +1,20 @@