Files
AIGC/demo/frontend/src/components/PaymentModal.vue

1206 lines
34 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>
<el-dialog
v-model="visible"
:title="title"
width="500px"
class="payment-modal"
:modal="true"
:close-on-click-modal="false"
:close-on-press-escape="true"
@close="handleClose"
:show-close="true"
custom-class="payment-modal-dialog"
:modal-class="'payment-modal-overlay'"
>
<div class="payment-content">
<!-- 支付方式选择 -->
<div class="payment-methods">
<div
class="payment-method"
:class="{ active: selectedMethod === 'alipay' }"
@click="selectMethod('alipay')"
>
<div class="method-icon alipay-icon">
<el-icon><CreditCard /></el-icon>
</div>
<span>支付宝支付</span>
</div>
<div
class="payment-method"
:class="{ active: selectedMethod === 'paypal' }"
@click="selectMethod('paypal')"
>
<div class="method-icon paypal-icon">
<el-icon><CreditCard /></el-icon>
</div>
<span>PayPal支付</span>
</div>
</div>
<!-- 金额显示 -->
<div class="amount-section">
<div class="amount-label">金额</div>
<div class="amount-value">${{ amount }}</div>
</div>
<!-- 支付宝支付区域 -->
<div v-if="selectedMethod === 'alipay'" class="alipay-section">
<div class="alipay-info">
<div class="alipay-logo">
<svg width="100" height="32" viewBox="0 0 100 32" fill="none">
<text x="0" y="24" font-family="Arial" font-size="20" font-weight="bold" fill="#1677FF">支付宝</text>
</svg>
</div>
<p class="alipay-desc">安全便捷的在线支付方式</p>
<p class="alipay-desc-small">点击下方按钮跳转到支付宝完成支付</p>
</div>
<button
class="alipay-pay-button"
@click="handlePay"
:disabled="loading"
>
<span v-if="!loading">前往支付宝支付</span>
<span v-else>正在跳转...</span>
</button>
</div>
<!-- PayPal支付按钮区域 -->
<div v-if="selectedMethod === 'paypal'" class="paypal-section">
<div class="paypal-info">
<div class="paypal-logo">
<svg width="100" height="32" viewBox="0 0 100 32" fill="none">
<text x="0" y="24" font-family="Arial" font-size="20" font-weight="bold" fill="#0070BA">PayPal</text>
</svg>
</div>
<p class="paypal-desc">安全便捷的国际支付方式</p>
<p class="paypal-desc-small">点击下方按钮跳转到PayPal完成支付</p>
</div>
<button
class="paypal-pay-button"
@click="handlePay"
:disabled="loading"
>
<span v-if="!loading">前往PayPal支付</span>
<span v-else>正在跳转...</span>
</button>
</div>
<!-- 底部链接 -->
<div class="footer-link">
<a href="#" @click.prevent="showAgreement">Vionow支付服务条款</a>
</div>
</div>
</el-dialog>
</template>
<script setup>
import { ref, watch, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { CreditCard } from '@element-plus/icons-vue'
import { createPayment, createAlipayPayment, createPayPalPayment, getPaymentById, getPayPalPaymentStatus } from '@/api/payments'
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
title: {
type: String,
default: '标准版会员'
},
amount: {
type: [String, Number],
default: '32.00'
},
orderId: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:modelValue', 'pay-success', 'pay-error'])
const router = useRouter()
const visible = ref(false)
const selectedMethod = ref('alipay')
const loading = ref(false)
const currentPaymentId = ref(null)
let paymentPollingTimer = null
let isPaymentStarted = false // 防止重复调用
let lastPlanType = '' // 记录上一次的套餐类型
// 从orderId中提取套餐类型如 SUB_standard_xxx -> standard
const getPlanTypeFromOrderId = (orderId) => {
if (!orderId) return ''
const parts = orderId.split('_')
return parts.length >= 2 ? parts[1] : ''
}
// 监听 modelValue 变化
watch(() => props.modelValue, (newVal) => {
visible.value = newVal
// 当模态框打开时,检查是否需要创建新订单
if (newVal) {
const currentPlanType = getPlanTypeFromOrderId(props.orderId)
// 如果套餐类型变化了重置paymentId
if (currentPlanType !== lastPlanType) {
console.log('套餐变化,重置 paymentId旧套餐:', lastPlanType, '新套餐:', currentPlanType)
currentPaymentId.value = null
lastPlanType = currentPlanType
} else {
console.log('同一套餐,复用 paymentId:', currentPaymentId.value)
}
// 重置状态
isPaymentStarted = false
}
// 关闭时重置标志
if (!newVal) {
isPaymentStarted = false
}
})
// 监听 visible 变化
watch(visible, (newVal) => {
emit('update:modelValue', newVal)
// 如果模态框关闭,停止轮询
if (!newVal) {
stopPaymentPolling()
}
})
// 选择支付方式
const selectMethod = async (method) => {
if (selectedMethod.value !== method) {
console.log('切换支付方式:', selectedMethod.value, '->', method, '复用 paymentId:', currentPaymentId.value)
selectedMethod.value = method
// 如果已有支付记录更新支付方式和描述复用paymentId
if (currentPaymentId.value) {
try {
const newDescription = `${props.title} - ${method === 'paypal' ? 'PayPal' : '支付宝'}支付`
const newMethod = method === 'paypal' ? 'PAYPAL' : 'ALIPAY'
console.log('=== 开始更新支付方式 ===')
console.log('paymentId:', currentPaymentId.value)
console.log('newMethod:', newMethod)
console.log('newDescription:', newDescription)
const response = await fetch(`/api/payments/${currentPaymentId.value}/method`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
body: JSON.stringify({
method: newMethod,
description: newDescription
})
})
console.log('API响应状态:', response.status)
const responseData = await response.json()
console.log('API响应数据:', responseData)
if (response.ok && responseData.success) {
console.log('✅ 支付方式更新成功复用paymentId:', currentPaymentId.value)
} else {
console.error('❌ 支付方式更新失败:', responseData.message || response.statusText)
}
} catch (error) {
console.error('❌ 更新支付方式异常:', error)
}
}
}
}
// 处理支付
const handlePay = async () => {
try {
loading.value = true
// 如果还没有创建支付记录,先创建
if (!currentPaymentId.value) {
// 直接使用传入的orderId不再添加时间戳Subscription.vue已经处理了
const paymentData = {
orderId: props.orderId,
amount: props.amount.toString(),
method: selectedMethod.value === 'paypal' ? 'PAYPAL' : 'ALIPAY',
description: `${props.title} - ${selectedMethod.value === 'paypal' ? 'PayPal' : '支付宝'}支付`
}
console.log('=== 创建支付记录 ===')
console.log('支付数据:', paymentData)
const createResponse = await createPayment(paymentData)
console.log('创建支付订单响应:', createResponse)
if (createResponse.data && createResponse.data.success) {
currentPaymentId.value = createResponse.data.data.id
console.log('支付记录创建成功ID', currentPaymentId.value)
} else {
throw new Error(createResponse.data?.message || '创建支付记录失败')
}
} else {
// 已有支付记录,确保支付方式和描述与当前选择一致
try {
const newDescription = `${props.title} - ${selectedMethod.value === 'paypal' ? 'PayPal' : '支付宝'}支付`
const newMethod = selectedMethod.value === 'paypal' ? 'PAYPAL' : 'ALIPAY'
await fetch(`/api/payments/${currentPaymentId.value}/method`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
body: JSON.stringify({
method: newMethod,
description: newDescription
})
})
console.log('支付方式已同步:', newMethod)
} catch (e) {
console.warn('同步支付方式失败,继续支付:', e)
}
}
// 根据选择的支付方式处理
if (selectedMethod.value === 'paypal') {
await handlePayPalPayment()
} else {
await handleAlipayPayment()
}
} catch (error) {
console.error('=== 支付流程出错 ===')
console.error('错误详情:', error)
console.error('错误响应:', error.response)
console.error('错误状态:', error.response?.status)
console.error('错误数据:', error.response?.data)
ElMessage.error(`支付失败:${error.message || '请重试'}`)
emit('pay-error', error)
} finally {
loading.value = false
}
}
// 处理支付宝支付
const handleAlipayPayment = async () => {
ElMessage.info('正在创建支付宝支付...')
const paymentId = currentPaymentId.value
console.log('=== 开始支付宝支付流程 ===')
console.log('使用已创建的支付ID', paymentId)
// 创建支付宝支付
const alipayResponse = await createAlipayPayment({ paymentId })
console.log('支付宝支付响应:', alipayResponse)
if (alipayResponse.data && alipayResponse.data.success) {
const responseData = alipayResponse.data.data
// 检查是否是电脑网页支付返回HTML表单
if (responseData.payType === 'PAGE_PAY' && responseData.payForm) {
console.log('使用电脑网页支付,跳转到支付宝页面')
ElMessage.success('正在跳转到支付宝支付页面...')
// 创建一个临时的div来渲染表单并自动提交
const div = document.createElement('div')
div.innerHTML = responseData.payForm
document.body.appendChild(div)
// 找到表单并提交
const form = div.querySelector('form')
if (form) {
form.submit()
} else {
console.error('未找到支付表单')
ElMessage.error('支付页面生成失败')
document.body.removeChild(div)
}
return
}
console.error('支付宝响应格式未知:', responseData)
ElMessage.error('支付创建失败,请重试')
} else {
console.error('支付宝响应失败:', alipayResponse)
ElMessage.error(alipayResponse.data?.message || '支付创建失败')
emit('pay-error', new Error(alipayResponse.data?.message || '支付创建失败'))
}
}
// 处理PayPal支付
const handlePayPalPayment = async () => {
ElMessage.info('正在创建PayPal支付...')
const paymentId = currentPaymentId.value
console.log('=== 开始PayPal支付流程 ===')
console.log('使用已创建的支付ID', paymentId)
const response = await createPayPalPayment({ paymentId })
console.log('PayPal支付响应', response)
if (response.data && response.data.success) {
const paymentUrl = response.data.paymentUrl
console.log('PayPal支付URL:', paymentUrl)
ElMessage.success('正在跳转到PayPal支付页面...')
// 跳转到PayPal支付页面
window.location.href = paymentUrl
} else {
console.error('PayPal支付创建失败', response)
ElMessage.error(response.data?.message || 'PayPal支付创建失败')
emit('pay-error', new Error(response.data?.message || 'PayPal支付创建失败'))
}
}
// 轮询支付状态
const startPaymentPolling = (paymentId) => {
// 清除之前的轮询
stopPaymentPolling()
let pollCount = 0
const maxPolls = 200 // 最多轮询200次10分钟每3秒一次
const pollInterval = 3000 // 3秒轮询一次更快响应支付成功
const poll = async () => {
if (pollCount >= maxPolls) {
console.log('轮询达到最大次数,停止轮询')
stopPaymentPolling()
return
}
try {
console.log(`轮询支付状态 (${pollCount + 1}/${maxPolls})支付ID:`, paymentId)
const response = await getPaymentById(paymentId)
console.log('轮询响应:', response.data)
if (response.data && response.data.success) {
const payment = response.data.data
// 兼容枚举可能是字符串或对象的情况
const rawStatus = payment.status
// 更全面地解析状态:可能是字符串、对象、或者对象的属性
let status = rawStatus
if (typeof rawStatus === 'object' && rawStatus !== null) {
status = rawStatus.name || rawStatus.value || rawStatus.toString()
}
// 转为大写以便比较
const statusUpper = String(status).toUpperCase()
console.log('支付状态原始值:', rawStatus, '类型:', typeof rawStatus, '解析后:', status, '大写:', statusUpper)
if (statusUpper === 'SUCCESS' || statusUpper === 'COMPLETED') {
console.log('✅ 支付成功!支付数据:', payment)
stopPaymentPolling()
ElMessage.success('支付成功!')
emit('pay-success', payment)
// 重置状态,下次购买生成新订单
currentPaymentId.value = null
lastPlanType = ''
// 延迟关闭模态框
setTimeout(() => {
visible.value = false
}, 2000)
return
} else if (statusUpper === 'FAILED' || statusUpper === 'CANCELLED') {
console.log('支付失败或取消')
stopPaymentPolling()
ElMessage.warning('支付已取消或失败')
emit('pay-error', new Error('支付已取消或失败'))
return
} else if (statusUpper === 'PROCESSING') {
console.log('支付处理中...')
// PROCESSING 状态继续轮询
} else if (statusUpper === 'PENDING') {
console.log('支付待处理中(等待支付宝回调)...')
// PENDING 状态继续轮询
} else {
console.log('未知状态:', statusUpper, '继续轮询...')
}
} else {
console.warn('轮询响应失败:', response.data)
}
// 继续轮询
pollCount++
paymentPollingTimer = setTimeout(poll, pollInterval)
} catch (error) {
console.error('轮询支付状态失败:', error)
// 错误时也继续轮询,直到达到最大次数
pollCount++
if (pollCount < maxPolls) {
paymentPollingTimer = setTimeout(poll, pollInterval)
}
}
}
// 开始轮询等待2秒后开始第一次轮询更快响应
setTimeout(() => {
poll()
}, 2000)
}
// 停止轮询支付状态
const stopPaymentPolling = () => {
if (paymentPollingTimer) {
clearTimeout(paymentPollingTimer)
paymentPollingTimer = null
console.log('已停止轮询支付状态')
}
}
// 手动检查支付状态
const manualCheckPayment = async () => {
if (!currentPaymentId.value) {
ElMessage.warning('请先生成支付二维码')
return
}
ElMessage.info('正在查询支付状态...')
try {
const response = await getPaymentById(currentPaymentId.value)
if (response.data && response.data.success) {
const payment = response.data.data
// 兼容枚举可能是字符串或对象的情况
const rawStatus = payment.status
// 更全面地解析状态
let status = rawStatus
if (typeof rawStatus === 'object' && rawStatus !== null) {
status = rawStatus.name || rawStatus.value || rawStatus.toString()
}
const statusUpper = String(status).toUpperCase()
console.log('手动查询支付状态原始值:', rawStatus, '类型:', typeof rawStatus, '解析后:', status, '大写:', statusUpper)
if (statusUpper === 'SUCCESS' || statusUpper === 'COMPLETED') {
stopPaymentPolling()
ElMessage.success('支付成功!')
emit('pay-success', payment)
// 重置状态,下次购买生成新订单
currentPaymentId.value = null
lastPlanType = ''
setTimeout(() => {
visible.value = false
}, 1500)
} else if (statusUpper === 'FAILED' || statusUpper === 'CANCELLED') {
ElMessage.warning('支付已取消或失败')
} else {
ElMessage.info(`支付尚未完成(状态:${statusUpper}),请完成支付后再试`)
}
}
} catch (error) {
console.error('查询支付状态失败:', error)
ElMessage.error('查询失败,请稍后重试')
}
}
// 关闭模态框
const handleClose = () => {
stopPaymentPolling()
visible.value = false
}
// 组件卸载时清理轮询
onUnmounted(() => {
stopPaymentPolling()
})
// 获取支付状态描述
const getStatusDescription = (status) => {
const statusMap = {
'PENDING': '待支付 - 等待用户扫码支付',
'PROCESSING': '处理中 - 支付宝正在处理支付',
'SUCCESS': '支付成功',
'COMPLETED': '支付完成',
'FAILED': '支付失败',
'CANCELLED': '已取消',
'REFUNDED': '已退款'
}
return statusMap[status] || '未知状态'
}
// 显示协议
const showAgreement = () => {
router.push('/terms-of-service')
}
</script>
<style scoped>
.payment-modal {
background: #000000 !important;
}
/* 移除所有可能的白边和边框 */
.payment-modal :deep(.el-dialog),
.payment-modal-dialog,
.payment-modal :deep(.el-dialog.el-dialog--center.payment-modal),
.payment-modal :deep(.el-dialog.el-dialog--center),
.payment-modal.el-dialog.el-dialog--center.payment-modal,
.payment-modal :deep(.el-dialog.el-dialog--center.payment-modal-dialog),
.payment-modal :deep(.payment-modal-dialog.el-dialog.el-dialog--center.payment-modal) {
background: #000000 !important;
background-color: #000000 !important;
background-image: none !important;
border-radius: 12px !important;
border: none !important;
border-width: 0 !important;
border-style: none !important;
border-color: transparent !important;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), inset 0 0 0 0 transparent !important;
padding: 0 !important;
margin: 0 !important;
outline: none !important;
outline-width: 0 !important;
outline-style: none !important;
outline-color: transparent !important;
box-sizing: border-box !important;
overflow: hidden !important;
/* 移除所有可能的白色边框 */
-webkit-box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), inset 0 0 0 0 transparent !important;
-moz-box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), inset 0 0 0 0 transparent !important;
}
/* 移除所有伪元素可能产生的边框 */
.payment-modal :deep(.el-dialog::before),
.payment-modal :deep(.el-dialog::after),
.payment-modal :deep(.el-dialog__wrapper::before),
.payment-modal :deep(.el-dialog__wrapper::after),
.payment-modal :deep(.el-dialog__body::before),
.payment-modal :deep(.el-dialog__body::after) {
display: none !important;
content: none !important;
border: none !important;
outline: none !important;
box-shadow: none !important;
}
/* 移除所有可能的白色边框 - 使用更具体的选择器 */
.payment-modal :deep(.el-dialog),
.payment-modal :deep(.el-dialog *) {
border-left: none !important;
border-right: none !important;
border-top: none !important;
border-bottom: none !important;
}
.payment-modal :deep(.el-dialog__body) {
padding: 0 !important;
margin: 0 !important;
background: #000000 !important;
background-color: #000000 !important;
border: none !important;
border-width: 0 !important;
border-style: none !important;
border-color: transparent !important;
outline: none !important;
outline-width: 0 !important;
outline-style: none !important;
outline-color: transparent !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
/* 移除对话框内部的所有边框和间隙 */
.payment-modal :deep(.el-dialog) * {
border-color: transparent !important;
}
/* 确保对话框本身没有任何白色背景或边框 */
.payment-modal :deep(.el-dialog),
.payment-modal :deep(.el-dialog.el-dialog--center.payment-modal),
.payment-modal :deep(.el-dialog.el-dialog--center),
.payment-modal :deep(.payment-modal-dialog),
.payment-modal :deep(.payment-modal-dialog.el-dialog),
.payment-modal :deep(.payment-modal-dialog.el-dialog--center),
.payment-modal :deep(.payment-modal-dialog.el-dialog--center.payment-modal) {
background-color: #000000 !important;
background: #000000 !important;
background-image: none !important;
}
/* 移除所有可能的白色边框 */
.payment-modal :deep(.el-dialog),
.payment-modal :deep(.el-dialog__body) {
border: 0 !important;
border-top: none !important;
border-bottom: none !important;
border-left: none !important;
border-right: none !important;
border-width: 0 !important;
border-style: none !important;
border-color: transparent !important;
}
.payment-modal :deep(.el-dialog__header),
.payment-modal :deep(.el-dialog__header.show-close) {
background: #000000 !important;
background-color: #000000 !important;
border: none !important;
border-bottom: 1px solid #1a1a1a !important;
border-top: none !important;
border-left: none !important;
border-right: none !important;
border-width: 0 !important;
border-bottom-width: 1px !important;
border-bottom-style: solid !important;
border-bottom-color: #1a1a1a !important;
padding: 20px 24px !important;
margin: 0 !important;
color: white !important;
text-align: left !important;
}
/* 确保 header.show-close 内的所有文字都是白色 */
.payment-modal :deep(.el-dialog__header.show-close),
.payment-modal :deep(.el-dialog__header.show-close *),
.payment-modal :deep(.el-dialog__header.show-close .el-dialog__title),
.payment-modal :deep(.el-dialog__header.show-close .el-dialog__headerbtn) {
color: white !important;
}
/* 确保关闭按钮区域背景也与模态框一致 */
.payment-modal :deep(.el-dialog__headerbtn),
.payment-modal :deep(.el-dialog__headerbtn.is-close),
.payment-modal :deep(.el-dialog__header .el-dialog__headerbtn) {
background: transparent !important;
background-color: transparent !important;
}
.payment-modal :deep(.el-dialog__headerbtn:hover) {
background: rgba(255, 255, 255, 0.1) !important;
background-color: rgba(255, 255, 255, 0.1) !important;
}
.payment-modal :deep(.el-dialog__wrapper) {
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-width: 0 !important;
border-style: none !important;
border-color: transparent !important;
outline: none !important;
outline-width: 0 !important;
outline-style: none !important;
outline-color: transparent !important;
background: transparent !important;
}
/* 确保 wrapper 内的所有对话框元素背景为黑色 */
.payment-modal :deep(.el-dialog__wrapper .el-dialog),
.payment-modal :deep(.el-dialog__wrapper .el-dialog.el-dialog--center),
.payment-modal :deep(.el-dialog__wrapper .el-dialog.el-dialog--center.payment-modal),
.payment-modal :deep(.el-dialog__wrapper .payment-modal-dialog) {
background: #000000 !important;
background-color: #000000 !important;
}
.payment-modal :deep(.el-overlay),
.payment-modal :deep(.payment-modal-overlay),
.payment-modal :deep(.el-overlay.payment-modal-overlay),
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog) {
background: rgba(0, 0, 0, 0.5) !important;
border: none !important;
outline: none !important;
}
/* 确保 el-overlay.payment-modal-overlay.el-modal-dialog 内的对话框背景为黑色 */
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog .el-dialog),
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog .el-dialog.el-dialog--center),
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog .el-dialog.el-dialog--center.payment-modal),
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog .el-dialog__body),
.payment-modal :deep(.el-overlay.payment-modal-overlay.el-modal-dialog .el-dialog__header) {
background: #000000 !important;
background-color: #000000 !important;
}
.payment-modal :deep(.el-overlay-dialog) {
background: rgba(0, 0, 0, 0.5) !important;
border: none !important;
outline: none !important;
}
/* 确保 el-overlay-dialog 内的对话框背景为黑色 */
.payment-modal :deep(.el-overlay-dialog .el-dialog),
.payment-modal :deep(.el-overlay-dialog .el-dialog.el-dialog--center),
.payment-modal :deep(.el-overlay-dialog .el-dialog.el-dialog--center.payment-modal),
.payment-modal :deep(.el-overlay-dialog .el-dialog__body),
.payment-modal :deep(.el-overlay-dialog .el-dialog__header) {
background: #000000 !important;
background-color: #000000 !important;
}
/* 确保遮罩层没有白边 */
.payment-modal :deep(.el-overlay.is-message-box) {
background: rgba(0, 0, 0, 0.5) !important;
}
.payment-modal :deep(.el-dialog__title) {
color: #ffffff !important;
font-size: 18px !important;
font-weight: bold !important;
font-family: "SimSun", "宋体", serif !important;
text-align: left !important;
line-height: 1.5 !important;
letter-spacing: 0.5px !important;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 0 10px rgba(255, 255, 255, 0.3) !important;
filter: brightness(1.1) contrast(1.2) !important;
}
.payment-modal :deep(.el-dialog__headerbtn) {
color: white !important;
}
.payment-modal :deep(.el-dialog__headerbtn:hover) {
color: white !important;
}
.payment-modal :deep(.el-dialog__headerbtn svg) {
color: white !important;
fill: white !important;
}
.payment-content {
padding: 24px;
background: #000000 !important;
background-color: #000000 !important;
color: white !important;
margin: 0 !important;
border: none !important;
border-width: 0 !important;
box-sizing: border-box !important;
}
/* 确保 payment-content 内的所有文字都是白色(链接除外) */
.payment-content,
.payment-content *:not(a),
.payment-content p,
.payment-content span,
.payment-content div {
color: white !important;
}
/* 支付方式选择 */
.payment-methods {
display: flex;
gap: 12px;
margin-bottom: 24px;
}
.payment-method {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
background: #1a1a1a;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
color: white;
}
.payment-method:hover {
background: #2a2a2a;
box-shadow: 0 4px 16px rgba(74, 158, 255, 0.2);
}
.payment-method.active {
background: linear-gradient(135deg, #4a9eff 0%, #3a8bdf 100%);
color: white;
box-shadow: 0 4px 16px rgba(74, 158, 255, 0.3);
}
.method-icon {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: #1677FF;
}
.paypal-icon {
color: #0070BA;
}
.payment-method.active .method-icon {
color: white;
}
.payment-method span {
font-size: 14px !important;
font-weight: 500 !important;
color: white !important;
line-height: 1.5 !important;
letter-spacing: 0.3px !important;
}
/* 金额显示 */
.amount-section {
text-align: center;
margin-bottom: 24px;
}
.amount-label {
font-size: 14px !important;
color: white !important;
margin-bottom: 8px !important;
font-weight: 400 !important;
line-height: 1.5 !important;
letter-spacing: 0.3px !important;
}
.amount-value {
font-size: 32px !important;
font-weight: 700 !important;
color: white !important;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important;
line-height: 1.2 !important;
letter-spacing: 0.5px !important;
}
/* PayPal支付区域 */
.paypal-section {
text-align: center;
margin-bottom: 24px;
padding: 32px 24px;
background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.paypal-info {
margin-bottom: 24px;
}
.paypal-logo {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px;
}
.paypal-desc {
color: white !important;
font-size: 16px !important;
font-weight: 500 !important;
margin: 8px 0 !important;
line-height: 1.5 !important;
}
.paypal-desc-small {
color: rgba(255, 255, 255, 0.7) !important;
font-size: 13px !important;
font-weight: 400 !important;
margin: 4px 0 !important;
line-height: 1.5 !important;
}
.paypal-pay-button {
width: 100%;
padding: 16px 24px;
background: linear-gradient(135deg, #0070BA 0%, #005EA6 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(0, 112, 186, 0.3);
}
.paypal-pay-button:hover:not(:disabled) {
background: linear-gradient(135deg, #005EA6 0%, #004A85 100%);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 112, 186, 0.4);
}
.paypal-pay-button:active:not(:disabled) {
transform: translateY(0);
}
.paypal-pay-button:disabled {
background: #666;
cursor: not-allowed;
opacity: 0.6;
transform: none;
}
/* 支付宝支付区域 */
.alipay-section {
text-align: center;
margin-bottom: 24px;
padding: 32px 24px;
background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.alipay-info {
margin-bottom: 24px;
}
.alipay-logo {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px;
}
.alipay-desc {
color: white !important;
font-size: 16px !important;
font-weight: 500 !important;
margin: 8px 0 !important;
line-height: 1.5 !important;
}
.alipay-desc-small {
color: rgba(255, 255, 255, 0.7) !important;
font-size: 13px !important;
font-weight: 400 !important;
margin: 4px 0 !important;
line-height: 1.5 !important;
}
.alipay-pay-button {
width: 100%;
padding: 16px 24px;
background: linear-gradient(135deg, #1677FF 0%, #0958d9 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(22, 119, 255, 0.3);
}
.alipay-pay-button:hover:not(:disabled) {
background: linear-gradient(135deg, #0958d9 0%, #003eb3 100%);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(22, 119, 255, 0.4);
}
.alipay-pay-button:active:not(:disabled) {
transform: translateY(0);
}
.alipay-pay-button:disabled {
background: #666;
cursor: not-allowed;
opacity: 0.6;
transform: none;
}
/* 二维码区域 */
.qr-section {
text-align: center;
margin-bottom: 24px;
}
.qr-code {
width: 200px;
height: 200px;
margin: 0 auto 16px;
padding: 0;
background: #1a1a1a;
border: none;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
overflow: hidden;
box-sizing: border-box;
position: relative;
line-height: 0;
}
.qr-code img {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: none;
display: block;
object-fit: contain;
object-position: center;
background: #1a1a1a;
box-sizing: border-box;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
.qr-placeholder {
width: 200px;
height: 200px;
background: transparent;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.qr-placeholder svg {
width: 100%;
height: 100%;
border-radius: 10px;
}
.qr-tip {
font-size: 12px !important;
color: white !important;
line-height: 1.5 !important;
letter-spacing: 0.2px !important;
font-weight: 400 !important;
}
/* 操作按钮 */
.action-section {
margin-bottom: 16px;
}
.pay-button {
width: 100%;
padding: 14px;
background: #4a9eff;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.pay-button:hover {
background: #3a8bdf;
transform: translateY(-1px);
}
.pay-button:active {
transform: translateY(0);
}
.pay-button:disabled {
background: #666;
cursor: not-allowed;
transform: none;
}
.pay-button:disabled:hover {
background: #666;
transform: none;
}
/* 支付提示 */
.pay-tip {
text-align: center;
padding: 20px;
background: #1a1a1a;
border-radius: 8px;
border: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.pay-tip p {
margin: 8px 0 !important;
color: white !important;
font-size: 14px !important;
line-height: 1.6 !important;
letter-spacing: 0.3px !important;
font-weight: 400 !important;
}
.tip-small {
color: white !important;
font-size: 12px !important;
line-height: 1.5 !important;
letter-spacing: 0.2px !important;
font-weight: 400 !important;
opacity: 0.8 !important;
}
/* 底部链接 */
.footer-link {
text-align: center;
}
.footer-link a {
color: #4a9eff !important;
text-decoration: none !important;
font-size: 12px !important;
transition: color 0.3s ease !important;
line-height: 1.5 !important;
letter-spacing: 0.2px !important;
font-weight: 400 !important;
}
.footer-link a:hover {
color: #3a8bdf !important;
}
/* 我已完成支付按钮 */
.check-payment-btn {
width: 100%;
padding: 12px 24px;
margin-top: 16px;
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.check-payment-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #059669 0%, #047857 100%);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(16, 185, 129, 0.4);
}
.check-payment-btn:disabled {
background: #4a4a4a;
cursor: not-allowed;
opacity: 0.6;
}
/* 响应式设计 */
@media (max-width: 768px) {
.payment-modal :deep(.el-dialog) {
width: 90%;
margin: 0 auto;
}
.payment-methods {
flex-direction: column;
}
.qr-code {
width: 160px;
height: 160px;
}
.qr-placeholder {
width: 140px;
height: 140px;
}
.amount-value {
font-size: 28px;
}
}
</style>