feat: 数据概览简化 + 用户管理增加余额/提现列

- 数据概览:去掉代付统计独立卡片,总收入中以小标签显示代付金额
- 数据概览:移除余额统计区块(余额改在用户管理中展示)
- 数据概览:恢复转化率卡片(唯一付费用户/总用户)
- 用户管理:用户列表新增「余额/提现」列,显示钱包余额和已提现金额
- 后端:DBUsersList 增加 user_balances 查询,返回 walletBalance 字段
- 后端:User model 添加 WalletBalance 非数据库字段
- 包含之前的小程序埋点和管理后台点击统计面板

Made-with: Cursor
This commit is contained in:
卡若
2026-03-15 15:57:09 +08:00
parent 991e17698c
commit 708547d0dd
52 changed files with 3161 additions and 1103 deletions

View File

@@ -5,6 +5,7 @@
*/
const app = getApp()
const { trackClick } = require('../../utils/trackClick')
// 默认匹配类型配置
// 找伙伴:真正的匹配功能,匹配数据库中的真实用户
@@ -103,9 +104,7 @@ Page({
// 加载匹配配置
async loadMatchConfig() {
try {
const res = await app.request({ url: '/api/miniprogram/match/config', silent: true, method: 'GET',
method: 'GET'
})
const res = await app.request({ url: '/api/miniprogram/match/config', silent: true, method: 'GET' })
if (res.success && res.data) {
// 更新全局配置,导师顾问类型强制显示「导师顾问」
@@ -196,6 +195,7 @@ Page({
// 选择匹配类型
selectType(e) {
trackClick('match', 'tab_click', e.currentTarget.dataset.type || '类型选择')
const typeId = e.currentTarget.dataset.type
const type = MATCH_TYPES.find(t => t.id === typeId)
this.setData({
@@ -206,6 +206,7 @@ Page({
// 点击匹配按钮
async handleMatchClick() {
trackClick('match', 'btn_click', '开始匹配')
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
// 导师顾问:先播匹配动画,动画完成后再跳转(不在此处直接跳)
@@ -363,7 +364,7 @@ Page({
}, 500)
// 1.5-3秒后导师顾问→跳转其他类型→弹窗
const delay = Math.random() * 1500 + 1500
const delay = Math.random() * 7000 + 3000
setTimeout(() => {
clearInterval(timer)
this.setData({ isMatching: false })
@@ -412,14 +413,15 @@ Page({
// 从数据库获取真实用户匹配
let matchedUser = null
try {
const res = await app.request({ url: '/api/miniprogram/match/users', silent: true,
const res = await app.request({
url: '/api/miniprogram/match/users',
silent: true,
method: 'POST',
data: {
matchType: this.data.selectedType,
userId: app.globalData.userInfo?.id || ''
}
})
if (res.success && res.data) {
matchedUser = res.data
console.log('[Match] 从数据库匹配到用户:', matchedUser.nickname)
@@ -429,8 +431,8 @@ Page({
}
// 延迟显示结果(模拟匹配过程)
const delay = Math.random() * 2000 + 2000
setTimeout(() => {
const delay = Math.random() * 7000 + 3000
const timeoutId = setTimeout(() => {
clearInterval(timer)
// 如果没有匹配到用户,提示用户
@@ -460,7 +462,6 @@ Page({
// 上报匹配行为到存客宝
this.reportMatch(matchedUser)
}, delay)
},
@@ -528,6 +529,7 @@ Page({
// 添加微信好友
handleAddWechat() {
trackClick('match', 'btn_click', '加好友')
if (!this.data.currentMatch) return
wx.setClipboardData({
@@ -578,6 +580,7 @@ Page({
// 提交加入
async handleJoinSubmit() {
trackClick('match', 'btn_click', '加入提交')
const { contactType, phoneNumber, wechatId, joinType, isJoining, canHelp, needHelp } = this.data
if (isJoining) return
@@ -668,6 +671,7 @@ Page({
// 购买匹配次数
async buyMatchCount() {
trackClick('match', 'btn_click', '购买次数')
this.setData({ showUnlockModal: false })
try {
@@ -744,11 +748,6 @@ Page({
wx.switchTab({ url: '/pages/chapters/chapters' })
},
// 打开设置
openSettings() {
wx.navigateTo({ url: '/pages/settings/settings' })
},
// 阻止事件冒泡
preventBubble() {},

View File

@@ -4,9 +4,7 @@
<!-- 自定义导航栏 -->
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-content">
<view class="nav-settings" bindtap="openSettings">
<text class="settings-icon">⚙️</text>
</view>
<view class="nav-left-placeholder"></view>
<text class="nav-title">找伙伴</text>
<view class="nav-right-placeholder"></view>
</view>

View File

@@ -27,15 +27,9 @@
padding: 0 32rpx;
}
.nav-settings {
.nav-left-placeholder {
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
background: #1c1c1e;
display: flex;
align-items: center;
justify-content: center;
}
.nav-title {
@@ -51,10 +45,6 @@
flex-shrink: 0;
}
.settings-icon {
font-size: 36rpx;
}
.nav-placeholder {
width: 100%;
}