Files
卡若 aca006e1b2 feat: 完成20260315用户管理3全部5个功能
1. 链接人和事:补充CKB_OPEN_API_KEY/ACCOUNT配置,新增fix-ckb批量创建获客计划API
2. 规则配置:打通DB规则与ruleEngine,新增/api/miniprogram/user-rules接口,
   ruleEngine改为从API动态加载规则并按enabled状态执行
3. 获客计划:修复获客数统计中personId/token不匹配导致永远为0的bug,
   管理端新增"修复CKB密钥"按钮
4. 支付问题:修复钱包充值和代付分享中openId缺失导致400错误,
   添加getOpenId()兜底逻辑
5. 朋友圈分享:shareToMoments改为复制文章前200字+省略号+手指箭头emoji

Made-with: Cursor
2026-03-15 23:00:42 +08:00

178 lines
5.7 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
let openId = app.globalData.openId
if (!openId) {
openId = await app.getOpenId()
}
if (!openId) {
wx.showToast({ title: '获取支付凭证失败,请重新登录', icon: 'none', duration: 2500 })
return
}
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) {
const payRes = await app.request({
url: '/api/miniprogram/pay',
method: 'POST',
data: {
openId: openId,
productType: 'balance_recharge',
productId: res.data.orderSn,
amount: amount,
description: `余额充值 ¥${amount}`,
userId: userId,
}
})
const params = (payRes && payRes.data && payRes.data.payParams) ? payRes.data.payParams : (payRes && payRes.payParams ? payRes.payParams : null)
if (params) {
wx.requestPayment({
...params,
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()
console.error('[Wallet] recharge error:', e)
wx.showToast({ title: '充值失败:' + (e.message || e.errMsg || '网络异常'), icon: 'none', duration: 3000 })
}
},
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
wx.showModal({
title: '余额退款',
content: `退回全部余额 ¥${balance.toFixed(2)}\n\n退款将在1-3个工作日内原路返回`,
confirmText: '确认退款',
cancelText: '取消',
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()
},
})