jcloud/dashboard/src2/components/JsiteDomainRenewalDialog.vue

222 lines
6.7 KiB
Vue

<template>
<div class="p-6">
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-900 mb-2">域名续费</h2>
<p class="text-sm text-gray-600">
为域名 <span class="font-medium">{{ domainDoc?.domain }}</span> 续费
</p>
</div>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">续费时长</label>
<select v-model="renewalPeriod" class="w-full border rounded px-3 py-2">
<option v-for="period in renewalPeriods" :key="period.value" :value="period.value">
{{ period.label }}
</option>
</select>
</div>
<div v-if="domainPrice" 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">
¥ {{ domainPrice }}
<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">{{ renewalPeriod }} </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">
<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>
<div class="flex justify-end gap-3 mt-6">
<button
@click="$emit('close')"
class="px-4 py-2 text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 transition-colors"
>
取消
</button>
<button
@click="processRenewal"
:disabled="!selectedPaymentMethod || isLoading"
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:bg-gray-300 transition-colors"
>
{{ isLoading ? '处理中...' : '确认续费' }}
</button>
</div>
</div>
</template>
<script>
import { toast } from 'vue-sonner';
import AlipayLogo from '../logo/AlipayLogo.vue';
import WeChatPayLogo from '../logo/WeChatPayLogo.vue';
export default {
name: 'JsiteDomainRenewalDialog',
components: {
AlipayLogo,
WeChatPayLogo
},
props: {
domain: {
type: String,
required: true
},
domainDoc: {
type: Object,
required: true
},
onSuccess: {
type: Function,
default: () => {}
}
},
data() {
return {
renewalPeriod: 1,
selectedPaymentMethod: null,
domainPrice: null,
renewalPeriods: [
{ value: 1, label: '1年' },
{ value: 2, label: '2年' },
{ value: 3, label: '3年' },
{ value: 5, label: '5年' },
{ value: 10, label: '10年' }
],
isLoading: false,
error: null
};
},
mounted() {
this.getDomainPrice();
},
methods: {
async getDomainPrice() {
try {
const response = await this.$resources.getDomainPrice.submit({
domain: this.domainDoc.domain,
year: 1
});
if (response && response.data && response.data.price) {
this.domainPrice = response.data.price;
} else {
this.domainPrice = this.domainDoc.price || 50;
}
} catch (error) {
this.domainPrice = this.domainDoc.price || 50;
}
},
getTotalAmount() {
const yearlyPrice = this.domainPrice || 0;
return (yearlyPrice * this.renewalPeriod).toFixed(2);
},
async processRenewal() {
if (!this.selectedPaymentMethod) {
this.error = '请选择支付方式';
return;
}
this.error = null;
this.isLoading = true;
try {
const response = await this.$resources.renewDomain.submit({
domain: this.domainDoc.domain,
period: this.renewalPeriod,
payment_method: this.selectedPaymentMethod
});
if (response.success) {
toast.success('续费请求已提交');
this.$emit('close');
this.onSuccess(response);
} else {
this.error = response.message || '续费失败';
}
} catch (error) {
this.error = error.message || '续费失败';
} finally {
this.isLoading = false;
}
}
},
resources: {
getDomainPrice() {
return {
url: 'jcloud.api.domain_west.get_west_domain_price',
onSuccess(response) {
if (response && response.data && response.data.price) {
this.domainPrice = response.data.price;
}
},
onError(error) {
this.domainPrice = this.domainDoc.price || 50;
}
};
},
renewDomain() {
return {
url: 'jcloud.api.domain_west.west_domain_renew',
onSuccess(response) {
return response;
},
onError(error) {
throw error;
}
};
}
}
};
</script>