项目重构: 整理目录结构, 更新前后端代码, 添加测试和数据库迁移

This commit is contained in:
AIGC Developer
2025-12-30 10:24:19 +08:00
parent 5344148a1c
commit 38630dbb66
117 changed files with 1987 additions and 1316 deletions

View File

@@ -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)