bindbox-game/.claude/plan/task-center-claim-bug.md
2026-03-05 12:50:06 +08:00

5.7 KiB
Raw Blame History

任务中心领取 Bug 修复计划

问题描述

小程序bindbox-mini任务中心活动前端领取不了但是可以看到。

根因分析

核心问题:前后端进度数据源不一致

后端 ClaimTierservice.go:738使用 TierProgressMap(基于窗口化、受任务时间约束的进度)来校验是否达标:

if tp, ok := progress.TierProgressMap[tierID]; ok {
    currentOrderCount = tp.OrderCount  // 窗口化进度,受任务 StartTime 约束
}

前端 isTierClaimableindex.vue:387-437使用的是 subProgress(活动级别汇总)或全局进度(orderCount / orderAmount完全没有使用 tier_progress_map

触发条件

最近提交 e0db875 修改了 computeTimeWindow

  • 修改前lifetime / since_registration / 空窗口 → return nil, nil(不限时间)
  • 修改后lifetime / 默认窗口 → return taskStart, taskEnd(受任务时间约束)

这导致 TierProgressMap 中的进度值被任务时间限制,但 API 返回的 order_count / sub_progress 全局进度仍然不受时间限制service.go:618-622 用 nil, nil 查询)。

不一致的结果

数据源 时间约束 进度值 使用方
TierProgressMap 受任务 StartTime/EndTime 约束 较小 后端 ClaimTier
SubProgress / 全局进度 无时间约束 较大 前端 isTierClaimable
API 返回的 order_count 无时间约束(或活动级别) 较大 前端 isTierClaimable

场景举例

  • 用户在任务创建前有 5 笔历史订单,任务创建后有 2 笔新订单
  • 任务档位要求 order_count >= 3
  • 前端看到全局 orderCount = 7(不限时间) → 显示"领取"按钮
  • 后端 TierProgressMap.OrderCount = 2(只统计任务开始后) → 返回"任务条件未达成"

或者反过来

  • 前端也使用 subProgress 做判断,但 subProgress 的统计可能不包含某些场景的数据
  • 导致前端 isTierClaimable 返回 false,按钮不出现
  • 用户看到任务但无法领取

任务类型

  • 后端 (→ 后端逻辑修复)
  • 前端 (→ 前端判断修复)

技术方案

方案 A推荐后端 API 返回 tier_progress_map,前端使用

让前后端使用同一份进度数据源(TierProgressMap),确保判断一致。

实施步骤

Step 1后端 - API Response 增加 tier_progress_map 字段

文件: internal/api/task_center/tasks_app.go

  1. taskProgressResponse 结构体中添加 TierProgressMap 字段:
type tierProgressItem struct {
    TierID      int64 `json:"tier_id"`
    OrderCount  int64 `json:"order_count"`
    OrderAmount int64 `json:"order_amount"`
    InviteCount int64 `json:"invite_count"`
    FirstOrder  bool  `json:"first_order"`
}

type taskProgressResponse struct {
    // ... existing fields ...
    TierProgress []tierProgressItem `json:"tier_progress"` // 新增
}
  1. GetTaskProgressForApp handler 中填充该字段。

Step 2前端 - isTierClaimable 优先使用 tier_progress

文件: bindbox-mini/pages-user/tasks/index.vue

  1. fetchData 中解析并存储 tier_progresstaskProgress[taskId]
  2. 修改 isTierClaimable 函数,优先从 tierProgress 中查找对应 tier 的进度
  3. 修改 getTierProgressTextgetTierProgressPercent,同步使用新数据源
function isTierClaimable(task, tier) {
  const progress = taskProgress[task.id] || {}

  // 优先使用 tier 级别窗口化进度(与后端 ClaimTier 保持一致)
  if (progress.tierProgress) {
    const tp = progress.tierProgress.find(t => t.tier_id === tier.id)
    if (tp) {
      const metric = tier.metric || ''
      const threshold = tier.threshold || 0
      const operator = tier.operator || '>='

      let current = 0
      if (metric === 'first_order') return tp.first_order || false
      else if (metric === 'order_count') current = tp.order_count || 0
      else if (metric === 'order_amount') current = tp.order_amount || 0
      else if (metric === 'invite_count') current = tp.invite_count || 0

      if (operator === '>=') return current >= threshold
      if (operator === '==') return current === threshold
      if (operator === '>') return current > threshold
      return current >= threshold
    }
  }

  // fallback: 原有逻辑
  // ...
}

Step 3同步修改进度显示

修改 getTierProgressTextgetTierProgressPercent 也优先使用 tierProgress 数据,确保用户看到的进度和可领取状态一致。

关键文件

文件 操作 说明
internal/api/task_center/tasks_app.go:106-170 修改 添加 tier_progress 到响应体
bindbox-mini/pages-user/tasks/index.vue:387-437 修改 isTierClaimable 使用 tier_progress
bindbox-mini/pages-user/tasks/index.vue:440-478 修改 getTierProgressText 使用 tier_progress
bindbox-mini/pages-user/tasks/index.vue:590-630 修改 getTierProgressPercent 使用 tier_progress
bindbox-mini/pages-user/tasks/index.vue:551-576 修改 fetchData 解析 tier_progress

风险与缓解

风险 缓解措施
前端旧版本未使用 tier_progress 字段 保持原有 order_countsub_progress 字段不变,tier_progress 为新增字段,向后兼容
tier_progress_map 为空(数据库无 tiers 配置) 前端 fallback 到原有 subProgress / 全局进度逻辑
已部署但未刷新前端的用户 tier_progress 是附加字段,不影响旧逻辑

SESSION_ID供 /ccg:execute 使用)

  • CODEX_SESSION: N/A未使用外部模型
  • GEMINI_SESSION: N/A未使用外部模型