jcloud/dashboard/src2/components/BuyPrepaidCreditsWeChatPay.vue
2025-04-12 17:39:38 +08:00

267 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<ErrorMessage
class="mt-3"
:message="$resources.createWeChatPayOrder.error || error"
/>
<div class="mt-4 flex w-full justify-end">
<Button
variant="solid"
class="wechat-pay-btn"
:loading="$resources.createWeChatPayOrder.loading || loading"
@click="processWeChatPayment"
>
使用微信支付
</Button>
</div>
<!-- 使用Teleport将弹窗移到body下 -->
<Teleport to="body">
<div v-if="showQRCode" class="wechat-qrcode-overlay">
<div class="wechat-qrcode-modal">
<div class="relative mb-4">
<div class="flex items-center justify-center">
<WeChatPayLogo />
</div>
<button @click="closeQRCode" class="close-button">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="text-center mb-5">
<div class="text-sm text-gray-600 mb-2">扫一扫付款</div>
<div class="text-3xl font-bold text-[#FF0036]">{{ amount }} </div>
</div>
<div class="flex justify-center">
<div v-if="qrCodeImage" class="qrcode-container">
<img :src="qrCodeImage" alt="微信支付二维码" class="qrcode-image" />
</div>
<div v-else class="qrcode-loading"></div>
</div>
<div class="mt-5 text-center text-sm">
<div class="text-gray-600">请使用微信扫描二维码完成支付</div>
<div class="text-gray-500 mt-1">二维码有效期 15 分钟</div>
</div>
</div>
</div>
</Teleport>
</div>
</template>
<script>
import { toast } from 'vue-sonner';
import { DashboardError } from '../utils/error';
import { Teleport } from 'vue'; // 确保导入Teleport
import WeChatPayLogo from '../logo/WeChatPayLogo.vue';
export default {
name: 'BuyPrepaidCreditsWeChatPay',
components: {
WeChatPayLogo
},
props: {
amount: {
default: 0
},
minimumAmount: {
default: 0
},
isOnboarding: {
default: false
}
},
data() {
return {
loading: false,
error: null,
showQRCode: false,
qrCodeUrl: null,
qrCodeImage: null,
orderId: null,
checkInterval: null
};
},
resources: {
createWeChatPayOrder() {
return {
url: 'jcloud.api.billing.create_wechatpay_order_for_recharge',
params: {
amount: this.amount
},
validate() {
if (this.amount <= 0) {
throw new DashboardError('支付金额必须大于0');
}
if (this.amount < this.minimumAmount) {
throw new DashboardError('金额低于最低要求金额');
}
},
onSuccess(response) {
console.log('微信支付响应:', response);
this.orderId = response.order_id;
this.qrCodeUrl = response.qr_code_url;
this.qrCodeImage = response.qr_code_image;
this.showQRCode = true;
this.startPaymentCheck();
}
};
},
checkPaymentStatus() {
return {
url: 'jcloud.api.billing.check_payment_status',
params: {
order_id: this.orderId,
payment_type: 'wechatpay'
},
onSuccess(data) {
if (data && (data.status === 'Success' || data.status === '已支付' || data.status === '交易成功')) {
this.stopPaymentCheck();
this.closeQRCode();
this.$emit('payment-success');
toast.success('支付成功');
}
}
};
}
},
methods: {
processWeChatPayment() {
this.$resources.createWeChatPayOrder.submit();
},
startPaymentCheck() {
this.checkInterval = setInterval(() => {
this.$resources.checkPaymentStatus.submit();
}, 3000);
},
stopPaymentCheck() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
},
checkPaymentStatus() {
this.$resources.checkPaymentStatus.submit();
},
closeQRCode() {
this.stopPaymentCheck();
this.showQRCode = false;
this.qrCodeUrl = null;
this.qrCodeImage = null;
}
},
beforeUnmount() {
this.stopPaymentCheck();
}
};
</script>
<style scoped>
.wechat-pay-btn {
background-color: #07C160 !important;
border: none;
color: white;
border-radius: 4px;
font-size: 1rem;
padding: 0.625rem 1.25rem;
transition: all 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.wechat-pay-btn:hover {
background-color: #06ad56 !important;
transform: translateY(-1px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}
/* 全新的弹窗样式 */
.wechat-qrcode-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 99999; /* 极高的z-index确保在最上层 */
}
.wechat-qrcode-modal {
background: white;
border-radius: 12px;
padding: 24px;
width: 90%;
max-width: 420px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
position: relative;
}
.close-button {
position: absolute;
top: -12px;
right: -12px;
background: #f3f4f6;
border-radius: 50%;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
color: #6b7280;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
transition: all 0.2s;
}
.close-button:hover {
background: #e5e7eb;
color: #374151;
transform: scale(1.05);
}
.qrcode-container {
height: 250px;
width: 250px;
margin: 0 auto;
padding: 5px;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
.qrcode-image {
height: 100%;
width: 100%;
object-fit: contain;
}
.qrcode-loading {
height: 250px;
width: 250px;
margin: 0 auto;
background-color: #f3f4f6;
border-radius: 8px;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% {
opacity: 0.6;
}
50% {
opacity: 0.8;
}
100% {
opacity: 0.6;
}
}
</style>