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
224 lines
7.9 KiB
Markdown
224 lines
7.9 KiB
Markdown
## 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 页面保持一致?
|