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