Merge pull request 'feat:添加新增虚拟机' (#3) from master into deploy
Reviewed-on: lin/ApiServer-Web-admin_dashboard_pc#3
This commit was merged in pull request #3.
This commit is contained in:
@@ -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 => {
|
export const getInstanceConsole = data => {
|
||||||
return http2.get(`/v1/admin/instance/console/${data}`);
|
return http2.get(`/v1/admin/instance/console/${data}`);
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
<el-button @click="resetSearch">
|
<el-button @click="resetSearch">
|
||||||
<el-icon><refresh /></el-icon>重置
|
<el-icon><refresh /></el-icon>重置
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button type="success" @click="showAddVmDialog">
|
||||||
|
<el-icon><plus /></el-icon>新增虚拟机
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
@@ -124,6 +127,131 @@
|
|||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 新增虚拟机对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="addVmDialogVisible"
|
||||||
|
title="新增虚拟机"
|
||||||
|
width="600px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="addVmFormRef"
|
||||||
|
:model="addVmForm"
|
||||||
|
:rules="addVmRules"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户ID" prop="user_id">
|
||||||
|
<el-input
|
||||||
|
v-model="addVmForm.user_id"
|
||||||
|
placeholder="请输入用户ID"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="套餐" prop="plan_id">
|
||||||
|
<el-select
|
||||||
|
v-model="addVmForm.plan_id"
|
||||||
|
placeholder="请选择套餐"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
:loading="planLoading"
|
||||||
|
@focus="fetchPlanList"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="plan in planList"
|
||||||
|
:key="plan.id"
|
||||||
|
:label="plan.name"
|
||||||
|
:value="plan.plan_id"
|
||||||
|
>
|
||||||
|
<span style="float: left">{{ plan.name }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">
|
||||||
|
{{ plan.price }}元/月
|
||||||
|
</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="额外数据卷大小" prop="volume_size">
|
||||||
|
<el-input-number
|
||||||
|
v-model="addVmForm.volume_size"
|
||||||
|
:min="0"
|
||||||
|
:max="10000"
|
||||||
|
placeholder="请输入额外数据卷大小(GB)"
|
||||||
|
style="width: 100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="购买时间(月)" prop="pay_months">
|
||||||
|
<el-input-number
|
||||||
|
v-model="addVmForm.pay_months"
|
||||||
|
:min="1"
|
||||||
|
:max="120"
|
||||||
|
placeholder="请输入购买月数"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="支付类型" prop="pay_type">
|
||||||
|
<el-select
|
||||||
|
v-model="addVmForm.pay_type"
|
||||||
|
placeholder="请选择支付类型"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<!-- <el-option label="支付宝" value="alipay" />
|
||||||
|
<el-option label="微信支付" value="wechat" />
|
||||||
|
<el-option label="银行卡" value="bank" /> -->
|
||||||
|
<el-option label="余额" value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="镜像" prop="image_id">
|
||||||
|
<el-select
|
||||||
|
v-model="addVmForm.image_id"
|
||||||
|
placeholder="请选择镜像"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
:loading="mirrorLoading"
|
||||||
|
@focus="fetchMirrorList"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="mirror in mirrorList"
|
||||||
|
:key="mirror.id"
|
||||||
|
:label="mirror.name"
|
||||||
|
:value="mirror.id"
|
||||||
|
>
|
||||||
|
<span style="float: left">{{ mirror.name }}</span>
|
||||||
|
<span style="float: right; color: #8492a6; font-size: 13px">
|
||||||
|
{{ mirror.size }}MB
|
||||||
|
</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="价格" prop="price">
|
||||||
|
<el-input-number
|
||||||
|
v-model="addVmForm.price"
|
||||||
|
:min="0"
|
||||||
|
:max="999999"
|
||||||
|
:precision="2"
|
||||||
|
placeholder="请输入价格"
|
||||||
|
style="width: 100%"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="cancelAddVm">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddVm" :loading="addVmLoading">
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -132,7 +260,7 @@ import { ref, onMounted, defineProps, watch } from 'vue';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import {
|
import {
|
||||||
Search, Refresh, Menu, VideoPlay, VideoPause, RefreshRight, ArrowDown
|
Search, Refresh, Menu, VideoPlay, VideoPause, RefreshRight, ArrowDown, Plus
|
||||||
} from '@element-plus/icons-vue';
|
} from '@element-plus/icons-vue';
|
||||||
import {
|
import {
|
||||||
getContainer,
|
getContainer,
|
||||||
@@ -142,8 +270,11 @@ import {
|
|||||||
getInstanceList,
|
getInstanceList,
|
||||||
reinstallI,
|
reinstallI,
|
||||||
rescueInstance,
|
rescueInstance,
|
||||||
exitRescueInstance
|
exitRescueInstance,
|
||||||
|
addInstance,
|
||||||
|
getServerPlan
|
||||||
} from '@/utils/acs/server';
|
} from '@/utils/acs/server';
|
||||||
|
import { getMirrorList } from '@/utils/acs/mirror';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
ID: {
|
ID: {
|
||||||
@@ -160,6 +291,48 @@ const currentPage = ref(1);
|
|||||||
const pageSize = ref(10);
|
const pageSize = ref(10);
|
||||||
const searchKey = ref('');
|
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 () => {
|
const fetchVmList = async () => {
|
||||||
loading.value = true;
|
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(() => {
|
onMounted(() => {
|
||||||
if (props.ID) {
|
if (props.ID) {
|
||||||
fetchVmList();
|
fetchVmList();
|
||||||
|
|||||||
Reference in New Issue
Block a user