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

143 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 任务中心领取 Bug 修复计划
## 问题描述
小程序bindbox-mini任务中心活动前端领取不了但是可以看到。
## 根因分析
### 核心问题:前后端进度数据源不一致
**后端 `ClaimTier`**service.go:738使用 `TierProgressMap`(基于窗口化、受任务时间约束的进度)来校验是否达标:
```go
if tp, ok := progress.TierProgressMap[tierID]; ok {
currentOrderCount = tp.OrderCount // 窗口化进度,受任务 StartTime 约束
}
```
**前端 `isTierClaimable`**index.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`,按钮不出现
- 用户看到任务但无法领取
## 任务类型
- [x] 后端 (→ 后端逻辑修复)
- [x] 前端 (→ 前端判断修复)
## 技术方案
**方案 A推荐后端 API 返回 `tier_progress_map`,前端使用**
让前后端使用同一份进度数据源(`TierProgressMap`),确保判断一致。
### 实施步骤
#### Step 1后端 - API Response 增加 `tier_progress_map` 字段
**文件**: `internal/api/task_center/tasks_app.go`
1.`taskProgressResponse` 结构体中添加 `TierProgressMap` 字段:
```go
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"` // 新增
}
```
2.`GetTaskProgressForApp` handler 中填充该字段。
#### Step 2前端 - `isTierClaimable` 优先使用 `tier_progress`
**文件**: `bindbox-mini/pages-user/tasks/index.vue`
1.`fetchData` 中解析并存储 `tier_progress``taskProgress[taskId]`
2. 修改 `isTierClaimable` 函数,优先从 `tierProgress` 中查找对应 tier 的进度
3. 修改 `getTierProgressText``getTierProgressPercent`,同步使用新数据源
```js
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同步修改进度显示
修改 `getTierProgressText``getTierProgressPercent` 也优先使用 `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_count``sub_progress` 字段不变,`tier_progress` 为新增字段,向后兼容 |
| `tier_progress_map` 为空(数据库无 tiers 配置) | 前端 fallback 到原有 `subProgress` / 全局进度逻辑 |
| 已部署但未刷新前端的用户 | `tier_progress` 是附加字段,不影响旧逻辑 |
### SESSION_ID供 /ccg:execute 使用)
- CODEX_SESSION: N/A未使用外部模型
- GEMINI_SESSION: N/A未使用外部模型