feat: 同步今日小程序与后台迭代版本

集中提交今日 API、管理端、小程序与部署文档调整,确保 Gitea 主分支与本地最新开发版本一致。

Made-with: Cursor
This commit is contained in:
卡若
2026-04-20 11:07:55 +08:00
parent 7108f28280
commit ce55c48c64
180 changed files with 11659 additions and 6078 deletions

View File

@@ -22,7 +22,7 @@ Page({
testCommissionRate: '',
testCommissionAmount: '',
testNoPayment: false,
withdrawMinYuan: '1.00',
withdrawMinYuan: '0.01',
withdrawMaxYuan: '',
withdrawFeePct: 0,
requireWithdrawAudit: true,
@@ -79,7 +79,7 @@ Page({
testCommissionRate: d.testCommissionRate,
testCommissionAmount: d.testCommissionAmount,
testNoPayment: d.testNoPayment,
withdrawMinYuan: d.withdrawMinYuan != null ? d.withdrawMinYuan : '1.00',
withdrawMinYuan: d.withdrawMinYuan != null ? d.withdrawMinYuan : '0.01',
withdrawMaxYuan: d.withdrawMaxYuan != null && d.withdrawMaxYuan !== '' ? d.withdrawMaxYuan : '',
withdrawFeePct: d.withdrawFeePct != null ? d.withdrawFeePct : 0,
requireWithdrawAudit: d.requireWithdrawAudit !== false,
@@ -150,8 +150,8 @@ Page({
/** 申请提现:打开自定义金额弹框 */
handleWithdraw() {
const balance = parseFloat(this.data.balance)
if (balance < 1) {
wx.showToast({ title: '余额不足1元暂无提现', icon: 'none' })
if (!balance || balance <= 0) {
wx.showToast({ title: '暂无提现余额', icon: 'none' })
return
}
const pct = this.data.withdrawFeePct || 0
@@ -198,28 +198,29 @@ Page({
confirmWithdraw() {
const balance = parseFloat(this.data.balance)
const val = parseFloat(this.data.withdrawAmountInput)
const minYuan = parseFloat(this.data.withdrawMinYuan) || 1
const cfgMin = parseFloat(this.data.withdrawMinYuan)
const minYuan = !isNaN(cfgMin) && cfgMin > 0 ? cfgMin : 0.01
const pct = this.data.withdrawFeePct || 0
if (isNaN(val)) {
this.setData({ withdrawError: '请输入正确的金额' })
return
}
if (val < 1) {
this.setData({ withdrawError: '单次提现金额至少 1 元' })
if (val + 1e-9 < minYuan) {
this.setData({ withdrawError: `单次提现金额至少 ¥${minYuan.toFixed(2)}` })
return
}
if (val > balance) {
if (val > balance + 1e-9) {
this.setData({ withdrawError: '不可超过当前可提现金额' })
return
}
const actualYuan = val - val * pct / 100
if (actualYuan < minYuan) {
this.setData({ withdrawError: `实际到账金额不得低于最低提现金额 ¥${minYuan.toFixed(2)}` })
if (actualYuan + 1e-9 < minYuan) {
this.setData({ withdrawError: `实际到账金额不得低于 ¥${minYuan.toFixed(2)}` })
return
}
const amountFen = Math.floor(val * 100)
const amountFen = Math.max(1, Math.round(val * 100))
this.setData({ withdrawError: '' })
try { require('../../utils/analytics').track('tap_promo_withdraw', { amountFen }) } catch (e) {}

View File

@@ -1,219 +1,219 @@
<!--pages/promo/index.wxml-->
<view class="container">
<!-- 顶部统计卡片 -->
<view class="hero-card">
<view class="hero-header-row">
<view class="hero-left">
<view class="wallet-icon">
<text class="emoji">🧧</text>
</view>
<view class="title-text">
<text class="label">可提现金额</text>
<view class="badge">
<view class="dot"></view>
<text class="badge-text">{{commissionRate}}% 高额返利</text>
</view>
</view>
</view>
<view class="hero-right">
<text class="amount">¥{{balance}}</text>
<text class="amount-sub">累计: ¥{{totalEarned}} | 待审核: ¥{{pendingAmount}}</text>
</view>
</view>
<button class="withdraw-btn {{balance > 0 ? '' : 'disabled'}}" bindtap="handleWithdraw">
<text>{{balance > 0 ? '立即提现' : '暂无提现'}}</text>
</button>
<view class="record-link" bindtap="goToWithdrawHistory">
<text>查看提现记录</text>
<text class="arrow"></text>
</view>
</view>
<!-- 自定义提现金额弹框 -->
<view class="withdraw-mask" wx:if="{{showWithdrawDialog}}">
<view class="withdraw-dialog">
<view class="dialog-title">申请提现</view>
<view class="dialog-sub">可提现 ¥{{balance}},请输入本次提现金额</view>
<view class="amount-input-row">
<text class="currency">¥</text>
<input
class="amount-input"
type="digit"
focus="true"
value="{{withdrawAmountInput}}"
placeholder="至少 1.00 元"
bindinput="onWithdrawInput"
/>
</view>
<view class="amount-hint">
<text>本次最高可提 ¥{{balance}}</text>
</view>
<view class="fee-actual-row" wx:if="{{withdrawFeePct > 0}}">
<text>手续费 ¥{{withdrawFeeYuan}}</text>
<text class="actual">实际到账 ¥{{withdrawActualYuan}}</text>
</view>
<view class="error-text" wx:if="{{withdrawError}}">
<text>{{withdrawError}}</text>
</view>
<view class="dialog-actions">
<view class="btn cancel" bindtap="closeWithdrawDialog">取消</view>
<view class="btn confirm" bindtap="confirmWithdraw">确定</view>
</view>
</view>
</view>
<!-- 四格统计 -->
<view class="stats-grid">
<view class="stat-item">
<text class="stat-val">{{bindingCount}}</text>
<text class="stat-label">绑定中</text>
</view>
<view class="stat-item">
<text class="stat-val">{{paidCount}}</text>
<text class="stat-label">已付款</text>
</view>
<view class="stat-item">
<text class="stat-val highlight">{{expiringCount}}</text>
<text class="stat-label">即将过期</text>
</view>
<view class="stat-item">
<text class="stat-val">{{totalInvite}}</text>
<text class="stat-label">总邀请</text>
</view>
</view>
<!-- 收益规则 -->
<view class="section rule-section">
<view class="section-header">
<view class="header-icon red">
<text class="emoji-sm">🛡️</text>
</view>
<text class="section-title">推广收益规则</text>
</view>
<view class="rule-list">
<view class="rule-item">
<text class="rule-bullet">✨</text>
<text class="rule-text">用户绑定有效期为 <text class="highlight">{{bindingDays}}天</text>,期满自动解除</text>
</view>
<view class="rule-item">
<text class="rule-bullet">💰</text>
<text class="rule-text">单笔提现:最低 <text class="highlight">¥{{withdrawMinYuan}}</text></text>
<text class="rule-text" wx:if="{{withdrawMaxYuan}}">最高 <text class="highlight">¥{{withdrawMaxYuan}}</text></text>
<text class="rule-text" wx:else>不设上限</text>
</view>
<view class="rule-item" wx:if="{{withdrawFeePct > 0}}">
<text class="rule-bullet">📋</text>
<text class="rule-text">提现手续费:<text class="highlight">{{withdrawFeePct}}%</text></text>
</view>
</view>
</view>
<!-- 绑定用户列表 -->
<view class="section user-section">
<view class="section-header border-b">
<view class="header-left">
<text class="emoji-sm">👥</text>
<text class="section-title">绑定用户</text>
<text class="count-label">({{totalInvite}})</text>
</view>
</view>
<!-- Tab 切换 -->
<view class="tab-bar">
<view class="tab-item {{activeTab === 0 ? 'active' : ''}}" bindtap="switchTab" data-index="0">
绑定中 ({{bindingCount}})
</view>
<view class="tab-item {{activeTab === 1 ? 'active' : ''}}" bindtap="switchTab" data-index="1">
已付款 ({{paidCount}})
</view>
<view class="tab-item {{activeTab === 2 ? 'active' : ''}}" bindtap="switchTab" data-index="2">
已过期 ({{expiringCount}})
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{userList.length === 0}}">
<view class="empty-icon">
<text class="emoji-lg">🔍</text>
</view>
<text class="empty-text">目前还没有绑定的用户哦</text>
<text class="empty-sub">快去分享链接邀请好友吧</text>
</view>
<!-- 用户列表 -->
<view class="user-list" wx:else>
<view class="user-item" wx:for="{{userList}}" wx:key="id">
<!-- 头像 -->
<image wx:if="{{item.avatar}}" class="user-avatar" src="{{item.avatar}}" mode="aspectFill"/>
<view wx:else class="user-avatar user-avatar-placeholder">
<text class="user-avatar-letter">{{item.nickname ? item.nickname[0] : '?'}}</text>
</view>
<!-- 昵称 + 绑定时间 -->
<view class="user-info">
<text class="user-name">{{item.nickname || '微信用户'}}</text>
<text class="user-time">绑定于 {{item.createdAtStr}}</text>
</view>
<!-- 状态 / 剩余天数 -->
<view class="user-badge {{item.status === 'active' ? 'badge-active' : (item.status === 'expired' ? 'badge-expired' : 'badge-paid')}}">
<text wx:if="{{item.status === 'active'}}">{{item.remainDays}}天到期</text>
<text wx:elif="{{item.status === 'expired'}}">已过期</text>
<text wx:else>已付款</text>
</view>
</view>
<!-- 加载更多 / 没有更多 -->
<view class="list-footer" wx:if="{{listLoading}}">
<text class="list-footer-text">加载中...</text>
</view>
<view class="list-footer" wx:elif="{{listFinished && userList.length > 0}}">
<text class="list-footer-text">— 已加载全部 —</text>
</view>
</view>
</view>
<!-- 操作菜单 -->
<view class="menu-card">
<view class="menu-item" bindtap="generatePoster">
<view class="menu-icon-wrap rose">
<text class="emoji-sm">🎨</text>
</view>
<view class="menu-info">
<text class="menu-name">生成推广海报</text>
<text class="menu-desc">一键生成您的专属精美海报</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" bindtap="shareToTimeline">
<view class="menu-icon-wrap emerald">
<text class="emoji-sm">💬</text>
</view>
<view class="menu-info">
<text class="menu-name">分享到朋友圈</text>
<text class="menu-desc">通过右上角菜单分享到朋友圈</text>
</view>
<text class="menu-arrow"></text>
</view>
<button class="menu-item share-btn" open-type="share">
<view class="menu-icon-wrap violet">
<text class="emoji-sm">📤</text>
</view>
<view class="menu-info">
<text class="menu-name">分享给好友</text>
<text class="menu-desc">通过系统面板发送给微信好友</text>
</view>
<text class="menu-arrow"></text>
</button>
</view>
<!-- 底部提示 -->
<view class="footer-tip">
<text>分享专属链接,好友通过链接点击后自动绑定</text>
<text>购买任意测评即可获得 <text class="highlight">90%</text> 的现金返利</text>
</view>
<view class="safe-bottom"></view>
</view>
<!--pages/promo/index.wxml-->
<view class="container">
<!-- 顶部统计卡片 -->
<view class="hero-card">
<view class="hero-header-row">
<view class="hero-left">
<view class="wallet-icon">
<text class="emoji">🧧</text>
</view>
<view class="title-text">
<text class="label">可提现金额</text>
<view class="badge">
<view class="dot"></view>
<text class="badge-text">{{commissionRate}}% 高额返利</text>
</view>
</view>
</view>
<view class="hero-right">
<text class="amount">¥{{balance}}</text>
<text class="amount-sub">累计: ¥{{totalEarned}} | 待审核: ¥{{pendingAmount}}</text>
</view>
</view>
<button class="withdraw-btn {{balance > 0 ? '' : 'disabled'}}" bindtap="handleWithdraw">
<text>{{balance > 0 ? '立即提现' : '暂无提现'}}</text>
</button>
<view class="record-link" bindtap="goToWithdrawHistory">
<text>查看提现记录</text>
<text class="arrow"></text>
</view>
</view>
<!-- 自定义提现金额弹框 -->
<view class="withdraw-mask" wx:if="{{showWithdrawDialog}}">
<view class="withdraw-dialog">
<view class="dialog-title">申请提现</view>
<view class="dialog-sub">可提现 ¥{{balance}},请输入本次提现金额</view>
<view class="amount-input-row">
<text class="currency">¥</text>
<input
class="amount-input"
type="digit"
focus="true"
value="{{withdrawAmountInput}}"
placeholder="输入提现金额"
bindinput="onWithdrawInput"
/>
</view>
<view class="amount-hint">
<text>本次最高可提 ¥{{balance}}</text>
</view>
<view class="fee-actual-row" wx:if="{{withdrawFeePct > 0}}">
<text>手续费 ¥{{withdrawFeeYuan}}</text>
<text class="actual">实际到账 ¥{{withdrawActualYuan}}</text>
</view>
<view class="error-text" wx:if="{{withdrawError}}">
<text>{{withdrawError}}</text>
</view>
<view class="dialog-actions">
<view class="btn cancel" bindtap="closeWithdrawDialog">取消</view>
<view class="btn confirm" bindtap="confirmWithdraw">确定</view>
</view>
</view>
</view>
<!-- 四格统计 -->
<view class="stats-grid">
<view class="stat-item">
<text class="stat-val">{{bindingCount}}</text>
<text class="stat-label">绑定中</text>
</view>
<view class="stat-item">
<text class="stat-val">{{paidCount}}</text>
<text class="stat-label">已付款</text>
</view>
<view class="stat-item">
<text class="stat-val highlight">{{expiringCount}}</text>
<text class="stat-label">即将过期</text>
</view>
<view class="stat-item">
<text class="stat-val">{{totalInvite}}</text>
<text class="stat-label">总邀请</text>
</view>
</view>
<!-- 收益规则 -->
<view class="section rule-section">
<view class="section-header">
<view class="header-icon red">
<text class="emoji-sm">🛡️</text>
</view>
<text class="section-title">推广收益规则</text>
</view>
<view class="rule-list">
<view class="rule-item">
<text class="rule-bullet">✨</text>
<text class="rule-text">用户绑定有效期为 <text class="highlight">{{bindingDays}}天</text>,期满自动解除</text>
</view>
<view class="rule-item">
<text class="rule-bullet">💰</text>
<text class="rule-text">单笔提现:最低 <text class="highlight">¥{{withdrawMinYuan}}</text></text>
<text class="rule-text" wx:if="{{withdrawMaxYuan}}">最高 <text class="highlight">¥{{withdrawMaxYuan}}</text></text>
<text class="rule-text" wx:else>不设上限</text>
</view>
<view class="rule-item" wx:if="{{withdrawFeePct > 0}}">
<text class="rule-bullet">📋</text>
<text class="rule-text">提现手续费:<text class="highlight">{{withdrawFeePct}}%</text></text>
</view>
</view>
</view>
<!-- 绑定用户列表 -->
<view class="section user-section">
<view class="section-header border-b">
<view class="header-left">
<text class="emoji-sm">👥</text>
<text class="section-title">绑定用户</text>
<text class="count-label">({{totalInvite}})</text>
</view>
</view>
<!-- Tab 切换 -->
<view class="tab-bar">
<view class="tab-item {{activeTab === 0 ? 'active' : ''}}" bindtap="switchTab" data-index="0">
绑定中 ({{bindingCount}})
</view>
<view class="tab-item {{activeTab === 1 ? 'active' : ''}}" bindtap="switchTab" data-index="1">
已付款 ({{paidCount}})
</view>
<view class="tab-item {{activeTab === 2 ? 'active' : ''}}" bindtap="switchTab" data-index="2">
已过期 ({{expiringCount}})
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{userList.length === 0}}">
<view class="empty-icon">
<text class="emoji-lg">🔍</text>
</view>
<text class="empty-text">目前还没有绑定的用户哦</text>
<text class="empty-sub">快去分享链接邀请好友吧</text>
</view>
<!-- 用户列表 -->
<view class="user-list" wx:else>
<view class="user-item" wx:for="{{userList}}" wx:key="id">
<!-- 头像 -->
<image wx:if="{{item.avatar}}" class="user-avatar" src="{{item.avatar}}" mode="aspectFill"/>
<view wx:else class="user-avatar user-avatar-placeholder">
<text class="user-avatar-letter">{{item.nickname ? item.nickname[0] : '?'}}</text>
</view>
<!-- 昵称 + 绑定时间 -->
<view class="user-info">
<text class="user-name">{{item.nickname || '微信用户'}}</text>
<text class="user-time">绑定于 {{item.createdAtStr}}</text>
</view>
<!-- 状态 / 剩余天数 -->
<view class="user-badge {{item.status === 'active' ? 'badge-active' : (item.status === 'expired' ? 'badge-expired' : 'badge-paid')}}">
<text wx:if="{{item.status === 'active'}}">{{item.remainDays}}天到期</text>
<text wx:elif="{{item.status === 'expired'}}">已过期</text>
<text wx:else>已付款</text>
</view>
</view>
<!-- 加载更多 / 没有更多 -->
<view class="list-footer" wx:if="{{listLoading}}">
<text class="list-footer-text">加载中...</text>
</view>
<view class="list-footer" wx:elif="{{listFinished && userList.length > 0}}">
<text class="list-footer-text">— 已加载全部 —</text>
</view>
</view>
</view>
<!-- 操作菜单 -->
<view class="menu-card">
<view class="menu-item" bindtap="generatePoster">
<view class="menu-icon-wrap rose">
<text class="emoji-sm">🎨</text>
</view>
<view class="menu-info">
<text class="menu-name">生成推广海报</text>
<text class="menu-desc">一键生成您的专属精美海报</text>
</view>
<text class="menu-arrow"></text>
</view>
<view class="menu-item" bindtap="shareToTimeline">
<view class="menu-icon-wrap emerald">
<text class="emoji-sm">💬</text>
</view>
<view class="menu-info">
<text class="menu-name">分享到朋友圈</text>
<text class="menu-desc">通过右上角菜单分享到朋友圈</text>
</view>
<text class="menu-arrow"></text>
</view>
<button class="menu-item share-btn" open-type="share">
<view class="menu-icon-wrap violet">
<text class="emoji-sm">📤</text>
</view>
<view class="menu-info">
<text class="menu-name">分享给好友</text>
<text class="menu-desc">通过系统面板发送给微信好友</text>
</view>
<text class="menu-arrow"></text>
</button>
</view>
<!-- 底部提示 -->
<view class="footer-tip">
<text>分享专属链接,好友通过链接点击后自动绑定</text>
<text>购买任意测评即可获得 <text class="highlight">90%</text> 的现金返利</text>
</view>
<view class="safe-bottom"></view>
</view>

File diff suppressed because it is too large Load Diff