144 lines
6.1 KiB
Markdown
144 lines
6.1 KiB
Markdown
## Context
|
||
|
||
**当前状态**:
|
||
- 后端 `BudgetStatsService` 已正确计算 `Description` (HTML格式明细) 和 `Trend` (每日累计金额数组)
|
||
- Service 层的 `BudgetStatsDto` 包含这两个字段
|
||
- **问题**: Application 层在映射 DTO 时丢失了这两个字段,导致 API 响应不完整
|
||
- 前端使用 fallback 逻辑(线性估算)来弥补缺失数据,导致燃尽图显示为直线
|
||
|
||
**约束**:
|
||
- 修复必须向后兼容,不能破坏现有 API 契约
|
||
- 优先修复 Bug #4 和 #5(高优先级),因为修复简单且影响大
|
||
- 前端已有完整的数据处理逻辑,只需后端提供正确数据
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
- 修复 `BudgetStatsDetail` DTO 定义,添加 `Description` 和 `Trend` 字段
|
||
- 修复 `BudgetApplication.GetCategoryStatsAsync` 中的 DTO 映射逻辑
|
||
- 修复前端路由配置和 Vant 组件注册问题
|
||
- 分析并修复账单删除功能和金额不一致问题
|
||
- 添加单元测试覆盖修复场景
|
||
|
||
**Non-Goals:**
|
||
- 不重构 `BudgetStatsService` 的计算逻辑(已验证正确)
|
||
- 不改变前端图表组件的渲染逻辑(已有完整支持)
|
||
- 不修改 API 路由或版本化(向后兼容)
|
||
|
||
## Decisions
|
||
|
||
### 决策 1: 使用 `init` 关键字而非 `set` 来定义新字段
|
||
**理由**: `BudgetStatsDetail` 是 `record` 类型,遵循不可变对象模式。使用 `init` 确保字段只能在对象初始化时设置。
|
||
|
||
**替代方案**:
|
||
- 改用 `class` + `set` → 违背现有代码风格,且失去 record 的值语义
|
||
- 保持 `record` + `set` → C# 9+ 允许,但不符合不可变设计原则
|
||
|
||
### 决策 2: 在 Application 层映射时直接赋值,不做转换
|
||
**理由**: Service 层的 `BudgetStatsDto.Trend` 和 `Description` 已经是目标格式(`List<decimal?>` 和 `string`),无需额外处理。
|
||
|
||
**实现**:
|
||
```csharp
|
||
Month = new BudgetStatsDetail
|
||
{
|
||
Limit = stats.Month.Limit,
|
||
Current = stats.Month.Current,
|
||
Remaining = stats.Month.Remaining,
|
||
UsagePercentage = stats.Month.UsagePercentage,
|
||
Trend = stats.Month.Trend, // ⬅️ 新增
|
||
Description = stats.Month.Description // ⬅️ 新增
|
||
}
|
||
```
|
||
|
||
### 决策 3: Bug #1 (路由跳转) - 修改底部导航配置而非路由定义
|
||
**理由**: 经验证,`/statistics-v2` 路由已存在且正常工作。问题出在底部导航组件中硬编码了错误的路由路径。
|
||
|
||
**定位策略**:
|
||
1. 搜索底部导航组件代码 (通常包含 `van-tabbar` 或 `router-link`)
|
||
2. 检查"统计"标签的 `to` 属性或 `path` 配置
|
||
3. 修改为 `/statistics-v2`
|
||
|
||
### 决策 4: Bug #2 (删除功能) - 添加确认对话框而非直接删除
|
||
**理由**: 删除操作是破坏性的,应符合最佳实践要求用户确认。
|
||
|
||
**实现**:
|
||
```vue
|
||
const handleDelete = async () => {
|
||
const confirmed = await showConfirmDialog({
|
||
title: '确认删除',
|
||
message: '确定要删除这条账单吗?此操作无法撤销。'
|
||
})
|
||
if (confirmed) {
|
||
await deleteBill(billId)
|
||
closePopup()
|
||
}
|
||
}
|
||
```
|
||
|
||
### 决策 5: Bug #3 (组件警告) - 按需导入而非全局注册
|
||
**理由**: Vant 推荐使用按需导入,减少打包体积。全局注册可能是遗漏导致的警告。
|
||
|
||
**验证步骤**:
|
||
1. 检查 `main.ts` 或全局插件文件是否有 `DatetimePicker` 导入
|
||
2. 如果缺失,添加 `import { DatetimePicker } from 'vant'; app.use(DatetimePicker);`
|
||
3. 或在使用组件的文件中局部导入
|
||
|
||
### 决策 6: Bug #6 (金额不一致) - 先验证是否虚拟消耗导致
|
||
**理由**: Bug-handoff 文档指出硬性预算 (📌标记) 会产生虚拟消耗,这是设计行为而非 bug。
|
||
|
||
**验证逻辑**:
|
||
1. 检查不一致的预算是否标记为硬性预算
|
||
2. 检查 `BudgetService.GetPeriodRange` 返回的日期范围是否与 `periodStart/periodEnd` 一致
|
||
3. 如果是虚拟消耗:在前端账单列表中添加提示说明
|
||
4. 如果是日期范围问题:修复 `BudgetResult` 的赋值逻辑
|
||
|
||
## Risks / Trade-offs
|
||
|
||
### 风险 1: API 响应体积增大
|
||
**问题**: 新增 `Trend` 数组(月度31个元素,年度12个元素)会增加响应大小。
|
||
|
||
**缓解措施**:
|
||
- `Trend` 数据是前端绘制图表必需的,体积增长合理
|
||
- 考虑后续添加 gzip 压缩到 API 响应(可选优化)
|
||
|
||
### 风险 2: 前端可能依赖旧的 fallback 逻辑
|
||
**问题**: 如果前端代码中有显式检查 `trend.length === 0` 的逻辑,可能会在修复后仍执行 fallback。
|
||
|
||
**缓解措施**:
|
||
- 在修复后端后,验证前端 `BudgetChartAnalysis.vue:603` 和 `629` 行的条件是否正确处理非空 trend
|
||
- 如果逻辑有问题,修改为 `if (!trend || trend.length === 0)`
|
||
|
||
### 风险 3: 测试覆盖不足可能导致回归
|
||
**问题**: 现有测试可能未覆盖 DTO 映射场景。
|
||
|
||
**缓解措施**:
|
||
- 在 `WebApi.Test` 中添加针对 `BudgetApplication.GetCategoryStatsAsync` 的单元测试
|
||
- 验证返回的 DTO 包含非空的 `Description` 和 `Trend`
|
||
- 使用 `FluentAssertions` 编写清晰的断言
|
||
|
||
## Migration Plan
|
||
|
||
**部署步骤**:
|
||
1. 部署后端更新(向后兼容,前端可继续使用旧逻辑)
|
||
2. 验证 API 响应包含新字段 (使用 Swagger 或浏览器开发工具)
|
||
3. 前端无需额外部署(已支持新字段,会自动切换到真实数据)
|
||
4. 清除浏览器缓存以确保使用最新前端代码
|
||
|
||
**回滚策略**:
|
||
- 如果新版本出现问题,回滚到上一个 commit
|
||
- API 是向后兼容的(只添加字段),旧版前端仍可正常工作
|
||
|
||
**验证清单**:
|
||
- [ ] 预算明细弹窗显示完整的 HTML 表格
|
||
- [ ] 燃尽图显示波动曲线而非直线
|
||
- [ ] 底部导航"统计"按钮正常跳转
|
||
- [ ] 删除账单功能弹出确认对话框并正常工作
|
||
- [ ] 控制台无 `van-datetime-picker` 警告
|
||
- [ ] 金额不一致问题已分析并修复或说明
|
||
|
||
## Open Questions
|
||
|
||
1. **Bug #6 金额不一致的根本原因**: 需要在测试环境中验证是否为虚拟消耗导致,还是日期范围计算错误。
|
||
2. **前端 fallback 逻辑是否需要移除**: 当前 fallback 作为容错机制保留是否合理?还是应在有真实数据时完全禁用?
|
||
3. **是否需要添加 E2E 测试**: 当前只计划单元测试,是否需要添加端到端测试覆盖完整流程?
|