项目重构: 整理目录结构, 更新前后端代码, 添加测试和数据库迁移
This commit is contained in:
@@ -140,14 +140,39 @@ const qrCodeUrl = ref('') // 二维码URL
|
||||
const showQrCode = ref(false) // 是否显示二维码
|
||||
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 && !isPaymentStarted) {
|
||||
isPaymentStarted = true
|
||||
handlePay()
|
||||
// 当模态框打开时,检查是否需要创建新订单
|
||||
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)
|
||||
}
|
||||
|
||||
qrCodeUrl.value = ''
|
||||
showQrCode.value = false
|
||||
|
||||
// 只有选择支付宝时才自动生成二维码,PayPal需要用户点击按钮
|
||||
if (!isPaymentStarted && selectedMethod.value === 'alipay') {
|
||||
isPaymentStarted = true
|
||||
handlePay()
|
||||
}
|
||||
}
|
||||
// 关闭时重置标志
|
||||
if (!newVal) {
|
||||
@@ -158,7 +183,7 @@ watch(() => props.modelValue, (newVal) => {
|
||||
// 监听 visible 变化
|
||||
watch(visible, (newVal) => {
|
||||
emit('update:modelValue', newVal)
|
||||
// 如果模态框关闭,停止轮询并重置状态
|
||||
// 如果模态框关闭,停止轮询并重置二维码状态(但保留paymentId和lastPlanType用于同套餐复用)
|
||||
if (!newVal) {
|
||||
stopPaymentPolling()
|
||||
qrCodeUrl.value = ''
|
||||
@@ -167,13 +192,62 @@ watch(visible, (newVal) => {
|
||||
})
|
||||
|
||||
// 选择支付方式
|
||||
const selectMethod = (method) => {
|
||||
// 如果切换了支付方式,需要重置 paymentId,因为支付方式不同需要创建新的支付记录
|
||||
const selectMethod = async (method) => {
|
||||
if (selectedMethod.value !== method) {
|
||||
currentPaymentId.value = null
|
||||
console.log('切换支付方式,重置 paymentId')
|
||||
console.log('切换支付方式:', selectedMethod.value, '->', method, '复用 paymentId:', currentPaymentId.value)
|
||||
selectedMethod.value = method
|
||||
|
||||
// 重置二维码显示
|
||||
qrCodeUrl.value = ''
|
||||
showQrCode.value = false
|
||||
|
||||
// 如果已有支付记录,更新支付方式和描述(复用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)
|
||||
// 如果切换到支付宝,生成新二维码
|
||||
if (method === 'alipay') {
|
||||
await handleAlipayPayment()
|
||||
}
|
||||
} else {
|
||||
console.error('❌ 支付方式更新失败:', responseData.message || response.statusText)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 更新支付方式异常:', error)
|
||||
}
|
||||
} else {
|
||||
// 没有支付记录,如果是支付宝则自动创建
|
||||
if (method === 'alipay') {
|
||||
isPaymentStarted = true
|
||||
await handlePay()
|
||||
}
|
||||
}
|
||||
}
|
||||
selectedMethod.value = method
|
||||
}
|
||||
|
||||
// 处理支付
|
||||
@@ -183,10 +257,9 @@ const handlePay = async () => {
|
||||
|
||||
// 如果还没有创建支付记录,先创建
|
||||
if (!currentPaymentId.value) {
|
||||
// 生成唯一的订单ID,加上时间戳避免重复
|
||||
const uniqueOrderId = `${props.orderId}_${Date.now()}`
|
||||
// 直接使用传入的orderId,不再添加时间戳(Subscription.vue已经处理了)
|
||||
const paymentData = {
|
||||
orderId: uniqueOrderId,
|
||||
orderId: props.orderId,
|
||||
amount: props.amount.toString(),
|
||||
method: selectedMethod.value === 'paypal' ? 'PAYPAL' : 'ALIPAY',
|
||||
description: `${props.title} - ${selectedMethod.value === 'paypal' ? 'PayPal' : '支付宝'}支付`
|
||||
@@ -204,6 +277,27 @@ const handlePay = async () => {
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 根据选择的支付方式处理
|
||||
@@ -332,6 +426,9 @@ const startPaymentPolling = (paymentId) => {
|
||||
stopPaymentPolling()
|
||||
ElMessage.success('支付成功!')
|
||||
emit('pay-success', payment)
|
||||
// 重置状态,下次购买生成新订单
|
||||
currentPaymentId.value = null
|
||||
lastPlanType = ''
|
||||
// 延迟关闭模态框
|
||||
setTimeout(() => {
|
||||
visible.value = false
|
||||
@@ -412,6 +509,9 @@ const manualCheckPayment = async () => {
|
||||
stopPaymentPolling()
|
||||
ElMessage.success('支付成功!')
|
||||
emit('pay-success', payment)
|
||||
// 重置状态,下次购买生成新订单
|
||||
currentPaymentId.value = null
|
||||
lastPlanType = ''
|
||||
setTimeout(() => {
|
||||
visible.value = false
|
||||
}, 1500)
|
||||
|
||||
Reference in New Issue
Block a user