fix: 充值体验修复——回调写星尘流水(明细页有记录)+重推幂等+退款回调写流水+充值成功返回我的+我的页onShow刷新余额
This commit is contained in:
@@ -108,7 +108,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
|
import { onShow, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { knowledgeApi, aiChatApi, request } from '@/utils/api'
|
import { knowledgeApi, aiChatApi, request } from '@/utils/api'
|
||||||
@@ -174,9 +174,15 @@ const quotaPercent = computed(() => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadStats()
|
loadStats()
|
||||||
if (userStore.isLoggedIn) {
|
if (userStore.isLoggedIn) {
|
||||||
loadVpayInfo()
|
|
||||||
userStore.fetchMe()
|
userStore.fetchMe()
|
||||||
loadCollected()
|
loadCollected()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 每次进入/返回本页都刷新余额与额度(充值页支付成功后返回时余额同步)
|
||||||
|
onShow(() => {
|
||||||
|
if (userStore.isLoggedIn) {
|
||||||
|
loadVpayInfo()
|
||||||
loadQuota()
|
loadQuota()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -120,8 +120,16 @@ async function recharge() {
|
|||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
uni.showToast({ title: '充值成功!', icon: 'success' })
|
uni.showToast({ title: '充值成功!', icon: 'success' })
|
||||||
// 刷新余额
|
// 刷新余额后返回"我的"(该页 onShow 会重新拉取余额与额度)
|
||||||
info.value = await request('GET', '/api/vpay/info', null, userStore.token)
|
try {
|
||||||
|
info.value = await request('GET', '/api/vpay/info', null, userStore.token)
|
||||||
|
} catch (e) {}
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
fail: () => uni.switchTab({ url: '/pages/profile/profile' }),
|
||||||
|
})
|
||||||
|
}, 1200)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e.message || '支付未完成'
|
const msg = e.message || '支付未完成'
|
||||||
if (msg.includes('cancel')) {
|
if (msg.includes('cancel')) {
|
||||||
|
|||||||
+49
-26
@@ -48,7 +48,7 @@ module.exports = function registerWxMsgRoutes(app) {
|
|||||||
const event = fields.Event || fields.event || ''
|
const event = fields.Event || fields.event || ''
|
||||||
console.log('[wx-msg] 收到推送 Event=' + event, JSON.stringify(fields).slice(0, 500))
|
console.log('[wx-msg] 收到推送 Event=' + event, JSON.stringify(fields).slice(0, 500))
|
||||||
|
|
||||||
// 代币充值到账:改写用户星尘余额 + 订单状态
|
// 代币充值到账:改写用户星尘余额 + 订单状态 + 写星尘流水(明细页数据源)
|
||||||
if (event === 'xpay_coin_pay_notify') {
|
if (event === 'xpay_coin_pay_notify') {
|
||||||
try {
|
try {
|
||||||
const { User, Order, CoinLedger } = require('../models')
|
const { User, Order, CoinLedger } = require('../models')
|
||||||
@@ -61,43 +61,66 @@ module.exports = function registerWxMsgRoutes(app) {
|
|||||||
)
|
)
|
||||||
console.log(`[wx-msg] 充值回调解析: order=${outTradeNo} coins=${coins} coinInfo=${JSON.stringify(coinInfo)}`)
|
console.log(`[wx-msg] 充值回调解析: order=${outTradeNo} coins=${coins} coinInfo=${JSON.stringify(coinInfo)}`)
|
||||||
if (outTradeNo && coins > 0) {
|
if (outTradeNo && coins > 0) {
|
||||||
// 先查订单,没有也直接给用户加币(Attach 里带了 uid)
|
// 幂等:微信会重推,同一订单只入账一次(以流水为准)
|
||||||
const order = await Order.findOne({ orderNo: outTradeNo })
|
const dup = await CoinLedger.findOne({ orderNo: outTradeNo, type: 'recharge' })
|
||||||
if (order && order.status === 'pending') {
|
if (dup) {
|
||||||
await Order.updateOne({ _id: order._id }, { status: 'paid', paidAt: new Date() })
|
console.log(`[wx-msg] 重复推送已忽略: ${outTradeNo}`)
|
||||||
await User.updateOne({ _id: order.userId }, { $inc: { vpayCoins: coins } })
|
|
||||||
console.log(`[wx-msg] ✓ 星尘充值到账(有订单): ${outTradeNo} +${coins} → user=${order.userId}`)
|
|
||||||
} else {
|
} else {
|
||||||
// 订单可能未落库或已处理——从 Attach 里拿 uid 直接加
|
const order = await Order.findOne({ orderNo: outTradeNo })
|
||||||
try {
|
if (order && order.status === 'refunded') {
|
||||||
const attach = typeof coinInfo === 'object' ? coinInfo.Attach || '' : ''
|
console.log(`[wx-msg] 订单已退款,跳过重复入账: ${outTradeNo}`)
|
||||||
const uid = attach ? JSON.parse(attach).uid : ''
|
} else {
|
||||||
if (uid) {
|
// userId 优先取订单,缺失时从 Attach 兜底解析
|
||||||
await User.updateOne({ _id: uid }, { $inc: { vpayCoins: coins } })
|
let uid = order ? String(order.userId) : ''
|
||||||
if (order) await Order.updateOne({ _id: order._id }, { status: 'paid', paidAt: new Date() })
|
if (!uid) {
|
||||||
console.log(`[wx-msg] ✓ 星尘充值到账(从Attach): ${outTradeNo} +${coins} → user=${uid}`)
|
try {
|
||||||
} else if (order) {
|
const attach = typeof coinInfo === 'object' ? coinInfo.Attach || '' : ''
|
||||||
await Order.updateOne({ _id: order._id }, { status: 'paid', paidAt: new Date() })
|
uid = attach ? JSON.parse(attach).uid || '' : ''
|
||||||
await User.updateOne({ _id: order.userId }, { $inc: { vpayCoins: coins } })
|
} catch (e2) { console.error('[wx-msg] Attach解析失败:', e2.message) }
|
||||||
console.log(`[wx-msg] ✓ 星尘充值到账(订单补偿): ${outTradeNo} +${coins}`)
|
}
|
||||||
|
if (uid) {
|
||||||
|
const u = await User.findOneAndUpdate({ _id: uid }, { $inc: { vpayCoins: coins } }, { new: true })
|
||||||
|
if (u) {
|
||||||
|
await CoinLedger.create({
|
||||||
|
openid: u.openid, userId: u._id, type: 'recharge', amount: coins,
|
||||||
|
balanceAfter: u.vpayCoins || 0, description: '星尘充值', orderNo: outTradeNo,
|
||||||
|
})
|
||||||
|
if (order && order.status === 'pending') {
|
||||||
|
await Order.updateOne({ _id: order._id }, { status: 'paid', paidAt: new Date() })
|
||||||
|
}
|
||||||
|
console.log(`[wx-msg] ✓ 星尘充值到账: ${outTradeNo} +${coins} → user=${uid} 余额=${u.vpayCoins}`)
|
||||||
}
|
}
|
||||||
} catch (e2) { console.error('[wx-msg] Attach解析失败:', e2.message) }
|
} else {
|
||||||
|
console.error(`[wx-msg] 充值到账失败: 找不到订单和Attach uid, order=${outTradeNo}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { console.error('[wx-msg] 充值到账失败:', e.message) }
|
} catch (e) { console.error('[wx-msg] 充值到账失败:', e.message) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退款:扣回星尘
|
// 退款:扣回星尘 + 写流水(仅处理管理后台之外直接发起的退款;后台退款时订单已标 refunded,此处自动跳过)
|
||||||
if (event === 'xpay_refund_notify') {
|
if (event === 'xpay_refund_notify') {
|
||||||
try {
|
try {
|
||||||
const { User, Order, CoinLedger } = require('../models')
|
const { User, Order, CoinLedger } = require('../models')
|
||||||
const outTradeNo = fields.OutTradeNo || ''
|
const outTradeNo = fields.OutTradeNo || ''
|
||||||
|
const dup = await CoinLedger.findOne({ orderNo: outTradeNo, type: 'refund' })
|
||||||
const order = await Order.findOne({ orderNo: outTradeNo, status: 'paid' })
|
const order = await Order.findOne({ orderNo: outTradeNo, status: 'paid' })
|
||||||
if (order) {
|
if (order && !dup) {
|
||||||
await Order.updateOne({ _id: order._id }, { status: 'refunded' })
|
const coins = (order.metadata || {}).coins || Math.round((order.amount || 0) * 100) || 0
|
||||||
const coins = (order.metadata || {}).coins || 0
|
if (coins > 0) {
|
||||||
if (coins > 0) await User.updateOne({ _id: order.userId }, { $inc: { vpayCoins: -coins } })
|
const u = await User.findOneAndUpdate({ _id: order.userId }, { $inc: { vpayCoins: -coins } }, { new: true })
|
||||||
console.log(`[wx-msg] 星尘退款: ${outTradeNo} -${coins}`)
|
await Order.updateOne({ _id: order._id }, { status: 'refunded' })
|
||||||
|
if (u) {
|
||||||
|
await CoinLedger.create({
|
||||||
|
openid: u.openid, userId: u._id, type: 'refund', amount: -coins,
|
||||||
|
balanceAfter: u.vpayCoins || 0, description: '退款扣回', orderNo: outTradeNo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log(`[wx-msg] 星尘退款: ${outTradeNo} -${coins}`)
|
||||||
|
} else {
|
||||||
|
await Order.updateOne({ _id: order._id }, { status: 'refunded' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { console.error('[wx-msg] 退款处理失败:', e.message) }
|
} catch (e) { console.error('[wx-msg] 退款处理失败:', e.message) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user