221 lines
11 KiB
Markdown
221 lines
11 KiB
Markdown
|
|
## 1. 项目结构准备
|
|||
|
|
|
|||
|
|
- [x] 1.1 创建 `Web/src/views/budgetV2/` 目录
|
|||
|
|
- [x] 1.2 创建 `Web/src/views/budgetV2/modules/` 子目录
|
|||
|
|
- [x] 1.3 创建 `Web/src/views/budgetV2/Index.vue` 主页面文件(空模板)
|
|||
|
|
- [x] 1.4 创建 `Web/src/views/budgetV2/modules/ExpenseBudgetContent.vue` 支出预算子模块(空模板)
|
|||
|
|
- [x] 1.5 创建 `Web/src/views/budgetV2/modules/IncomeBudgetContent.vue` 收入预算子模块(空模板)
|
|||
|
|
- [x] 1.6 创建 `Web/src/views/budgetV2/modules/SavingsBudgetContent.vue` 存款计划子模块(空模板)
|
|||
|
|
|
|||
|
|
## 2. 路由配置
|
|||
|
|
|
|||
|
|
- [x] 2.1 在 `Web/src/router/index.js` 中添加 `/budget-v2` 路由,指向 `budgetV2/Index.vue`
|
|||
|
|
- [x] 2.2 配置路由的 `name: 'BudgetV2'` 和 `meta` 信息(用于 keep-alive)
|
|||
|
|
- [x] 2.3 保留旧路由 `/budget` 指向 `BudgetView.vue`(作为回退方案)
|
|||
|
|
- [x] 2.4 在导航配置中将"预算"菜单指向新路由 `/budget-v2`
|
|||
|
|
|
|||
|
|
## 3. 主页面布局实现
|
|||
|
|
|
|||
|
|
- [x] 3.1 在 `Index.vue` 中引入 `DateSelectHeader` 组件
|
|||
|
|
- [x] 3.2 添加 `van-tabs` 组件(支出/收入/计划三个 tab)
|
|||
|
|
- [x] 3.3 添加可滚动内容区域(包含 `van-pull-refresh`)
|
|||
|
|
- [x] 3.4 设置页面容器样式(`page-container-flex` + 底部安全距离)
|
|||
|
|
- [x] 3.5 配置 `defineOptions({ name: 'BudgetV2View' })` 用于 keep-alive
|
|||
|
|
|
|||
|
|
## 4. 状态管理和数据定义
|
|||
|
|
|
|||
|
|
- [x] 4.1 定义当前日期状态 `currentDate = ref(new Date())`
|
|||
|
|
- [x] 4.2 定义业务 tab 状态 `activeTab = ref(BudgetCategory.Expense)`
|
|||
|
|
- [x] 4.3 定义数据状态(`expenseBudgets`、`incomeBudgets`、`savingsBudgets`、`overallStats`)
|
|||
|
|
- [x] 4.4 定义 UI 状态(`loading`、`refreshing`、`hasError`、`errorMessage`)
|
|||
|
|
- [x] 4.5 定义未覆盖分类状态 `uncoveredCategories = ref([])`
|
|||
|
|
- [x] 4.6 定义归档总结状态(`showSummaryPopup`、`archiveSummary`)
|
|||
|
|
- [x] 4.7 定义日期选择器状态(`showDatePicker`、`pickerDate`)
|
|||
|
|
|
|||
|
|
## 5. DateSelectHeader 集成
|
|||
|
|
|
|||
|
|
- [x] 5.1 配置 DateSelectHeader 的 `type` 属性为 'month'
|
|||
|
|
- [x] 5.2 绑定 DateSelectHeader 的 `current-date` 属性到 `currentDate`
|
|||
|
|
- [x] 5.3 监听 DateSelectHeader 的 `@prev` 事件,实现 `handlePrevMonth()` 方法
|
|||
|
|
- [x] 5.4 监听 DateSelectHeader 的 `@next` 事件,实现 `handleNextMonth()` 方法
|
|||
|
|
- [x] 5.5 监听 DateSelectHeader 的 `@jump` 事件,打开日期选择器
|
|||
|
|
- [x] 5.6 在页头右侧添加未覆盖分类警告图标(根据 `uncoveredCategories` 显示)
|
|||
|
|
- [x] 5.7 在页头右侧添加归档图标(历史月份显示)
|
|||
|
|
|
|||
|
|
## 6. 业务 tabs 实现
|
|||
|
|
|
|||
|
|
- [x] 6.1 配置 `van-tabs` 的三个 tab(支出、收入、计划)
|
|||
|
|
- [x] 6.2 绑定 `van-tabs` 的 `v-model:active` 到 `activeTab`
|
|||
|
|
- [x] 6.3 监听 `activeTab` 的变化,触发数据刷新(使用 `watch`)
|
|||
|
|
- [x] 6.4 在每个 tab 中引入对应的子模块组件
|
|||
|
|
|
|||
|
|
## 7. 数据加载核心逻辑
|
|||
|
|
|
|||
|
|
- [x] 7.1 实现 `loadBudgetData()` 统一数据加载函数(月度)
|
|||
|
|
- [x] 7.2 实现 `loadMonthlyData(year, month)` 加载月度预算数据
|
|||
|
|
- [x] 7.3 实现 `loadCategoryStats()` 加载分类统计数据
|
|||
|
|
- [x] 7.4 实现 `loadUncoveredCategories()` 加载未覆盖分类(仅支出和收入 tab)
|
|||
|
|
- [x] 7.5 实现 `loadArchiveSummary()` 加载归档总结(历史月份)
|
|||
|
|
- [x] 7.6 使用 `Promise.allSettled()` 并发加载多个数据源
|
|||
|
|
|
|||
|
|
## 8. 月份切换逻辑
|
|||
|
|
|
|||
|
|
- [x] 8.1 实现 `handlePrevMonth()` 方法(切换到上一个月)
|
|||
|
|
- [x] 8.2 实现 `handleNextMonth()` 方法(切换到下一个月,禁止未来月份)
|
|||
|
|
- [x] 8.3 实现 `isCurrentMonth()` 方法(判断是否为当前月,禁用右箭头)
|
|||
|
|
- [x] 8.4 在月份切换后自动调用 `loadBudgetData()` 刷新数据
|
|||
|
|
|
|||
|
|
## 9. 日期选择器实现
|
|||
|
|
|
|||
|
|
- [x] 9.1 添加 `van-popup` + `van-date-picker` 组件
|
|||
|
|
- [x] 9.2 配置日期选择器为年月模式(columns-type: ['year', 'month'])
|
|||
|
|
- [x] 9.3 实现 `onDatePickerConfirm()` 方法(确认日期选择)
|
|||
|
|
- [x] 9.4 在日期选择器中限制不能选择未来的月份
|
|||
|
|
- [x] 9.5 选择日期后自动调用 `loadBudgetData()` 刷新数据
|
|||
|
|
|
|||
|
|
## 10. 左右滑动手势实现
|
|||
|
|
|
|||
|
|
- [x] 10.1 定义触摸状态(`touchStartX`, `touchStartY`, `touchEndX`, `touchEndY`)
|
|||
|
|
- [x] 10.2 实现 `handleTouchStart()` 方法(记录触摸起始位置)
|
|||
|
|
- [x] 10.3 实现 `handleTouchMove()` 方法(记录触摸移动位置)
|
|||
|
|
- [x] 10.4 实现 `handleTouchEnd()` 方法(判断滑动方向和距离)
|
|||
|
|
- [x] 10.5 在 `handleTouchEnd()` 中根据滑动方向调用 `handlePrevMonth()` 或 `handleNextMonth()`
|
|||
|
|
- [x] 10.6 设置最小滑动距离阈值(50px),避免误触
|
|||
|
|
- [x] 10.7 确保垂直滑动(滚动内容)不触发月份切换
|
|||
|
|
|
|||
|
|
## 11. 下拉刷新实现
|
|||
|
|
|
|||
|
|
- [x] 11.1 配置 `van-pull-refresh` 组件,绑定 `v-model="refreshing"`
|
|||
|
|
- [x] 11.2 实现 `onRefresh()` 方法(清除错误状态,重新加载数据)
|
|||
|
|
- [x] 11.3 在数据加载完成后设置 `refreshing = false`
|
|||
|
|
- [x] 11.4 显示刷新成功提示
|
|||
|
|
|
|||
|
|
## 12. 加载状态和错误处理
|
|||
|
|
|
|||
|
|
- [x] 12.1 在数据加载中显示 `van-loading` 组件
|
|||
|
|
- [x] 12.2 在数据加载失败时显示 `van-empty` 组件(包含"重试"按钮)
|
|||
|
|
- [x] 12.3 实现 `retryLoad()` 方法(清除错误状态,重新加载数据)
|
|||
|
|
- [x] 12.4 在所有 API 调用中添加 try-catch 错误处理
|
|||
|
|
- [x] 12.5 使用 `Promise.allSettled()` 并发加载,避免单点失败
|
|||
|
|
|
|||
|
|
## 13. 支出预算子模块实现
|
|||
|
|
|
|||
|
|
- [x] 13.1 在 `ExpenseBudgetContent.vue` 中定义 props(`budgets`, `stats`, `uncoveredCategories`)
|
|||
|
|
- [x] 13.2 复用 `BudgetChartAnalysis` 组件显示统计图表
|
|||
|
|
- [x] 13.3 复用 `BudgetCard` 组件显示预算列表
|
|||
|
|
- [x] 13.4 使用 `van-swipe-cell` 实现左滑删除功能
|
|||
|
|
- [x] 13.5 点击预算卡片打开 `BudgetEditPopup` 编辑弹窗
|
|||
|
|
- [x] 13.6 添加悬浮按钮(`van-floating-bubble`)打开预算列表弹窗
|
|||
|
|
- [x] 13.7 在预算列表弹窗中显示所有支出预算
|
|||
|
|
|
|||
|
|
## 14. 收入预算子模块实现
|
|||
|
|
|
|||
|
|
- [x] 14.1 在 `IncomeBudgetContent.vue` 中定义 props(`budgets`, `stats`, `uncoveredCategories`)
|
|||
|
|
- [x] 14.2 复用 `BudgetChartAnalysis` 组件显示统计图表
|
|||
|
|
- [x] 14.3 复用 `BudgetCard` 组件显示预算列表(调整显示字段:已收入、目标、差额)
|
|||
|
|
- [x] 14.4 使用 `van-swipe-cell` 实现左滑删除功能
|
|||
|
|
- [x] 14.5 点击预算卡片打开 `BudgetEditPopup` 编辑弹窗
|
|||
|
|
- [x] 14.6 添加悬浮按钮打开预算列表弹窗
|
|||
|
|
|
|||
|
|
## 15. 存款计划子模块实现
|
|||
|
|
|
|||
|
|
- [x] 15.1 在 `SavingsBudgetContent.vue` 中定义 props(`budgets`)
|
|||
|
|
- [x] 15.2 复用 `BudgetCard` 组件显示存款计划列表(调整显示字段:已存、目标、还差)
|
|||
|
|
- [x] 15.3 在每个存款计划卡片底部添加日期切换按钮(左箭头、日期标签、右箭头)
|
|||
|
|
- [x] 15.4 实现 `handleSavingsNav(budget, offset)` 方法(切换存款计划的日期)
|
|||
|
|
- [x] 15.5 实现 `getSavingsDateLabel(budget)` 方法(格式化存款计划的日期标签)
|
|||
|
|
- [x] 15.6 实现 `disabledSavingsNextNav(budget)` 方法(判断是否禁用右箭头)
|
|||
|
|
- [x] 15.7 调用 `getSavingsBudget(year, month, type)` API 切换存款计划日期
|
|||
|
|
- [x] 15.8 在页头右侧显示储蓄配置图标,点击打开 `SavingsConfigPopup`
|
|||
|
|
|
|||
|
|
## 16. 未覆盖分类弹窗实现
|
|||
|
|
|
|||
|
|
- [x] 16.1 复用 `PopupContainer` 组件创建未覆盖分类弹窗
|
|||
|
|
- [x] 16.2 在弹窗中显示未覆盖分类列表(分类名称、交易笔数、总金额)
|
|||
|
|
- [x] 16.3 使用卡片样式展示每个分类(`uncovered-item`)
|
|||
|
|
- [x] 16.4 在弹窗底部添加"我知道了"按钮关闭弹窗
|
|||
|
|
|
|||
|
|
## 17. 归档总结弹窗实现
|
|||
|
|
|
|||
|
|
- [x] 17.1 复用 `PopupContainer` 组件创建归档总结弹窗
|
|||
|
|
- [x] 17.2 调用 `getArchiveSummary(date)` API 获取归档总结
|
|||
|
|
- [x] 17.3 在弹窗中显示富文本内容(使用 `v-html`)
|
|||
|
|
- [x] 17.4 如果没有总结,显示"暂无总结"提示
|
|||
|
|
|
|||
|
|
## 18. 预算编辑和删除功能
|
|||
|
|
|
|||
|
|
- [x] 18.1 引入 `BudgetEditPopup` 组件
|
|||
|
|
- [x] 18.2 点击悬浮按钮打开 `BudgetEditPopup`(新增预算)
|
|||
|
|
- [x] 18.3 点击预算卡片打开 `BudgetEditPopup`(编辑预算)
|
|||
|
|
- [x] 18.4 在 `BudgetEditPopup` 的 `@success` 事件中调用 `loadBudgetData()` 刷新数据
|
|||
|
|
- [x] 18.5 实现 `handleDelete(budget)` 方法(删除预算)
|
|||
|
|
- [x] 18.6 在删除前显示确认对话框(`showConfirmDialog`)
|
|||
|
|
- [x] 18.7 调用 `deleteBudget(id)` API 删除预算
|
|||
|
|
- [x] 18.8 删除成功后调用 `loadBudgetData()` 刷新数据
|
|||
|
|
|
|||
|
|
## 19. 储蓄配置功能
|
|||
|
|
|
|||
|
|
- [x] 19.1 引入 `SavingsConfigPopup` 组件
|
|||
|
|
- [x] 19.2 在存款计划 tab 的页头右侧显示配置图标
|
|||
|
|
- [x] 19.3 点击配置图标打开 `SavingsConfigPopup`
|
|||
|
|
- [x] 19.4 在 `SavingsConfigPopup` 的 `@success` 事件中调用 `loadBudgetData()` 刷新数据
|
|||
|
|
|
|||
|
|
## 20. 全局事件监听
|
|||
|
|
|
|||
|
|
- [x] 20.1 在 `onMounted()` 中监听 'transactions-changed' 全局事件
|
|||
|
|
- [x] 20.2 实现 `handleTransactionsChanged()` 方法(刷新数据)
|
|||
|
|
- [x] 20.3 在 `onActivated()` 中处理从缓存恢复时的数据刷新
|
|||
|
|
- [x] 20.4 在 `onBeforeUnmount()` 中移除事件监听器
|
|||
|
|
|
|||
|
|
## 21. 样式和主题
|
|||
|
|
|
|||
|
|
- [x] 21.1 添加页面容器样式(`.budget-v2-wrapper`)
|
|||
|
|
- [x] 21.2 添加可滚动内容区域样式(`.budget-scroll-content`)
|
|||
|
|
- [x] 21.3 添加底部安全距离样式(`calc(95px + env(safe-area-inset-bottom))`)
|
|||
|
|
- [x] 21.4 配置主题变量(使用 `var(--van-primary-color)` 等)
|
|||
|
|
- [x] 21.5 添加深色模式支持(通过 `van-config-provider`)
|
|||
|
|
- [x] 21.6 优化移动端滚动体验(`-webkit-overflow-scrolling: touch`)
|
|||
|
|
|
|||
|
|
## 22. 辅助函数实现
|
|||
|
|
|
|||
|
|
- [x] 22.1 实现 `formatMoney(val)` 方法(格式化金额显示)
|
|||
|
|
- [x] 22.2 实现 `getPeriodLabel(type)` 方法(获取周期标签:本月/本年)
|
|||
|
|
- [x] 22.3 实现 `getProgressColor(budget)` 方法(计算进度条颜色)
|
|||
|
|
- [x] 22.4 实现 `isArchiveMonth(date)` 方法(判断是否为历史月份)
|
|||
|
|
|
|||
|
|
## 23. 测试和调试
|
|||
|
|
|
|||
|
|
- [x] 23.1 测试页面初始加载(默认当前月、支出 tab)
|
|||
|
|
- [x] 23.2 测试月份切换(左右箭头、滑动手势)
|
|||
|
|
- [x] 23.3 测试支出/收入/计划 tab 切换
|
|||
|
|
- [x] 23.4 测试左右滑动手势切换月份
|
|||
|
|
- [x] 23.5 测试下拉刷新功能
|
|||
|
|
- [x] 23.6 测试日期选择器(选择历史月份、禁止未来月份)
|
|||
|
|
- [x] 23.7 测试未覆盖分类功能(警告图标、弹窗)
|
|||
|
|
- [x] 23.8 测试归档总结功能(历史月份)
|
|||
|
|
- [x] 23.9 测试存款计划的独立日期切换
|
|||
|
|
- [x] 23.10 测试预算新增、编辑、删除功能
|
|||
|
|
- [x] 23.11 测试储蓄配置功能
|
|||
|
|
- [x] 23.12 测试错误处理(API 失败、网络错误)
|
|||
|
|
- [x] 23.13 测试加载状态显示
|
|||
|
|
- [x] 23.14 测试 keep-alive 缓存和全局事件刷新
|
|||
|
|
- [x] 23.15 测试深色模式切换
|
|||
|
|
|
|||
|
|
## 24. 优化和完善
|
|||
|
|
|
|||
|
|
- [x] 24.1 检查并优化数据加载性能(使用 `Promise.allSettled` 并发加载)
|
|||
|
|
- [x] 24.2 添加必要的加载动画和过渡效果
|
|||
|
|
- [x] 24.3 添加代码注释(业务逻辑复杂的部分)
|
|||
|
|
- [x] 24.4 检查并修复 ESLint 警告
|
|||
|
|
- [x] 24.5 验证所有 API 调用的错误处理
|
|||
|
|
- [x] 24.6 验证移动端适配(安全距离、触摸手势)
|
|||
|
|
|
|||
|
|
## 25. 文档和发布
|
|||
|
|
|
|||
|
|
- [x] 25.1 更新 README.md(如果需要)
|
|||
|
|
- [ ] 25.2 创建 PR 并填写详细的变更说明
|
|||
|
|
- [ ] 25.3 在 PR 中添加测试截图或录屏
|
|||
|
|
- [ ] 25.4 请求代码审查
|
|||
|
|
- [ ] 25.5 合并 PR 并部署到测试环境
|
|||
|
|
- [ ] 25.6 收集用户反馈并快速迭代
|