Files
soul-yongping/开发文档/8、部署/收益明细优化说明.md

18 KiB
Raw Blame History

分销中心收益明细优化说明

📋 需求

在分销中心的"收益明细"部分,显示更详细的购买信息:

  1. 购买用户的头像
  2. 购买用户的昵称
  3. 购买的书籍和章节
  4. 下单时间

实现方案

修改前

┌─────────────────────────────┐
│ 🎁  整本书购买              │
│     12-25                  │
│                 +¥0.90     │
└─────────────────────────────┘

问题:

  • 不知道是谁购买的
  • 不知道买的哪本书、哪一章
  • 信息太简略

修改后

┌─────────────────────────────┐
│  👤  张三          +¥0.90  │ ← 头像 + 昵称 + 佣金
│     《Soul创业派对》- 1.1   │ ← 书名 - 章节
│     12-25                  │ ← 购买时间
└─────────────────────────────┘

优势:

  • 显示买家头像和昵称
  • 显示具体书籍和章节
  • 信息完整、清晰

🔧 实现细节

1. 后端 API 增强

文件: app/api/referral/data/route.ts

修改前第159-170行:

earningsDetails = await query(`
  SELECT o.id, o.order_sn, o.amount, o.product_type, o.pay_time,
         u.nickname as buyer_nickname,
         rb.commission_amount
  FROM orders o
  JOIN users u ON o.user_id = u.id
  JOIN referral_bindings rb ON o.user_id = rb.referee_id AND rb.referrer_id = ?
  WHERE o.status = 'paid'
  ORDER BY o.pay_time DESC
  LIMIT 30
`, [userId])

修改后:

earningsDetails = await query(`
  SELECT 
    o.id, 
    o.order_sn, 
    o.amount, 
    o.product_type, 
    o.product_id,
    o.description,              -- ✅ 新增:商品描述(书名-章节)
    o.pay_time,
    u.nickname as buyer_nickname,
    u.avatar as buyer_avatar,    -- ✅ 新增:买家头像
    rb.total_commission / rb.purchase_count as commission_per_order
  FROM orders o
  JOIN users u ON o.user_id = u.id
  JOIN referral_bindings rb ON o.user_id = rb.referee_id AND rb.referrer_id = ?
  WHERE o.status = 'paid' AND o.referrer_id = ?
  ORDER BY o.pay_time DESC
  LIMIT 30
`, [userId, userId])

