- 数据概览:去掉代付统计独立卡片,总收入中以小标签显示代付金额 - 数据概览:移除余额统计区块(余额改在用户管理中展示) - 数据概览:恢复转化率卡片(唯一付费用户/总用户) - 用户管理:用户列表新增「余额/提现」列,显示钱包余额和已提现金额 - 后端:DBUsersList 增加 user_balances 查询,返回 walletBalance 字段 - 后端:User model 添加 WalletBalance 非数据库字段 - 包含之前的小程序埋点和管理后台点击统计面板 Made-with: Cursor
168 lines
5.3 KiB
JavaScript
168 lines
5.3 KiB
JavaScript
const app = getApp()
|
||
const { trackClick } = require('../../utils/trackClick')
|
||
|
||
Page({
|
||
data: {
|
||
statusBarHeight: 0,
|
||
balance: 0,
|
||
balanceText: '0.00',
|
||
totalRecharged: '0.00',
|
||
totalGifted: '0.00',
|
||
totalRefunded: '0.00',
|
||
transactions: [],
|
||
loading: true,
|
||
rechargeAmounts: [10, 30, 50, 1000],
|
||
selectedAmount: 30,
|
||
},
|
||
|
||
onLoad() {
|
||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
|
||
this.loadBalance()
|
||
this.loadTransactions()
|
||
},
|
||
|
||
async loadBalance() {
|
||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) return
|
||
const userId = app.globalData.userInfo.id
|
||
try {
|
||
const res = await app.request({ url: `/api/miniprogram/balance?userId=${userId}`, silent: true })
|
||
if (res && res.data) {
|
||
this.setData({
|
||
balance: res.data.balance || 0,
|
||
balanceText: (res.data.balance || 0).toFixed(2),
|
||
totalRecharged: (res.data.totalRecharged || 0).toFixed(2),
|
||
totalGifted: (res.data.totalGifted || 0).toFixed(2),
|
||
totalRefunded: (res.data.totalRefunded || 0).toFixed(2),
|
||
loading: false,
|
||
})
|
||
}
|
||
} catch (e) {
|
||
this.setData({ loading: false })
|
||
}
|
||
},
|
||
|
||
async loadTransactions() {
|
||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) return
|
||
const userId = app.globalData.userInfo.id
|
||
try {
|
||
const res = await app.request({ url: `/api/miniprogram/balance/transactions?userId=${userId}`, silent: true })
|
||
if (res && res.data) {
|
||
const list = (res.data || []).map(t => ({
|
||
...t,
|
||
amountText: (t.amount || 0).toFixed(2),
|
||
amountSign: (t.amount || 0) >= 0 ? '+' : '',
|
||
description: t.description || (t.type === 'recharge' ? '充值' : t.type === 'gift' ? '赠送' : t.type === 'refund' ? '退款' : t.type === 'consume' ? '阅读消费' : '其他'),
|
||
}))
|
||
this.setData({ transactions: list })
|
||
}
|
||
} catch (e) {
|
||
console.warn('[Wallet] load transactions failed', e)
|
||
}
|
||
},
|
||
|
||
selectAmount(e) {
|
||
trackClick('wallet', 'tab_click', '选择金额' + (e.currentTarget.dataset.amount || ''))
|
||
this.setData({ selectedAmount: parseInt(e.currentTarget.dataset.amount) })
|
||
},
|
||
|
||
async handleRecharge() {
|
||
trackClick('wallet', 'btn_click', '充值')
|
||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||
wx.showToast({ title: '请先登录', icon: 'none' })
|
||
return
|
||
}
|
||
const userId = app.globalData.userInfo.id
|
||
const amount = this.data.selectedAmount
|
||
|
||
wx.showLoading({ title: '创建订单...' })
|
||
try {
|
||
const res = await app.request({
|
||
url: '/api/miniprogram/balance/recharge',
|
||
method: 'POST',
|
||
data: { userId, amount }
|
||
})
|
||
wx.hideLoading()
|
||
if (res && res.data && res.data.orderSn) {
|
||
// Trigger WeChat Pay for the recharge order
|
||
const payRes = await app.request({
|
||
url: '/api/miniprogram/pay',
|
||
method: 'POST',
|
||
data: {
|
||
openId: app.globalData.openId,
|
||
productType: 'balance_recharge',
|
||
productId: res.data.orderSn,
|
||
amount: amount,
|
||
description: `余额充值 ¥${amount}`,
|
||
userId: userId,
|
||
}
|
||
})
|
||
if (payRes && payRes.payParams) {
|
||
wx.requestPayment({
|
||
...payRes.payParams,
|
||
success: async () => {
|
||
// Confirm the recharge
|
||
await app.request({
|
||
url: '/api/miniprogram/balance/recharge/confirm',
|
||
method: 'POST',
|
||
data: { orderSn: res.data.orderSn }
|
||
})
|
||
wx.showToast({ title: '充值成功', icon: 'success' })
|
||
this.loadBalance()
|
||
this.loadTransactions()
|
||
},
|
||
fail: () => {
|
||
wx.showToast({ title: '支付取消', icon: 'none' })
|
||
}
|
||
})
|
||
} else {
|
||
wx.showToast({ title: '创建支付失败', icon: 'none' })
|
||
}
|
||
}
|
||
} catch (e) {
|
||
wx.hideLoading()
|
||
wx.showToast({ title: '充值失败', icon: 'none' })
|
||
}
|
||
},
|
||
|
||
async handleRefund() {
|
||
trackClick('wallet', 'btn_click', '退款')
|
||
if (this.data.balance <= 0) {
|
||
wx.showToast({ title: '余额为零', icon: 'none' })
|
||
return
|
||
}
|
||
const userId = app.globalData.userInfo.id
|
||
const balance = this.data.balance
|
||
const refundAmount = (balance * 0.9).toFixed(2)
|
||
|
||
wx.showModal({
|
||
title: '余额退款',
|
||
content: `退回全部余额 ¥${balance.toFixed(2)}\n实际到账 ¥${refundAmount}(9折)\n\n退款将在1-3个工作日内原路返回`,
|
||
confirmText: '确认退款',
|
||
success: async (res) => {
|
||
if (!res.confirm) return
|
||
wx.showLoading({ title: '处理中...' })
|
||
try {
|
||
const result = await app.request({
|
||
url: '/api/miniprogram/balance/refund',
|
||
method: 'POST',
|
||
data: { userId, amount: balance }
|
||
})
|
||
wx.hideLoading()
|
||
if (result && result.data) {
|
||
wx.showToast({ title: result.data.message || '退款成功', icon: 'success' })
|
||
this.loadBalance()
|
||
this.loadTransactions()
|
||
}
|
||
} catch (e) {
|
||
wx.hideLoading()
|
||
wx.showToast({ title: '退款失败', icon: 'none' })
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
goBack() {
|
||
wx.navigateBack()
|
||
},
|
||
})
|