778 lines
26 KiB
Vue
778 lines
26 KiB
Vue
<template>
|
||
<div>
|
||
<!-- 页面头部 -->
|
||
<div class="sticky top-0 z-10 shrink-0">
|
||
<Header>
|
||
<Breadcrumbs
|
||
:items="[
|
||
{ label: '服务器', route: '/jsite-servers' },
|
||
{ label: '新建服务器', route: '/jsite-servers/new' }
|
||
]"
|
||
/>
|
||
</Header>
|
||
</div>
|
||
|
||
<!-- 主要内容区域 -->
|
||
<div class="mx-auto max-w-2xl px-5">
|
||
<!-- 第一步:选择服务器配置和支付方式 -->
|
||
<div v-if="!showPaymentProcessing" class="space-y-12 pb-[50vh] pt-12">
|
||
<div class="mb-6">
|
||
<h1 class="text-2xl font-bold text-gray-900 mb-2">新建服务器</h1>
|
||
<p class="text-sm text-gray-600">
|
||
请选择服务器配置和支付方式,点击"创建"后将自动为您开通。
|
||
</p>
|
||
</div>
|
||
|
||
<div class="space-y-6">
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">区域选择</label>
|
||
<select v-model="selectedRegionId" class="w-full border rounded px-3 py-2" required @change="onRegionChange">
|
||
<option value="">请选择区域</option>
|
||
<option v-for="region in regions" :key="getRegionId(region)" :value="getRegionId(region)">
|
||
{{ getRegionName(region) }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">镜像选择(Jsite服务器推荐选择Ubuntu-22.04)</label>
|
||
<select v-model="selectedImageId" class="w-full border rounded px-3 py-2" required :disabled="!selectedRegionId" @change="onImageChange">
|
||
<option value="">请选择镜像</option>
|
||
<option v-for="image in images" :key="getImageId(image)" :value="getImageId(image)">
|
||
{{ getImageDisplayName(image) }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">套餐选择</label>
|
||
<select v-model="selectedPlanId" class="w-full border rounded px-3 py-2" required :disabled="!selectedImageId">
|
||
<option value="">请选择套餐</option>
|
||
<option v-for="plan in filteredPlans" :key="plan.plan_id" :value="plan.plan_id">
|
||
{{ getPlanDisplayName(plan) }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">购买时长</label>
|
||
<select v-model="period" class="w-full border rounded px-3 py-2">
|
||
<option v-for="p in periods" :key="p.value" :value="p.value">{{ p.label }}</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 价格信息显示 -->
|
||
<div v-if="selectedPlanId && selectedImageId" class="border-t border-gray-200 pt-4">
|
||
<div class="flex justify-between items-center">
|
||
<div class="text-sm text-gray-600">月度费用</div>
|
||
<div class="font-medium">
|
||
¥ {{ getSelectedPlanPrice() }}
|
||
<span class="text-gray-500 text-sm">(月付)</span>
|
||
</div>
|
||
</div>
|
||
<div class="flex justify-between items-center mt-2">
|
||
<div class="text-sm text-gray-600">购买时长</div>
|
||
<div class="font-medium">{{ period }} 个月</div>
|
||
</div>
|
||
<div class="flex justify-between items-center mt-2 text-lg font-bold">
|
||
<div>总计</div>
|
||
<div>¥ {{ getTotalAmount() }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 支付方式选择 -->
|
||
<div class="border-t border-gray-200 pt-4">
|
||
<label class="block text-sm font-medium text-gray-700 mb-3">
|
||
选择支付方式
|
||
</label>
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-2">
|
||
<button
|
||
class="p-4 border rounded-lg flex flex-col items-center justify-center hover:bg-gray-50 transition-all"
|
||
:class="{'border-blue-500 border-2 shadow-sm': selectedPaymentMethod === 'balance', 'border-gray-200': selectedPaymentMethod !== 'balance'}"
|
||
@click="selectedPaymentMethod = 'balance'"
|
||
>
|
||
<span class="text-gray-800 font-medium">余额支付</span>
|
||
</button>
|
||
|
||
<button
|
||
class="p-4 border rounded-lg hover:bg-gray-50 transition-all"
|
||
:class="{'border-blue-500 border-2 shadow-sm': selectedPaymentMethod === 'alipay', 'border-gray-200': selectedPaymentMethod !== 'alipay'}"
|
||
@click="selectedPaymentMethod = 'alipay'"
|
||
>
|
||
<div class="flex flex-col items-center">
|
||
<div class="mb-2">
|
||
<AlipayLogo class="h-8" />
|
||
</div>
|
||
</div>
|
||
</button>
|
||
|
||
<button
|
||
class="p-4 border rounded-lg hover:bg-gray-50 transition-all"
|
||
:class="{'border-blue-500 border-2 shadow-sm': selectedPaymentMethod === 'wechatpay', 'border-gray-200': selectedPaymentMethod !== 'wechatpay'}"
|
||
@click="selectedPaymentMethod = 'wechatpay'"
|
||
>
|
||
<div class="flex flex-col items-center">
|
||
<div class="mb-2">
|
||
<WeChatPayLogo class="h-8" />
|
||
</div>
|
||
</div>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="error" class="p-3 bg-red-50 text-red-700 rounded-md text-sm">
|
||
{{ error }}
|
||
</div>
|
||
|
||
<!-- 创建按钮 -->
|
||
<div class="pt-4">
|
||
<button
|
||
type="button"
|
||
class="w-full px-4 py-2 bg-[#1fc76f] border border-transparent rounded-md text-sm font-medium text-white hover:bg-[#19b862] focus:outline-none"
|
||
@click="createInstance"
|
||
:disabled="isLoading"
|
||
>
|
||
{{ isLoading ? '处理中...' : '创建' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 第二步:处理支付 -->
|
||
<div v-else class="space-y-12 pb-[50vh] pt-12">
|
||
<!-- 加载中状态 -->
|
||
<div v-if="isProcessingPayment" class="text-center py-8">
|
||
<div class="h-12 w-12 mx-auto animate-spin text-blue-600 mb-4 flex items-center justify-center">
|
||
<i class="fe fe-loader text-3xl"></i>
|
||
</div>
|
||
<p class="text-gray-700 text-lg">正在处理支付,请稍候...</p>
|
||
</div>
|
||
|
||
<!-- 支付成功状态 -->
|
||
<div v-else-if="paymentSuccess" class="text-center py-8">
|
||
<div class="flex justify-center mb-6">
|
||
<div class="rounded-full bg-green-100 p-3">
|
||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
<h3 class="text-xl font-medium text-gray-900 mb-2">支付成功!</h3>
|
||
<p class="text-gray-600 mb-4">
|
||
您的订单已支付成功,服务器记录已创建。服务器正在后台创建中,创建并启动需要 3-5 分钟,请耐心等待。
|
||
</p>
|
||
<p class="text-gray-500 text-sm">
|
||
您可以在服务器列表中查看服务器状态,创建完成后状态将更新为"Running"。
|
||
</p>
|
||
<div class="mt-6">
|
||
<button
|
||
type="button"
|
||
class="px-4 py-2 bg-[#1fc76f] border border-transparent rounded-md text-sm font-medium text-white hover:bg-[#19b862] focus:outline-none"
|
||
@click="goToServerList"
|
||
>
|
||
返回服务器列表
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 微信支付状态 -->
|
||
<div v-else-if="selectedPaymentMethod === 'wechatpay' && paymentQrCode" class="text-center">
|
||
<div class="relative mb-6">
|
||
<div class="flex items-center justify-center">
|
||
<WeChatPayLogo class="h-10" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="text-center mb-6">
|
||
<div class="text-sm text-gray-600 mb-2">扫一扫付款(元)</div>
|
||
<div class="text-3xl font-bold text-[#FF0036]">{{ order?.total_amount }} 元</div>
|
||
</div>
|
||
|
||
<div class="flex justify-center">
|
||
<div class="qrcode-container bg-white p-4 border border-gray-100 shadow-sm rounded-lg">
|
||
<img
|
||
:src="paymentQrCodeImage"
|
||
alt="微信支付二维码"
|
||
class="qrcode-image"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-6 text-center">
|
||
<p class="text-gray-600">
|
||
请使用微信扫描二维码完成支付
|
||
</p>
|
||
<p class="text-gray-500 text-sm mt-2">二维码有效期 15 分钟</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 支付宝支付状态 -->
|
||
<div v-else-if="selectedPaymentMethod === 'alipay' && paymentUrl" class="text-center py-6">
|
||
<div class="mb-6">
|
||
<AlipayLogo class="h-10 mx-auto" />
|
||
</div>
|
||
|
||
<h3 class="text-lg font-medium text-gray-900 mb-4">请在新页面完成支付宝支付</h3>
|
||
<p class="text-gray-600 mb-6">
|
||
如果没有自动跳转,请点击下方按钮打开支付页面
|
||
</p>
|
||
<div class="space-y-4">
|
||
<button
|
||
class="w-full px-6 py-3 bg-[#1677FF] text-white rounded-lg hover:bg-[#0E5FD8] transition-colors shadow-sm"
|
||
@click="window.open(paymentUrl, '_blank')"
|
||
>
|
||
打开支付页面
|
||
</button>
|
||
<p class="text-gray-600 text-sm mt-4">
|
||
支付完成后,请稍等片刻,系统会自动刷新页面
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="error" class="p-3 bg-red-50 text-red-700 rounded-md text-sm">
|
||
{{ error }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { toast } from 'vue-sonner';
|
||
import { DashboardError } from '../utils/error';
|
||
import AlipayLogo from '../logo/AlipayLogo.vue';
|
||
import WeChatPayLogo from '../logo/WeChatPayLogo.vue';
|
||
import router from '../router';
|
||
|
||
export default {
|
||
name: 'NewJsiteServer',
|
||
components: {
|
||
AlipayLogo,
|
||
WeChatPayLogo
|
||
},
|
||
data() {
|
||
return {
|
||
selectedRegionId: '',
|
||
selectedPlanId: '',
|
||
selectedImageId: '',
|
||
period: 1,
|
||
selectedPaymentMethod: null, // 支付方式
|
||
regions: [],
|
||
plans: [],
|
||
images: [],
|
||
periods: [
|
||
{ value: 1, label: '1个月' },
|
||
{ value: 3, label: '3个月' },
|
||
{ value: 6, label: '6个月' },
|
||
{ value: 12, label: '1年' },
|
||
{ value: 24, label: '2年' },
|
||
{ value: 36, label: '3年' }
|
||
],
|
||
isLoading: false,
|
||
error: null,
|
||
success: false,
|
||
// 支付相关状态
|
||
order: null,
|
||
server: null, // 服务器记录信息
|
||
showPaymentProcessing: false,
|
||
paymentSuccess: false,
|
||
isProcessingPayment: false,
|
||
paymentUrl: null,
|
||
paymentQrCode: null,
|
||
paymentQrCodeImage: null,
|
||
checkInterval: null
|
||
};
|
||
},
|
||
resources: {
|
||
aliyunRegions() {
|
||
return {
|
||
url: 'jcloud.api.aliyun_server_light.get_aliyun_regions',
|
||
onSuccess(response) {
|
||
// 后端返回格式: {success: true, data: {...}, message: '...'}
|
||
const data = response.data || response;
|
||
|
||
// 处理不同的数据结构可能性
|
||
let regionsData = [];
|
||
|
||
if (data.regions) {
|
||
// 直接有regions字段
|
||
regionsData = data.regions;
|
||
} else if (data.Regions) {
|
||
// 阿里云API可能返回Regions字段
|
||
regionsData = data.Regions;
|
||
} else if (Array.isArray(data)) {
|
||
// 直接是数组
|
||
regionsData = data;
|
||
} else if (data.body && data.body.regions) {
|
||
// 嵌套在body中
|
||
regionsData = data.body.regions;
|
||
} else if (data.body && data.body.Regions) {
|
||
// 嵌套在body中,字段名大写
|
||
regionsData = data.body.Regions;
|
||
}
|
||
|
||
if (Array.isArray(regionsData) && regionsData.length > 0) {
|
||
this.regions = regionsData;
|
||
} else {
|
||
this.error = '区域数据格式不正确或为空';
|
||
}
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '获取区域失败';
|
||
}
|
||
};
|
||
},
|
||
aliyunPlans() {
|
||
return {
|
||
url: 'jcloud.api.aliyun_server_light.get_aliyun_plans',
|
||
onSuccess(response) {
|
||
const data = response.data || response;
|
||
this.plans = data.plans || [];
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '获取套餐失败';
|
||
}
|
||
};
|
||
},
|
||
aliyunImages() {
|
||
return {
|
||
url: 'jcloud.api.aliyun_server_light.get_aliyun_images',
|
||
onSuccess(response) {
|
||
const data = response.data || response;
|
||
|
||
// 处理不同的数据结构可能性
|
||
let imagesData = [];
|
||
|
||
if (data.images) {
|
||
// 直接有images字段
|
||
imagesData = data.images;
|
||
} else if (data.Images) {
|
||
// 阿里云API可能返回Images字段
|
||
imagesData = data.Images;
|
||
} else if (Array.isArray(data)) {
|
||
// 直接是数组
|
||
imagesData = data;
|
||
} else if (data.body && data.body.images) {
|
||
// 嵌套在body中
|
||
imagesData = data.body.images;
|
||
} else if (data.body && data.body.Images) {
|
||
// 嵌套在body中,字段名大写
|
||
imagesData = data.body.Images;
|
||
}
|
||
|
||
if (Array.isArray(imagesData) && imagesData.length > 0) {
|
||
this.images = imagesData;
|
||
} else {
|
||
this.error = '镜像数据格式不正确或为空';
|
||
}
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '获取镜像失败';
|
||
}
|
||
};
|
||
},
|
||
// 创建服务器订单
|
||
createServerOrder() {
|
||
return {
|
||
url: 'jcloud.api.aliyun_server_light.create_server_order',
|
||
validate() {
|
||
if (!this.selectedRegionId || !this.selectedPlanId || !this.selectedImageId) {
|
||
throw new DashboardError('请选择完整配置');
|
||
}
|
||
if (!this.selectedPaymentMethod) {
|
||
throw new DashboardError('请选择支付方式');
|
||
}
|
||
},
|
||
onSuccess(data) {
|
||
if (!data.success) {
|
||
this.error = data.message || '创建服务器订单失败';
|
||
return;
|
||
}
|
||
|
||
// 显示订单支付界面
|
||
this.order = data.order;
|
||
this.server = data.server; // 保存服务器记录信息
|
||
this.showPaymentProcessing = true;
|
||
|
||
// 立即处理支付
|
||
this.processPayment();
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '创建服务器订单失败';
|
||
}
|
||
};
|
||
},
|
||
// 处理余额支付
|
||
processBalancePayment() {
|
||
return {
|
||
url: 'jcloud.api.billing.process_balance_payment_for_server_order',
|
||
validate() {
|
||
if (!this.order || !this.order.order_id) {
|
||
throw new DashboardError('缺少订单信息');
|
||
}
|
||
},
|
||
onSuccess(response) {
|
||
if (response.status === "Error" || response.success === false) {
|
||
toast.error(response.message || '支付失败,请确保余额充足');
|
||
this.error = response.message || '余额不足';
|
||
this.isProcessingPayment = false;
|
||
return;
|
||
}
|
||
|
||
const orderData = {
|
||
...this.order,
|
||
...(response.order || {}),
|
||
status: '已支付'
|
||
};
|
||
|
||
// 同时发送服务器记录信息
|
||
const serverData = {
|
||
...this.server
|
||
};
|
||
|
||
this.isProcessingPayment = false;
|
||
this.paymentSuccess = true;
|
||
|
||
// 支付成功后跳转到服务器列表
|
||
setTimeout(() => {
|
||
this.$router.push('/jsite-servers');
|
||
}, 30000);
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '余额支付处理失败';
|
||
this.isProcessingPayment = false;
|
||
}
|
||
};
|
||
},
|
||
// 处理支付宝支付
|
||
processAlipayPayment() {
|
||
return {
|
||
url: 'jcloud.api.billing.process_alipay_order',
|
||
validate() {
|
||
if (!this.order || !this.order.order_id) {
|
||
throw new DashboardError('缺少订单信息');
|
||
}
|
||
},
|
||
onSuccess(response) {
|
||
this.paymentUrl = response.payment_url;
|
||
window.open(response.payment_url, '_blank');
|
||
|
||
toast.success('支付页面已在新窗口打开');
|
||
|
||
// 开始轮询支付状态
|
||
this.startPaymentCheck();
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '支付宝支付处理失败';
|
||
this.isProcessingPayment = false;
|
||
}
|
||
};
|
||
},
|
||
// 处理微信支付
|
||
processWechatPayment() {
|
||
return {
|
||
url: 'jcloud.api.billing.process_wechatpay_order',
|
||
validate() {
|
||
if (!this.order || !this.order.order_id) {
|
||
throw new DashboardError('缺少订单信息');
|
||
}
|
||
},
|
||
onSuccess(response) {
|
||
this.paymentQrCode = response.payment_url;
|
||
this.paymentQrCodeImage = response.qr_code_image || null;
|
||
|
||
// 开始轮询支付状态
|
||
this.startPaymentCheck();
|
||
},
|
||
onError(error) {
|
||
this.error = error.message || '微信支付处理失败';
|
||
this.isProcessingPayment = false;
|
||
}
|
||
};
|
||
},
|
||
// 检查支付状态
|
||
checkPaymentStatus() {
|
||
return {
|
||
url: 'jcloud.api.billing.check_order_payment_status',
|
||
params: {
|
||
order_id: this.order?.order_id
|
||
},
|
||
validate() {
|
||
if (!this.order || !this.order.order_id) {
|
||
throw new DashboardError('缺少订单信息');
|
||
}
|
||
},
|
||
onSuccess(data) {
|
||
if (data && data.status === '已支付') {
|
||
// 支付成功,停止轮询
|
||
this.stopPaymentCheck();
|
||
|
||
const orderData = { ...this.order, ...(data.order || {}) };
|
||
|
||
// 同时发送服务器记录信息
|
||
const serverData = {
|
||
...this.server
|
||
};
|
||
|
||
this.paymentSuccess = true;
|
||
|
||
// 支付成功后跳转到服务器列表
|
||
setTimeout(() => {
|
||
this.$router.push('/jsite-servers');
|
||
}, 30000);
|
||
}
|
||
}
|
||
};
|
||
},
|
||
|
||
},
|
||
computed: {
|
||
filteredPlans() {
|
||
// 如果没有选择镜像,返回空数组
|
||
if (!this.selectedImageId) {
|
||
return [];
|
||
}
|
||
|
||
// 获取选择的镜像信息
|
||
const selectedImage = this.images.find(img => this.getImageId(img) === this.selectedImageId);
|
||
if (!selectedImage) {
|
||
return [];
|
||
}
|
||
|
||
// 获取镜像平台信息
|
||
const imagePlatform = selectedImage.platform || '';
|
||
|
||
// 根据镜像平台过滤套餐
|
||
return this.plans.filter(plan => {
|
||
const supportPlatform = plan.support_platform;
|
||
if (!supportPlatform) {
|
||
return true; // 如果没有support_platform信息,默认显示
|
||
}
|
||
|
||
try {
|
||
// 解析support_platform字段(JSON字符串格式)
|
||
const platforms = JSON.parse(supportPlatform);
|
||
return platforms.includes(imagePlatform);
|
||
} catch (e) {
|
||
// 如果解析失败,尝试字符串匹配
|
||
return supportPlatform.includes(imagePlatform);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
beforeUnmount() {
|
||
this.stopPaymentCheck();
|
||
},
|
||
mounted() {
|
||
this.$resources.aliyunRegions.submit();
|
||
},
|
||
methods: {
|
||
async onRegionChange() {
|
||
this.selectedPlanId = '';
|
||
this.selectedImageId = '';
|
||
this.plans = [];
|
||
this.images = [];
|
||
|
||
if (this.selectedRegionId) {
|
||
// 只加载镜像,套餐将在选择镜像后加载
|
||
await this.$resources.aliyunImages.submit({
|
||
region_id: this.selectedRegionId,
|
||
image_type: 'system' // 明确指定镜像类型
|
||
});
|
||
}
|
||
},
|
||
async onImageChange() {
|
||
this.selectedPlanId = '';
|
||
this.plans = [];
|
||
if (this.selectedImageId) {
|
||
await this.$resources.aliyunPlans.submit({
|
||
region_id: this.selectedRegionId
|
||
});
|
||
}
|
||
},
|
||
async createInstance() {
|
||
if (!this.selectedRegionId || !this.selectedPlanId || !this.selectedImageId) {
|
||
this.error = '请选择完整配置';
|
||
return;
|
||
}
|
||
if (!this.selectedPaymentMethod) {
|
||
this.error = '请选择支付方式';
|
||
return;
|
||
}
|
||
|
||
this.error = null;
|
||
this.isLoading = true;
|
||
|
||
await this.$resources.createServerOrder.submit({
|
||
plan_id: this.selectedPlanId,
|
||
image_id: this.selectedImageId,
|
||
period: this.period,
|
||
region_id: this.selectedRegionId,
|
||
payment_method: this.selectedPaymentMethod
|
||
});
|
||
|
||
this.isLoading = false;
|
||
},
|
||
startPaymentCheck() {
|
||
this.isProcessingPayment = false;
|
||
|
||
this.checkInterval = setInterval(() => {
|
||
this.$resources.checkPaymentStatus.submit();
|
||
}, 3000);
|
||
|
||
// 15分钟后停止检查
|
||
setTimeout(() => {
|
||
this.stopPaymentCheck();
|
||
}, 900000);
|
||
},
|
||
stopPaymentCheck() {
|
||
if (this.checkInterval) {
|
||
clearInterval(this.checkInterval);
|
||
this.checkInterval = null;
|
||
}
|
||
},
|
||
processPayment() {
|
||
this.isProcessingPayment = true;
|
||
this.error = null;
|
||
|
||
if (!this.order || !this.order.order_id) {
|
||
this.error = '订单信息不完整,请重试';
|
||
this.isProcessingPayment = false;
|
||
return;
|
||
}
|
||
|
||
if (this.selectedPaymentMethod === 'balance') {
|
||
this.$resources.processBalancePayment.submit({
|
||
order_id: this.order.order_id
|
||
});
|
||
} else if (this.selectedPaymentMethod === 'alipay') {
|
||
this.$resources.processAlipayPayment.submit({
|
||
order_id: this.order.order_id
|
||
});
|
||
} else if (this.selectedPaymentMethod === 'wechatpay') {
|
||
this.$resources.processWechatPayment.submit({
|
||
order_id: this.order.order_id
|
||
});
|
||
}
|
||
},
|
||
goToServerList() {
|
||
this.$router.push('/jsite-servers');
|
||
},
|
||
|
||
getRegionId(region) {
|
||
return region.region_id || region.RegionId || region.id;
|
||
},
|
||
getRegionName(region) {
|
||
return region.local_name || region.region_name || region.RegionName || region.name;
|
||
},
|
||
getPlanDisplayName(plan) {
|
||
// 根据阿里云API返回的数据结构显示套餐信息
|
||
const cpu = plan.core || plan.cpu || '未知';
|
||
const memory = plan.memory || '未知';
|
||
const disk = plan.disk_size || plan.system_disk_size || '未知';
|
||
const bandwidth = plan.bandwidth || '未知';
|
||
const price = plan.origin_price || '未知';
|
||
const planType = plan.plan_type || '';
|
||
const publicIpNum = plan.public_ip_num || 0;
|
||
|
||
// 处理内存显示(如果是小数,转换为MB)
|
||
let memoryDisplay = memory;
|
||
if (typeof memory === 'number' && memory < 1) {
|
||
memoryDisplay = Math.round(memory * 1024) + 'MB';
|
||
} else if (typeof memory === 'number') {
|
||
memoryDisplay = memory + 'GB';
|
||
}
|
||
|
||
// 处理带宽显示
|
||
let bandwidthDisplay = bandwidth;
|
||
if (typeof bandwidth === 'number') {
|
||
bandwidthDisplay = bandwidth + 'Mbps';
|
||
}
|
||
|
||
// 根据plan_type添加类型前缀
|
||
let typePrefix = '';
|
||
switch (planType) {
|
||
case 'NORMAL':
|
||
typePrefix = '通用型 - ';
|
||
break;
|
||
case 'MULTI_IP':
|
||
typePrefix = '多公网IP型 - ';
|
||
break;
|
||
case 'INTERNATIONAL':
|
||
typePrefix = '国际型 - ';
|
||
break;
|
||
case 'CAPACITY':
|
||
typePrefix = '容量型 - ';
|
||
break;
|
||
default:
|
||
typePrefix = '';
|
||
}
|
||
|
||
return `${typePrefix}${cpu}核/${memoryDisplay}/${disk}GB/${bandwidthDisplay}/${publicIpNum}个公网IP - ¥${price}/月`;
|
||
},
|
||
getSelectedPlanPrice() {
|
||
const selectedPlan = this.filteredPlans.find(plan => plan.plan_id === this.selectedPlanId);
|
||
return selectedPlan ? (selectedPlan.origin_price || 0) : 0;
|
||
},
|
||
getTotalAmount() {
|
||
const monthlyPrice = this.getSelectedPlanPrice();
|
||
return (monthlyPrice * this.period).toFixed(2);
|
||
},
|
||
getImageId(image) {
|
||
return image.image_id || image.ImageId || image.id;
|
||
},
|
||
getImageDisplayName(image) {
|
||
// 根据阿里云API返回的数据结构显示镜像信息
|
||
const name = image.image_name || image.name || image.ImageName || image.Name || '未知镜像';
|
||
const platform = image.platform || '';
|
||
const description = image.description || '';
|
||
|
||
// 显示格式:镜像名称 (平台)
|
||
if (platform) {
|
||
return `${name} (${platform})`;
|
||
}
|
||
return name;
|
||
},
|
||
getPaymentMethodName(method) {
|
||
const methodNames = {
|
||
'balance': '余额支付',
|
||
'alipay': '支付宝',
|
||
'wechatpay': '微信支付'
|
||
};
|
||
return methodNames[method] || '未知方式';
|
||
}
|
||
},
|
||
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.qrcode-container {
|
||
height: 250px;
|
||
width: 250px;
|
||
margin: 0 auto;
|
||
padding: 5px;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 12px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.qrcode-image {
|
||
height: 100%;
|
||
width: 100%;
|
||
object-fit: contain;
|
||
}
|
||
|
||
/* 添加渐入动画 */
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(10px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
</style>
|