新增字段:

  • description - 商品描述(如"《Soul创业派对》- 1.1 派对房的秘密"
  • buyer_avatar - 买家头像URL
  • product_id - 商品ID如章节ID

2. 后端返回数据格式

文件: app/api/referral/data/route.ts 第261-272行

修改前:

earningsDetails: earningsDetails.map((e: any) => ({
  id: e.id,
  productType: e.product_type,
  commission: parseFloat(e.commission_amount),
  buyerNickname: e.buyer_nickname,
  payTime: e.pay_time
}))

修改后:

earningsDetails: earningsDetails.map((e: any) => ({
  id: e.id,
  orderSn: e.order_sn,
  amount: parseFloat(e.amount),
  commission: parseFloat(e.commission_per_order) || parseFloat(e.amount) * distributorShare,
  productType: e.product_type,
  productId: e.product_id,
  description: e.description,           // ✅ 新增
  buyerNickname: e.buyer_nickname || '用户' + e.id?.toString().slice(-4),
  buyerAvatar: e.buyer_avatar,          // ✅ 新增
  payTime: e.pay_time
}))

3. 小程序解析商品描述

文件: miniprogram/pages/referral/referral.js

新增函数:

// 解析商品描述,获取书名和章节
parseProductDescription(description, productType) {
  if (!description) {
    return {
      bookTitle: '未知商品',
      chapterTitle: ''
    }
  }
  
  // 匹配格式:《书名》- 章节名
  const match = description.match(/《(.+?)》(?:\s*-\s*(.+))?/)
  
  if (match) {
    return {
      bookTitle: match[1] || '未知书籍',
      chapterTitle: match[2] || (productType === 'fullbook' ? '全书购买' : '')
    }
  }
  
  // 如果匹配失败,直接返回原始描述
  return {
    bookTitle: description.split('-')[0] || description,
    chapterTitle: description.split('-')[1] || ''
  }
}

解析示例:

原始 description bookTitle chapterTitle
《Soul创业派对》- 1.1 派对房的秘密 Soul创业派对 1.1 派对房的秘密
《Soul创业派对》- 全书购买 Soul创业派对 全书购买
《Soul创业派对》 Soul创业派对 (空)

4. 小程序数据格式化

文件: miniprogram/pages/referral/referral.js 第179-193行

修改前:

earningsDetails: (realData?.earningsDetails || []).map(item => ({
  id: item.id,
  productType: item.productType,
  commission: (item.commission || 0).toFixed(2),
  payTime: item.payTime ? this.formatDate(item.payTime) : '--',
  buyerNickname: item.buyerNickname
}))

修改后:

earningsDetails: (realData?.earningsDetails || []).map(item => {
  // 解析商品描述,获取书名和章节
  const productInfo = this.parseProductDescription(item.description, item.productType)
  
  return {
    id: item.id,
    productType: item.productType,
    bookTitle: productInfo.bookTitle,        // ✅ 新增:书名
    chapterTitle: productInfo.chapterTitle,  // ✅ 新增:章节
    commission: (item.commission || 0).toFixed(2),
    payTime: item.payTime ? this.formatDate(item.payTime) : '--',
    buyerNickname: item.buyerNickname || '用户',
    buyerAvatar: item.buyerAvatar            // ✅ 新增:头像
  }
})

5. 小程序 UI 重构

文件: miniprogram/pages/referral/referral.wxml 第213-231行

修改前:

<view class="detail-item" wx:for="{{earningsDetails}}" wx:key="id">
  <view class="detail-left">
    <view class="detail-icon">
      <image class="icon-gift" src="/assets/icons/gift.svg" mode="aspectFit"></image>
    </view>
    <view class="detail-info">
      <text class="detail-type">{{item.productType === 'fullbook' ? '整本书购买' : '单节购买'}}</text>
      <text class="detail-time">{{item.payTime}}</text>
    </view>
  </view>
  <text class="detail-amount">+¥{{item.commission}}</text>
</view>

修改后:

<view class="detail-item" wx:for="{{earningsDetails}}" wx:key="id">
  <!-- 买家头像 -->
  <view class="detail-avatar-wrap">
    <image 
      class="detail-avatar" 
      wx:if="{{item.buyerAvatar}}" 
      src="{{item.buyerAvatar}}" 
      mode="aspectFill"
    />
    <view class="detail-avatar-text" wx:else>
      {{item.buyerNickname.charAt(0)}}
    </view>
  </view>
  
  <!-- 详细信息 -->
  <view class="detail-content">
    <view class="detail-top">
      <text class="detail-buyer">{{item.buyerNickname}}</text>
      <text class="detail-amount">+¥{{item.commission}}</text>
    </view>
    <view class="detail-product">
      <text class="detail-book">{{item.bookTitle}}</text>
      <text class="detail-chapter" wx:if="{{item.chapterTitle}}"> - {{item.chapterTitle}}</text>
    </view>
    <text class="detail-time">{{item.payTime}}</text>
  </view>
</view>

6. 样式优化

文件: miniprogram/pages/referral/referral.wxss

新增样式:

/* 收益明细增强样式 */
.detail-item {
  display: flex;
  align-items: center;
  gap: 24rpx;
  padding: 24rpx;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 16rpx;
  margin-bottom: 16rpx;
}

.detail-avatar-wrap {
  flex-shrink: 0;
}

.detail-avatar {
  width: 88rpx;
  height: 88rpx;
  border-radius: 50%;
  border: 2rpx solid rgba(56, 189, 172, 0.2);
}

.detail-avatar-text {
  width: 88rpx;
  height: 88rpx;
  border-radius: 50%;
  background: linear-gradient(135deg, #38bdac 0%, #2da396 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 36rpx;
  font-weight: 700;
  color: #ffffff;
}

.detail-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.detail-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.detail-buyer {
  font-size: 28rpx;
  font-weight: 500;
  color: #ffffff;
}

.detail-amount {
  font-size: 32rpx;
  font-weight: 700;
  color: #38bdac;
}

.detail-product {
  font-size: 24rpx;
  color: rgba(255, 255, 255, 0.6);
}

.detail-book {
  color: rgba(255, 255, 255, 0.7);
  font-weight: 500;
}

.detail-chapter {
  color: rgba(255, 255, 255, 0.5);
}

.detail-time {
  font-size: 22rpx;
  color: rgba(255, 255, 255, 0.4);
}

🎨 UI 效果对比

修改前

┌──────────────────────────────┐
│ 🎁 整本书购买    +¥0.90     │
│    12-25                     │
└──────────────────────────────┘

信息量: 只有类型、时间、金额


修改后

┌──────────────────────────────┐
│  👤                          │
│  张三            +¥0.90      │ ← 头像 + 昵称 + 佣金
│  《Soul创业派对》- 1.1 派对房的秘密
│  12-25                       │ ← 时间
└──────────────────────────────┘

信息量: 头像、昵称、书名、章节、金额、时间


📊 数据流转

订单创建
    ↓
orders 表记录:
  - user_id (买家ID)
  - description (商品描述)
  - amount (金额)
  - pay_time (支付时间)
    ↓
后端 API 查询:
  - JOIN users 获取买家信息(昵称、头像)
  - 返回 description、buyerAvatar 等
    ↓
小程序解析:
  - parseProductDescription() 解析书名和章节
  - formatDate() 格式化时间
    ↓
UI 显示:
  - 头像(有则显示,无则显示首字母)
  - 昵称、书名、章节、时间、佣金

🎯 显示逻辑

1. 头像显示

<!-- 如果有头像 -->
<image class="detail-avatar" src="{{item.buyerAvatar}}" />

<!-- 如果没有头像 -->
<view class="detail-avatar-text">
  {{item.buyerNickname.charAt(0)}}  <!-- 显示昵称首字母 -->
</view>

效果:

  • 有头像:显示圆形头像(带品牌色边框)
  • 无头像:显示品牌渐变背景 + 昵称首字母

2. 商品信息解析

输入: 《Soul创业派对》- 1.1 派对房的秘密

解析函数:

parseProductDescription(description, productType) {
  const match = description.match(/《(.+?)》(?:\s*-\s*(.+))?/)
  if (match) {
    return {
      bookTitle: match[1],      // "Soul创业派对"
      chapterTitle: match[2]    // "1.1 派对房的秘密"
    }
  }
}

显示:

<view class="detail-product">
  <text class="detail-book">{{item.bookTitle}}</text>
  <text class="detail-chapter"> - {{item.chapterTitle}}</text>
</view>

效果: Soul创业派对 - 1.1 派对房的秘密


3. 全书购买特殊处理

输入: 《Soul创业派对》- 全书购买

解析:

  • bookTitle: "Soul创业派对"
  • chapterTitle: "全书购买"

显示: Soul创业派对 - 全书购买


4. 时间格式化

输入: 2026-02-04 15:30:00

格式化:

formatDate(dateStr) {
  const d = new Date(dateStr)
  const month = (d.getMonth() + 1).toString().padStart(2, '0')
  const day = d.getDate().toString().padStart(2, '0')
  return `${month}-${day}`
}

输出: 02-04


🎨 视觉设计

布局结构

┌─────────────────────────────────────┐
│  ┌──────┐  ┌──────────────────────┐ │
│  │      │  │ 昵称         +¥金额  │ │
│  │ 头像 │  │ 书名 - 章节          │ │
│  │      │  │ 时间                 │ │
│  └──────┘  └──────────────────────┘ │
└─────────────────────────────────────┘

配色方案

元素 颜色 说明
头像边框 rgba(56, 189, 172, 0.2) 品牌色半透明
头像背景(无图) #38bdac → #2da396 品牌渐变
昵称 #ffffff 白色
佣金 #38bdac 品牌色(醒目)
书名 rgba(255, 255, 255, 0.7) 白色70%
章节 rgba(255, 255, 255, 0.5) 白色50%
时间 rgba(255, 255, 255, 0.4) 白色40%

📦 修改文件清单

文件 修改内容 状态
app/api/referral/data/route.ts SQL查询增加 description、buyer_avatar
app/api/referral/data/route.ts 返回数据添加新字段
miniprogram/pages/referral/referral.js 添加 parseProductDescription 函数
miniprogram/pages/referral/referral.js earningsDetails 数据处理逻辑
miniprogram/pages/referral/referral.wxml 重构收益明细 UI
miniprogram/pages/referral/referral.wxss 添加新样式

🧪 测试用例

测试1: 完整信息显示

数据:

{
  "buyerNickname": "张三",
  "buyerAvatar": "https://...",
  "description": "《Soul创业派对》- 1.1 派对房的秘密",
  "commission": 0.90,
  "payTime": "2026-02-04 15:30:00"
}

预期显示:

[头像] 张三          +¥0.90
      Soul创业派对 - 1.1 派对房的秘密
      02-04

测试2: 无头像用户

数据:

{
  "buyerNickname": "李四",
  "buyerAvatar": null,
  "description": "《Soul创业派对》- 全书购买",
  "commission": 8.91,
  "payTime": "2026-02-03 10:20:00"
}

预期显示:

[李] 李四          +¥8.91  ← 显示"李"(品牌色圆圈)
     Soul创业派对 - 全书购买
     02-03

测试3: 全书购买

数据:

{
  "buyerNickname": "王五",
  "description": "《Soul创业派对》- 全书购买",
  "productType": "fullbook"
}

预期显示:

[王] 王五          +¥8.91
     Soul创业派对 - 全书购买
     02-03

🔍 技术细节

1. 正则表达式解析

const match = description.match(/《(.+?)》(?:\s*-\s*(.+))?/)

匹配规则:

  • 《(.+?)》 - 匹配书名(在《》内)
  • (?:\s*-\s*(.+))? - 可选匹配章节(- 后的内容)

示例:

  • 《Soul创业派对》- 1.1 派对房的秘密["Soul创业派对", "1.1 派对房的秘密"]
  • 《Soul创业派对》["Soul创业派对", undefined]

2. 头像兜底方案

<!-- 优先显示真实头像 -->
<image wx:if="{{item.buyerAvatar}}" src="{{item.buyerAvatar}}" />

<!-- 无头像时显示首字母 -->
<view wx:else>{{item.buyerNickname.charAt(0)}}</view>

charAt(0): 获取昵称第一个字符

  • "张三" → "张"
  • "Soul用户" → "S"
  • "用户1234" → "用"

3. 文字溢出处理

.detail-product {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

作用: 如果章节名太长,自动省略显示 ...

示例:

  • 正常:Soul创业派对 - 1.1 派对房的秘密
  • 超长:Soul创业派对 - 1.1 派对房的秘密以及后续的...

📱 响应式适配

小屏手机

┌────────────────────────┐
│ 👤 张三      +¥0.90   │ ← 紧凑布局
│   Soul创业派对 - 1.1   │
│   02-04               │
└────────────────────────┘

大屏手机

┌──────────────────────────────┐
│  👤  张三            +¥0.90  │ ← 舒适间距
│     Soul创业派对 - 1.1 派对房的秘密
│     02-04                    │
└──────────────────────────────┘

自适应: 使用 rpx 单位,自动适配不同屏幕


完成效果

收益明细卡片

┌─────────────────────────────────┐
│  收益明细                       │
├─────────────────────────────────┤
│  👤  张三            +¥0.90    │
│     Soul创业派对 - 1.1 派对房的秘密
│     02-04                      │
├─────────────────────────────────┤
│  👤  李四            +¥8.91    │
│     Soul创业派对 - 全书购买     │
│     02-03                      │
├─────────────────────────────────┤
│  [王] 王五            +¥0.90    │ ← 无头像显示首字母
│     Soul创业派对 - 2.3 资源整合 │
│     02-02                      │
└─────────────────────────────────┘

🚀 部署说明

无需数据库修改

所有需要的字段(descriptionavatar)都已存在,只需部署代码即可。


验证步骤

  1. 部署新代码
  2. 打开分销中心
  3. 查看"收益明细"
  4. 验证显示:
    • 买家头像或首字母
    • 买家昵称
    • 书名和章节
    • 购买时间
    • 佣金金额

📊 信息完整度提升

维度 修改前 修改后
买家信息 头像 + 昵称
商品信息 只有类型 书名 + 章节
金额信息 佣金 佣金
时间信息 日期 日期

信息完整度: 30% → 100%


现在收益明细显示完整,推广者可以清楚看到每笔收益的详细来源! 🎉