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();