Files
EmailBill/openspec/changes/archive/2026-02-13-budget-page-v2/design.md
SunCheng 162b6d02dd
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 26s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
fix
2026-02-13 22:49:07 +08:00

224 lines
7.9 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.
## Context
当前预算页面(`BudgetView.vue`)是一个 1000+ 行的单文件组件,存在以下问题:
- 与 calendarV2、statisticsV2 风格不一致(页头和时间段切换设计不同)
- 数据加载逻辑复杂且存在 bug未覆盖分类、存款计划切换、日期同步问题
- 组件职责不清晰,难以维护
参考其他 v2 页面的经验,我们需要重构预算页面以实现:
1. 统一的页头设计DateSelectHeader
2. 模块化的组件结构(主页面 + 子模块)
3. 清晰的数据流和状态管理
4. 简洁高效的用户体验(月度视图为主)
**技术栈约束**
- Vue 3 Composition API + `<script setup>`
- Vant UI 组件库
- 现有的 `@/api/budget` 接口(不修改后端)
- 复用现有的 DateSelectHeader 组件
## Goals / Non-Goals
**Goals:**
- 创建简洁高效的预算 v2 页面
- 使用统一的 DateSelectHeader 组件
- 修复现有 bug数据加载、日期同步、存款计划切换
- 提升代码可维护性(拆分子模块,清晰职责)
- 保持所有现有业务功能(支出/收入/计划预算管理)
**Non-Goals:**
- 不修改后端 API完全前端重构
- 不改变预算业务逻辑(仅重构实现)
- 不添加新的预算功能(如预算模板、智能推荐等)
- 不添加周/年视图(保持月度视图为主)
- 不删除旧的 BudgetView.vue保留作为回退方案后续独立 PR 删除)
## Decisions
### 1. 页面布局结构:简洁的两层布局
**决策**:采用简洁的两层布局结构
```
- DateSelectHeader (年月选择器 + 左右箭头 + 通知图标)
- van-tabs (支出/收入/计划切换)
- 可滚动内容区域
- 下拉刷新
- 预算内容(统计卡片、图表、列表)
```
**理由**
- ✅ 简洁明了,减少复杂度
- ✅ 预算管理以月度为主,不需要周/年视图
- ✅ 与现有预算页面的逻辑一致,降低用户学习成本
**替代方案**
- ❌ 引入 TimePeriodTabs增加复杂度预算管理不需要多时间段
- ❌ 保留当前布局:无法实现风格统一和 bug 修复
### 2. 组件拆分策略:主页面 + 子模块
**决策**:创建 `budgetV2/Index.vue` 作为主页面,按业务功能拆分子模块
```
budgetV2/
├── Index.vue # 主页面布局、时间段切换、tabs
└── modules/
├── ExpenseBudgetContent.vue # 支出预算内容(统计 + 列表)
├── IncomeBudgetContent.vue # 收入预算内容(统计 + 列表)
└── SavingsBudgetContent.vue # 存款计划内容(列表 + 日期切换)
```
**理由**
- ✅ 主页面职责清晰(只负责布局和状态协调)
- ✅ 子模块独立开发和测试
- ✅ 参考 calendarV2 的 modules 模式
**替代方案**
- ❌ 单文件组件:难以维护(当前问题)
- ❌ 更细粒度拆分(如 ExpenseStats.vue, ExpenseList.vue过度设计增加文件数量
### 3. 数据加载策略:月度数据为主
**决策**:专注于月度数据加载,在主页面集中管理数据加载逻辑
```javascript
// Index.vue
const currentDate = ref(new Date()) // 当前年月
const activeTab = ref(BudgetCategory.Expense) // 当前业务 tab
// 统一数据加载函数(月度)
const loadBudgetData = async () => {
const year = currentDate.value.getFullYear()
const month = currentDate.value.getMonth() + 1
// 调用 getBudgetList, getCategoryStats 等月度 API
}
// 子模块通过 props 接收数据
<ExpenseBudgetContent :budgets="expenseBudgets" :stats="expenseStats" />
```
**理由**
- ✅ 简化逻辑,避免周/年数据的复杂处理
- ✅ 预算管理以月度为核心
- ✅ 统一的错误处理和加载状态
**替代方案**
- ❌ 支持多时间段:增加复杂度,预算场景不需要
- ❌ 子模块独立加载数据:重复逻辑,难以同步
### 4. 存款计划特殊处理:独立的日期切换逻辑
**决策**:存款计划保留现有的独立日期切换功能(卡片底部的前后箭头)
- 不受页头的 `currentDate` 影响
- 每个存款计划独立维护自己的 `periodStart` 状态
- 通过 `getSavingsBudget(year, month, type)` 切换日期
**理由**
- ✅ 符合业务需求(存款计划可能需要查看历史数据)
- ✅ 保持现有功能不变
**风险**
- ⚠️ 两套日期状态可能造成用户困惑
- **缓解措施**:在 UI 上明确区分(页头日期用于支出/收入,卡片底部日期用于存款计划)
### 5. 路由策略:创建新路由,保留旧路由
**决策**
- 创建新路由 `/budget-v2`(指向 `budgetV2/Index.vue`
- 保留旧路由 `/budget`(指向 `BudgetView.vue`
- 在导航中将"预算"菜单指向 `/budget-v2`
**理由**
- ✅ 支持灰度发布(可以快速回退)
- ✅ 便于对比测试
**迁移计划**
- 第一阶段:创建新路由,灰度测试
- 第二阶段:确认稳定后,删除旧路由和旧页面
### 6. 组件复用策略
**决策**:最大化复用现有组件,只在必要时调整
- ✅ 直接复用DateSelectHeader月度模式、BudgetEditPopup、SavingsConfigPopup、BudgetCard、BudgetChartAnalysis
- ⚠️ 不使用 TimePeriodTabs简化设计
**理由**
- 减少重复代码
- 保持 UI 一致性
- 简化维护
## Risks / Trade-offs
### Risk 1: 月度数据加载的稳定性
**风险**:数据加载和状态管理需要正确处理各种边界情况
**缓解措施**
- 参考现有 BudgetView 的数据加载逻辑
- 编写单元测试覆盖边界情况
- 详细的代码注释
### Risk 2: 存款计划的双日期状态可能造成用户困惑
**风险**:页头日期和存款计划的独立日期切换可能让用户困惑
**缓解措施**
- 在 UI 上明确区分(页头日期影响支出/收入,存款计划有独立切换)
- 添加帮助提示或引导
### Risk 3: 旧预算页面的兼容性
**风险**:用户习惯了旧页面的交互方式,可能不适应新页面
**缓解措施**
- 保留旧路由作为回退方案
- 收集用户反馈,快速迭代
### Risk 4: API 兼容性
**风险**:现有 API 可能存在未预见的边界情况
**缓解措施**
- 充分测试所有 API 调用
- 添加完善的错误处理
### Trade-off 1: 新旧页面并存增加维护成本
**权衡**:保留旧页面作为回退方案,但会增加短期维护成本
**接受理由**
- 灰度发布的安全性更重要
- 确认稳定后会删除旧页面
### Trade-off 2: 功能简化
**权衡**:不支持周/年视图,只支持月度
**接受理由**
- 预算管理以月度为核心,周/年视图使用频率低
- 简化设计,降低复杂度和维护成本
- 如果后续有需求,可以独立迭代
## Migration Plan
### 阶段 1开发和本地测试1 天)
1. 创建 `budgetV2/Index.vue` 和子模块
2. 实现基础布局DateSelectHeader + 业务 tabs
3. 实现支出/收入/存款三个 tabs 的内容(月度数据)
4. 本地测试所有功能(重点测试数据加载和日期切换)
### 阶段 2灰度发布1 周)
1. 添加新路由 `/budget-v2`
2. 在导航中将"预算"菜单指向新路由
3. 保留旧路由 `/budget` 作为回退
4. 收集用户反馈,修复 bug
### 阶段 3稳定后清理独立 PR
1. 确认新页面稳定后,删除旧路由
2. 删除 `BudgetView.vue`
3. 清理相关的测试代码
### Rollback 策略
如果新页面出现严重 bug
1. 在导航中将"预算"菜单改回 `/budget`
2. 修复 bug 后再次切换到 `/budget-v2`
## Open Questions
1. **BudgetChartAnalysis 组件是否需要调整?**
- 需要评估当前组件是否完全满足月度数据展示需求
- 是否需要调整图表样式或数据格式
2. **未覆盖分类的展示位置?**
- 当前在页头右侧有警告图标
- 新布局中是否保留此功能?位置在哪里?
3. **是否需要支持左右滑动切换月份?**
- 是否需要与其他 v2 页面保持一致?