## Context EmailBill 是一个预算跟踪应用,包含 .NET 10 后端和 Vue 3 前端。预算模块负责计算和展示预算执行情况,包括收入、支出和存款计划。 **当前问题**: 1. 预算收入的实际金额计算错误,`BudgetRepository.GetCurrentAmountAsync` 方法查询交易记录时可能存在过滤条件问题 2. 存款计划卡片缺少透明度,用户无法了解"计划存款"金额的计算依据 3. 预算页面的卡片样式与统计页面不一致,影响视觉统一性 **技术栈**: - 后端:.NET 10, FreeSql ORM, xUnit 测试 - 前端:Vue 3 Composition API, Vant UI, SCSS - 数据库:SQLite **约束**: - 保持向后兼容,不破坏现有 API 契约 - 遵循项目现有的代码风格(中文注释、文件作用域命名空间) - 样式修改需保持暗色主题兼容性 ## Goals / Non-Goals **Goals:** - 修复收入预算实际金额的计算错误,确保数据准确性 - 为存款计划添加明细展示功能,提升透明度 - 统一预算页面与统计页面的卡片样式,提升 UI 一致性 - 添加单元测试覆盖修复的逻辑 **Non-Goals:** - 不重构整个预算计算系统 - 不改变预算数据模型结构 - 不修改其他页面的卡片样式 - 不改变存款计划的计算算法本身 ## Decisions ### 决策 1:问题 1 的修复策略 **决定**:采用 TDD(测试驱动开发)方式修复计算错误 **方案对比**: - **方案 A(选择)**:先编写失败的单元测试复现 bug,然后修复代码,最后验证测试通过 - ✅ 确保 bug 被正确理解和修复 - ✅ 防止回归 - ⏱️ 需要额外编写测试 - **方案 B**:直接修复代码,手动验证 - ❌ 无法保证不引入新问题 - ❌ 缺少回归保护 **实施细节**: 1. 在 `WebApi.Test/` 中创建测试用例,使用实际数据复现"家庭年终奖金"的计算错误 2. 诊断 `BudgetRepository.GetCurrentAmountAsync` 的查询条件: - 检查 `SelectedCategories` 的 `Contains` 匹配逻辑 - 验证日期范围过滤是否正确(`>=` 和 `<=`) - 确认 `TransactionType` 过滤条件 3. 修复后运行测试验证 ### 决策 2:存款计划明细的数据来源 **决定**:前端计算明细,不新增后端 API **方案对比**: - **方案 A(选择)**:前端基于现有数据计算明细 - ✅ 不增加后端复杂度 - ✅ 响应速度快 - ⚠️ 前端需要理解计算逻辑 - **方案 B**:新增后端 API 返回计算明细 - ⏱️ 需要设计新的 DTO 和 API - 🔄 增加网络往返 **实施细节**: 1. 明细弹窗展示内容: - **收入预算总计**:所有收入预算的限额和实际值 - **支出预算总计**:所有支出预算的限额和实际值 - **计划存款公式**:`收入预算 - 支出预算 = 计划存款` - **实际存款**:从 budget 对象获取 - **差额**:`计划存款 - 实际存款` 2. 使用 Vant 的 Popup 组件实现弹窗 3. 在 `BudgetCard.vue` 的 `header-actions` slot 添加"明细"图标按钮(`icon="info"`) ### 决策 3:样式统一的方案 **决定**:直接修改 `.chart-card` 样式,使其继承或匹配 `.common-card` **方案对比**: - **方案 A(选择)**:修改 `BudgetChartAnalysis.vue` 中的 `.chart-card` 样式 - ✅ 改动最小,影响范围可控 - ✅ 立即见效 - **方案 B**:将所有预算卡片改为使用 `.common-card` 类 - ⏱️ 需要大量 HTML 结构修改 - ⚠️ 可能影响现有布局逻辑 - **方案 C**:创建新的统一卡片组件 - 🔄 过度设计 - ⏱️ 需要重构多个页面 **实施细节**: 1. 修改 `Web/src/components/Budget/BudgetChartAnalysis.vue` 的 `.chart-card` 样式: ```scss .chart-card { background: var(--van-background-2); border-radius: 16px; // 改为 16px padding: 16px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); // 统一阴影 border: 1px solid var(--van-border-color); // 添加边框 margin: 0 12px 16px; // 添加边距 } ``` 2. 检查 `.gauge-card` 的特殊样式是否需要保留 3. 验证暗色主题下的效果 ## Risks / Trade-offs **风险 1:问题 1 的修复可能影响其他预算类型** - **缓解**:编写覆盖支出、收入、存款三种类型的测试用例 - **回退**:保留 git 历史,可快速回滚 **风险 2:明细弹窗的计算逻辑可能与后端不一致** - **缓解**:参考 `BudgetSavingsService.cs` 的计算逻辑,确保前端实现一致 - **验证**:与后端计算结果进行对比测试 **风险 3:样式修改可能在某些设备或浏览器上显示异常** - **缓解**:修改后在浏览器中测试深色/浅色主题 - **回退**:样式改动独立 commit,可快速回滚 **权衡:前端计算 vs 后端计算** - 选择前端计算明细可以减少 API 开销,但增加了前端复杂度 - 如果未来计算逻辑变得更复杂,可能需要迁移到后端 ## Migration Plan **部署步骤**: 1. 后端修复和测试: - 运行 `dotnet test` 确保所有测试通过 - 构建后端:`dotnet build` 2. 前端修改: - 运行 `pnpm lint` 检查代码风格 - 构建前端:`pnpm build` 3. 浏览器验证: - 测试收入预算的实际金额显示 - 测试存款计划明细弹窗 - 验证卡片样式一致性 **回滚策略**: - 所有改动都在独立分支,可快速回滚 - 数据库无结构变更,无需数据迁移 **验证清单**: - [ ] 收入预算的"家庭年终奖金"实际金额正确显示 - [ ] 存款计划卡片有明细按钮,点击显示计算详情 - [ ] 预算页面的卡片样式与统计页面一致 - [ ] 所有单元测试通过 - [ ] 前端 ESLint 无错误 ## Open Questions 1. **问题 1 的具体原因**:`SelectedCategories` 匹配问题还是日期范围问题? - 需要查看实际数据库中的 `TransactionRecord` 和 `BudgetRecord` 数据 - 建议在修复前添加详细的日志输出 2. **明细弹窗是否需要支持历史月份查询?** - 当前设计仅展示当前周期的明细 - 如果需要历史查询,可能需要后端 API 支持 3. **样式修改是否需要同步到其他使用 `.chart-card` 的组件?** - 需要检查是否有其他页面使用了相同的类名 - 建议全局搜索 `.chart-card` 确认影响范围