Files
eryao/.trellis/tasks/archive/2026-04/04-28-feat-points-ledger/prd.md
T

202 lines
5.6 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.
# PRD:积分流水列表功能
## 1. 背景与目标
当前应用已有完整的积分账户系统:
- 积分账户表:`user_points`
- 积分业务流水:`points_ledger`(记录所有积分变动)
- 积分余额查询接口:`GET /api/v1/points/balance`
- 积分中心页面:`CoinCenterScreen`
用户在积分中心可以看到余额和购买套餐,但无法查看积分的收支明细。本任务目标是增加积分流水列表功能,让用户了解自己的积分变动历史。
## 2. 当前事实
### 2.1 后端现状
**已有的 `points_ledger` 表结构**
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | 主键 |
| `user_id` | UUID | 用户 ID |
| `direction` | smallint | 方向:1=收入,-1=支出 |
| `amount` | bigint | 变动数量(正数) |
| `balance_after` | bigint | 变动后余额 |
| `change_type` | varchar | 类型:register/consume/adjust/purchase/refund |
| `biz_type` | varchar | 业务类型:chat/payment(可空) |
| `biz_id` | UUID | 业务 ID(可空) |
| `event_id` | varchar | 幂等事件 ID |
| `operator_id` | UUID | 操作者 ID(可空) |
| `metadata` | jsonb | 扩展元数据 |
| `created_at` | timestamptz | 创建时间 |
**已有的索引**
- `ix_points_ledger_user_created_at`:支持按用户+时间倒序查询
- `uq_points_ledger_user_event`:用户+事件唯一约束
**已有的 Repository 方法**
- `append_ledger()`:写入流水
- `has_ledger_event()`:检查事件是否存在
**缺失**
- 无分页查询流水列表方法
- 无 HTTP API 端点
### 2.2 前端现状
**已有的积分中心页面**
- `apps/lib/features/settings/presentation/screens/coin_center_screen.dart`
- 显示余额和套餐卡片
**已有的 API 调用**
- `apps/lib/features/points/data/apis/points_api.dart`:仅支持 `getPackages()`
**缺失**
- 无流水列表 API 调用
- 无流水列表页面/组件
## 3. 需求范围
### 3.1 必须实现
**后端**
- 新增 `GET /api/v1/points/ledger` 接口
- 支持分页(游标分页,按 `created_at` 倒序)
- 返回流水列表,包含:时间、类型、金额、余额、描述
**前端**
- 在积分中心页面添加「查看流水」入口
- 新建流水列表页面,支持分页加载
- 流水项展示:类型图标、类型文案、金额(+绿色/-红色)、时间、余额
### 3.2 本期不做
- 按类型筛选(可作为后续优化)
- 导出流水
- 流水详情页
## 4. 数据契约
### 4.1 API 接口
**请求**
```
GET /api/v1/points/ledger?limit=20&cursor={created_at_iso}
```
**响应**
```json
{
"items": [
{
"id": "uuid",
"direction": 1,
"amount": 100,
"balanceAfter": 500,
"changeType": "purchase",
"displayText": "购买积分包",
"createdAt": "2026-04-28T10:00:00Z"
}
],
"nextCursor": "2026-04-27T10:00:00Z",
"hasMore": true
}
```
### 4.2 change_type 对应展示文案
| change_type | direction | 展示文案(中文) | 展示文案(英文) |
|-------------|-----------|------------------|------------------|
| register | 1 | 注册赠送 | Registration bonus |
| purchase | 1 | 购买积分包 | Purchase credits |
| consume | -1 | AI 对话消耗 | AI chat cost |
| adjust | ±1 | 系统调整 | System adjustment |
| refund | -1 | 退款 | Refund |
## 5. 技术方案
### 5.1 后端实现
**Repository 层**`v1/points/repository.py`):
```python
async def list_ledger(
self,
*,
user_id: UUID,
limit: int,
cursor: datetime | None = None,
) -> tuple[list[PointsLedger], bool]:
# 查询 points_ledger 表
# 按 created_at DESC 分页
# 返回 (items, has_more)
```
**Service 层**`v1/points/service.py`):
```python
async def get_ledger_list(
self,
*,
user_id: UUID,
limit: int = 20,
cursor: str | None = None,
) -> LedgerListResult:
# 调用 repository
# 组装 display_text
# 返回响应
```
**Router 层**`v1/points/router.py`):
```python
@router.get("/ledger", response_model=LedgerListResponse)
async def get_points_ledger(...):
...
```
### 5.2 前端实现
**目录结构**
```
apps/lib/features/points/
├── data/
│ ├── apis/
│ │ └── points_api.dart # 新增 getLedger()
│ └── models/
│ ├── package_info.dart # 已有
│ └── ledger_item.dart # 新增
└── presentation/
└── screens/
└── points_ledger_screen.dart # 新增
```
**入口**
-`CoinCenterScreen` 的余额卡片下方添加「查看流水」按钮
- 点击后导航到 `PointsLedgerScreen`
## 6. 实现步骤
### Phase 1: 后端 API
1. 新增 Schema`LedgerItem``LedgerListResponse``v1/points/schemas.py`
2. 新增 Repository 方法:`list_ledger()``v1/points/repository.py`
3. 新增 Service 方法:`get_ledger_list()``v1/points/service.py`
4. 新增 Router 端点:`GET /ledger``v1/points/router.py`
5. 编写单元测试
### Phase 2: 前端 UI
1. 新增 Model`LedgerItem``features/points/data/models/ledger_item.dart`
2. 新增 API 方法:`getLedger()``features/points/data/apis/points_api.dart`
3. 新增页面:`PointsLedgerScreen``features/points/presentation/screens/points_ledger_screen.dart`
4. 修改 `CoinCenterScreen`,添加入口按钮
5. 添加 i18n 文案(`app_zh.arb``app_en.arb``app_zh_hant.arb`
## 7. 验收标准
- [ ] 后端 API 返回正确的分页数据
- [ ] 前端能正确加载并展示流水列表
- [ ] 流水类型显示对应文案
- [ ] 金额按收支方向显示不同颜色
- [ ] 分页加载正常工作
- [ ] 无数据时显示空状态
- [ ] 加载中显示 loading 状态