diff --git a/src/utils/acs/server.js b/src/utils/acs/server.js index dfa217c..016ad30 100644 --- a/src/utils/acs/server.js +++ b/src/utils/acs/server.js @@ -279,6 +279,14 @@ export const connectConsole = data => { } }); }; +/**新增虚拟机 (管理员) */ +export const addInstance = data => { + return http2.post("/v1/admin/instance/create_vm", data, { + headers: { + "Content-Type": "multipart/form-data" + } + }); +}; /**获取虚拟机控制台 */ export const getInstanceConsole = data => { return http2.get(`/v1/admin/instance/console/${data}`); diff --git a/src/views/acs/nodes/components/VmList.vue b/src/views/acs/nodes/components/VmList.vue index fe0615b..1c8df73 100644 --- a/src/views/acs/nodes/components/VmList.vue +++ b/src/views/acs/nodes/components/VmList.vue @@ -14,6 +14,9 @@ 重置 + + 新增虚拟机 + + + + + + + + + + + + + {{ plan.name }} + + {{ plan.price }}元/月 + + + + + + + + + + + + + + + + + + + + + + + + {{ mirror.name }} + + {{ mirror.size }}MB + + + + + + + + + + + + @@ -132,7 +260,7 @@ import { ref, onMounted, defineProps, watch } from 'vue'; import { useRouter } from 'vue-router'; import { ElMessage, ElMessageBox } from 'element-plus'; import { - Search, Refresh, Menu, VideoPlay, VideoPause, RefreshRight, ArrowDown + Search, Refresh, Menu, VideoPlay, VideoPause, RefreshRight, ArrowDown, Plus } from '@element-plus/icons-vue'; import { getContainer, @@ -142,8 +270,11 @@ import { getInstanceList, reinstallI, rescueInstance, - exitRescueInstance + exitRescueInstance, + addInstance, + getServerPlan } from '@/utils/acs/server'; +import { getMirrorList } from '@/utils/acs/mirror'; const props = defineProps({ ID: { @@ -160,6 +291,48 @@ const currentPage = ref(1); const pageSize = ref(10); const searchKey = ref(''); +// 新增虚拟机相关状态 +const addVmDialogVisible = ref(false); +const addVmLoading = ref(false); +const addVmFormRef = ref(null); +const addVmForm = ref({ + user_id: '', + plan_id: '', + volume_size: null, + pay_months: null, + pay_type: '', + image_id: '', + price: null +}); + +// 套餐和镜像数据 +const planList = ref([]); +const mirrorList = ref([]); +const planLoading = ref(false); +const mirrorLoading = ref(false); + +// 表单验证规则 +const addVmRules = ref({ + user_id: [ + { required: true, message: '请输入用户ID', trigger: 'blur' } + ], + plan_id: [ + { required: true, message: '请选择套餐', trigger: 'change' } + ], + pay_months: [ + { required: true, message: '请输入购买月数', trigger: 'blur' } + ], + pay_type: [ + { required: true, message: '请选择支付类型', trigger: 'change' } + ], + image_id: [ + { required: true, message: '请选择镜像', trigger: 'change' } + ], + price: [ + { required: true, message: '请输入价格', trigger: 'blur' } + ] +}); + // 获取虚拟机列表 const fetchVmList = async () => { loading.value = true; @@ -437,6 +610,124 @@ watch(() => props.ID, (newVal) => { } }); +// 获取套餐列表 +const fetchPlanList = async () => { + if (planList.value.length > 0) return; // 已加载过,不重复加载 + + planLoading.value = true; + try { + const response = await getServerPlan({ + server_id: props.ID, + count: 100 + }); + + if (response && response.data && response.data.code === 200) { + planList.value = response.data.data || []; + } else { + ElMessage.error('获取套餐列表失败'); + } + } catch (error) { + console.error('获取套餐列表出错:', error); + ElMessage.error('获取套餐列表出错'); + } finally { + planLoading.value = false; + } +}; + +// 获取镜像列表 +const fetchMirrorList = async () => { + if (mirrorList.value.length > 0) return; // 已加载过,不重复加载 + + mirrorLoading.value = true; + try { + const response = await getMirrorList(props.ID); + + if (response && response.data && response.data.code === 200) { + mirrorList.value = response.data.data || []; + } else { + ElMessage.error('获取镜像列表失败'); + } + } catch (error) { + console.error('获取镜像列表出错:', error); + ElMessage.error('获取镜像列表出错'); + } finally { + mirrorLoading.value = false; + } +}; + +// 显示新增虚拟机对话框 +const showAddVmDialog = () => { + addVmDialogVisible.value = true; + // 重置表单 + addVmForm.value = { + user_id: '', + plan_id: '', + volume_size: null, + pay_months: null, + pay_type: '', + image_id: '', + price: null + }; + // 清除验证 + if (addVmFormRef.value) { + addVmFormRef.value.clearValidate(); + } + // 预加载数据 + fetchPlanList(); + fetchMirrorList(); +}; + +// 取消新增虚拟机 +const cancelAddVm = () => { + addVmDialogVisible.value = false; +}; + +// 确认新增虚拟机 +const confirmAddVm = async () => { + if (!addVmFormRef.value) return; + + try { + // 验证表单 + await addVmFormRef.value.validate(); + + addVmLoading.value = true; + + // 准备API参数 + const apiParams = { + user_id: addVmForm.value.user_id, + plan_id: addVmForm.value.plan_id, + volume_size: addVmForm.value.volume_size?.toString() || '', + pay_months: addVmForm.value.pay_months?.toString() || '', + pay_type: addVmForm.value.pay_type, + image_id: addVmForm.value.image_id, + price: addVmForm.value.price?.toString() || '' + }; + + console.log('新增虚拟机参数:', apiParams); + + // 调用API + const response = await addInstance(apiParams); + + if (response && response.data && response.data.code === 200) { + ElMessage.success('虚拟机创建成功'); + addVmDialogVisible.value = false; + // 刷新列表 + fetchVmList(); + } else { + ElMessage.error('创建失败: ' + (response.data?.message || '未知错误')); + } + } catch (error) { + console.error('新增虚拟机出错:', error); + if (error.message) { + ElMessage.error('表单验证失败: ' + error.message); + } else { + ElMessage.error('新增虚拟机出错'); + } + } finally { + addVmLoading.value = false; + } +}; + onMounted(() => { if (props.ID) { fetchVmList();