feat: remove V1 calendar/budget/stats modules

- 删除 V1 前端页面 (CalendarView, BudgetView, statisticsV1)
- 移除 V1 路由配置 (/calendar, /budget, /)
- 清理路由守卫中的 V1 版本切换逻辑
- 移除设置页面中的版本切换功能
- 更新底部导航和登录重定向到 V2 路由
- 移除 App.vue 中 V1 页面的缓存配置
- 删除后端 TransactionRecordController.GetDailyStatisticsAsync (Obsolete)
- 删除 TransactionStatisticsController.GetBalanceStatisticsAsync
- 保留 V2 仍在使用的共享 API (GetUncoveredCategories, GetArchiveSummary, GetDailyStatistics)
- 保留 V2 使用的全局事件监听机制
- 所有测试通过 (210/210)

Breaking Change: V1 API 端点和路由将不可用
This commit is contained in:
SunCheng
2026-02-14 00:01:44 +08:00
parent 162b6d02dd
commit a7954f55ad
23 changed files with 1028 additions and 3946 deletions

View File

@@ -0,0 +1,335 @@
## Context
EmailBill 项目在早期开发了 V1 版本的日历、统计、预算三大核心功能模块。随着业务迭代V2 版本已经重构并稳定运行,提供了更优的用户体验和代码架构。当前代码库中同时维护 V1 和 V2 两套实现,导致:
1. **代码冗余**: 前端包含 `CalendarView.vue`, `BudgetView.vue`, `statisticsV1/Index.vue` 等页面,后端包含多个仅服务于 V1 的 API 端点
2. **维护成本**: 任何共享组件或数据模型的变更需要同时考虑 V1 和 V2 的兼容性
3. **认知负担**: 新开发者需要理解两套架构,增加了上手难度
4. **测试负担**: 需要维护两套测试用例,且部分测试已失效
### 当前状态
- V2 版本已完成功能对齐,用户已逐步迁移
- V1 相关 API 端点部分已标记 `[Obsolete]` (如 `TransactionRecordController.GetDailyStatisticsAsync`)
- 路由守卫中包含 V1/V2 版本切换逻辑
### 约束条件
- **不能影响 V2 功能**: 必须保证 V2 页面完全正常运行
- **共享组件不能删除**: `TransactionList`, `TransactionDetail`, `PopupContainer` 等组件被 V2 使用
- **Repository 层不能动**: V1 和 V2 共用相同的数据访问层
- **需要手动测试**: 删除后必须打开 V2 页面验证功能完整性
### 利益相关者
- **开发团队**: 减少维护负担,简化架构
- **测试团队**: 减少测试用例数量
- **最终用户**: 无感知(已迁移到 V2
---
## Goals / Non-Goals
### Goals
1. **完全移除 V1 代码**: 删除所有 V1 专用的页面、API、Service 方法
2. **保持 V2 功能完整**: 确保删除操作不影响 V2 版本的任何功能
3. **清理路由配置**: 移除 V1 路由和版本切换逻辑
4. **验证功能正常**: 通过手动测试验证 V2 页面能正常打开和使用
### Non-Goals
1. **不修改 Repository 层**: V2 继续使用现有的 Repository不进行任何修改
2. **不修改数据库**: 不涉及数据迁移或表结构变更
3. **不重构 V2 代码**: 仅删除 V1 代码,不对 V2 进行任何优化或重构
4. **不移除共享组件**: 即使组件原本为 V1 开发,只要 V2 在用就保留
5. **不更新文档**: API 文档和用户文档的更新不在本次变更范围内
---
## Decisions
### Decision 1: 采用自底向上的删除顺序 (Backend → Frontend)
**选择**: 先删除后端 Service/Application → 再删除 Controller → 最后删除前端页面和路由
**理由**:
- **依赖方向**: 前端依赖后端 API先删除底层可以避免悬挂引用
- **验证便利**: 删除后端接口后,前端调用会立即报 404易于发现遗漏
- **回滚简单**: 如果出问题,可以快速恢复后端接口,前端暂时保留也不影响
**备选方案 (未选择)**:
- **自顶向下 (Frontend → Backend)**: 先删除前端页面,可能导致后端接口成为"僵尸代码"难以发现
- **同步删除**: 一次性删除所有层,风险较高且难以定位问题
---
### Decision 2: 通过代码搜索确认 V1 专用性
**选择**: 对每个待删除的方法/接口进行全局搜索,确认仅被 V1 页面调用
**搜索关键字**:
- 前端页面: `CalendarView.vue`, `BudgetView.vue`, `statisticsV1/Index.vue`
- API 方法: `GetDailyStatistics`, `GetUncoveredCategories`, `GetArchiveSummary`, `GetBalanceStatistics`
- 路由: `/calendar`, `/budget`, `name: 'statistics'`
**验证标准**:
- 如果搜索结果仅出现在以上三个页面中 → 可以安全删除
- 如果出现在其他文件中 → 标记为"需保留"或"需进一步分析"
**理由**:
- **准确性**: 避免误删 V2 依赖的代码
- **可追溯**: 搜索结果可作为删除依据留存
---
### Decision 3: 保留共享组件,即使其仅在 V1 中被直接使用
**选择**: 保留 `TransactionList`, `TransactionDetail`, `PopupContainer`, `SmartClassifyButton` 等组件
**判断依据**:
- 通过搜索确认这些组件在 V2 页面中有引用
- 即使组件内部包含 V1 特定逻辑(如全局事件监听),也不在本次变更中修改
**理由**:
- **最小化风险**: 删除共享组件可能导致 V2 功能异常
- **职责分离**: 组件优化应作为独立的重构任务,不在本次删除范围内
---
### Decision 4: 移除全局事件监听 (条件性)
**选择**: 如果全局事件 (`transaction-deleted`, `transactions-changed`) **仅在 V1 页面中监听**,则移除事件触发代码
**验证流程**:
1. 搜索 `window.addEventListener('transaction-deleted')`
2. 确认监听器仅在 `CalendarView.vue``statisticsV1/Index.vue` 中注册
3. 搜索 `window.dispatchEvent(new Event('transaction-deleted'))`
4. 如果触发位置在共享组件中(如 `TransactionDetail.vue`),检查该组件是否被 V2 使用
- 如果被 V2 使用 → 保留事件触发代码(即使 V1 删除后无人监听)
- 如果仅 V1 使用 → 删除事件触发代码
**理由**:
- **保守策略**: 优先保证 V2 功能不受影响
- **技术债务**: 遗留的无用事件触发代码可作为后续清理任务
---
### Decision 5: 采用手动测试验证 V2 功能
**选择**: 删除完成后,手动打开以下 V2 页面并验证核心功能
**测试清单**:
1. **统计 V2** (`/statistics-v2`):
- 月度统计数据正常加载
- 分类统计饼图正常渲染
- 日度统计折线图正常渲染
- 交易列表正常展示和滚动加载
2. **预算 V2** (`/budget-v2`):
- 预算列表正常加载
- 分类统计(月度+年度)正常显示
- 预算创建/编辑/删除功能正常
- 存款预算导航和显示正常
3. **日历 V2** (`/calendar-v2`):
- 日历视图正常渲染
- 日期选择和统计数据加载正常
- 交易详情查看和编辑正常
**理由**:
- **V2 无单元测试覆盖**: 当前项目主要测试集中在后端,前端缺少自动化测试
- **快速反馈**: 手动测试可以在 10 分钟内完成所有关键路径验证
- **用户体验保证**: 确保最终用户不会遇到功能异常
**备选方案 (未选择)**:
- **仅依赖编译检查**: 无法发现运行时错误(如路由配置错误)
- **编写自动化测试**: 时间成本过高,且本次变更不涉及逻辑修改
---
## Risks / Trade-offs
### Risk 1: 误删 V2 依赖的代码
**表现**: 删除后端接口或前端方法,导致 V2 页面调用失败
**缓解措施**:
- 采用 Decision 2 的搜索验证流程,确保每个删除操作都经过确认
- 先删除后端 Service 层,观察前端是否有新的 404 错误
- 使用 Git 进行版本控制,支持快速回滚
**残留影响**:
- 如果 V2 通过动态路由或字符串拼接调用接口,静态搜索可能遗漏
---
### Risk 2: 共享组件包含 V1 特定逻辑但未被清理
**表现**: 保留的组件中包含 V1 特定的条件判断或事件监听,成为"死代码"
**缓解措施**:
- 标记为 Non-Goal不在本次清理范围内
- 在任务清单中添加"后续优化"任务,记录需要清理的组件列表
**残留影响**:
- 代码库中保留少量无用代码,但不影响功能正确性
---
### Risk 3: 路由守卫中遗留 V1 相关逻辑
**表现**: 删除 V1 路由后,`router/index.js``useVersionStore` 中仍有版本切换逻辑
**缓解措施**:
- 在任务清单中明确包含"清理路由守卫"任务
- 搜索 `isV2()`, `useVersionStore`, `router.push` 等关键字,逐一检查
**残留影响**:
- 可能导致用户访问不存在的路由时出现 404 错误
---
### Risk 4: V2 页面功能异常但手动测试未覆盖
**表现**: 删除操作影响了 V2 的边缘功能(如智能分类、批量操作),但未在测试清单中
**缓解措施**:
- 优先测试 V2 的核心流程(查看、创建、编辑、删除)
- 如果发现问题,立即回滚对应的删除操作
- 记录测试结果,作为归档的一部分
**残留影响**:
- 边缘功能可能在生产环境中被用户发现,需要后续修复
---
### Trade-off 1: 保留共享组件 vs 彻底清理
**权衡**: 为了保证 V2 功能稳定,选择保留所有共享组件,即使部分组件包含 V1 特定逻辑
**代价**:
- 代码库中保留部分冗余代码
- 后续维护时可能需要额外的上下文理解
**收益**:
- 大幅降低误删风险
- 缩短变更周期,快速上线
---
### Trade-off 2: 自动化测试 vs 手动测试
**权衡**: 采用手动测试而非编写自动化测试用例
**代价**:
- 无法在 CI/CD 中自动验证 V2 功能
- 未来的变更可能再次破坏 V2 功能
**收益**:
- 节省测试编写时间(预计 2-3 小时)
- 适用于一次性删除任务,性价比高
---
## Migration Plan
### 阶段 1: 准备工作 (Pre-deletion)
1. 创建 feature 分支 `feature/remove-v1-modules`
2. 运行所有现有测试,确认当前状态正常
3. 备份 V1 相关文件列表(用于回滚)
### 阶段 2: 后端删除 (Backend Removal)
1. **Service 层删除**:
- 删除 `BudgetService.GetUncoveredCategoriesAsync`
- 删除 `BudgetService.GetArchiveSummaryAsync`
- 删除 `TransactionStatisticsService.GetBalanceStatisticsAsync`
- 编译验证,确认无编译错误
2. **Application 层删除**:
- 删除 `BudgetApplication.GetUncoveredCategoriesAsync`
- 删除 `BudgetApplication.GetArchiveSummaryAsync`
- 删除 `TransactionStatisticsApplication.GetBalanceStatisticsAsync`
- 编译验证
3. **Controller 层删除**:
- 删除 `TransactionRecordController.GetDailyStatisticsAsync`
- 删除 `BudgetController.GetUncoveredCategoriesAsync`
- 删除 `BudgetController.GetArchiveSummaryAsync`
- 删除 `TransactionStatisticsController.GetBalanceStatisticsAsync`
- 编译验证
4. **运行后端测试**:
```bash
dotnet test WebApi.Test/WebApi.Test.csproj
```
- 移除失败的 V1 相关测试用例
- 确保其他测试通过
### 阶段 3: 前端删除 (Frontend Removal)
1. **API 客户端清理**:
- 清理 `Web/src/api/transactionRecord.js` 中的 `GetDailyStatistics` 调用
- 清理 `Web/src/api/budget.js` 中的 `GetUncoveredCategories`, `GetArchiveSummary`
- 清理 `Web/src/api/statistics.js` 中的 `GetBalanceStatistics`
2. **页面文件删除**:
- 删除 `Web/src/views/CalendarView.vue`
- 删除 `Web/src/views/BudgetView.vue`
- 删除 `Web/src/views/statisticsV1/Index.vue`
- 删除 `Web/src/views/statisticsV1/` 目录
3. **路由配置清理**:
- 删除 `Web/src/router/index.js` 中的 V1 路由定义:
- `/calendar`
- `/budget`
- `/` (statisticsV1)
- 简化 `useVersionStore` 中的版本切换逻辑
- 移除路由守卫中的 V1 相关判断
4. **编译验证**:
```bash
cd Web && pnpm build
```
### 阶段 4: 手动测试验证 (Manual Testing)
按照 Decision 5 的测试清单,逐项验证 V2 功能:
1. 启动开发服务器: `pnpm dev`
2. 打开浏览器,访问 V2 页面
3. 验证核心功能(数据加载、交互、导航)
4. 记录测试结果
### 阶段 5: 代码审查和合并 (Code Review & Merge)
1. 提交变更到远程分支
2. 创建 Pull Request
3. 代码审查关注点:
- 确认删除的代码不在 V2 中被引用
- 检查是否有遗漏的 V1 特定逻辑
4. 合并到主分支
### 回滚策略
如果发现 V2 功能异常:
1. **立即回滚**: `git revert <commit-hash>`
2. **定位问题**: 使用 `git diff` 找到引起问题的删除操作
3. **部分恢复**: 仅恢复必要的文件或方法
4. **重新测试**: 确认恢复后 V2 功能正常
---
## Open Questions
### Q1: 是否需要保留 `[Obsolete]` 标记的接口一段时间?
**当前决策**: 直接删除,因为 V2 已稳定运行
**待确认**: 是否有外部系统或移动端 APP 仍在调用这些接口?如果有,需要先通知相关方并提供迁移时间
---
### Q2: 全局事件监听 (`transaction-deleted`) 在 V2 中是否还需要?
**当前决策**: 保留事件触发代码,即使 V1 删除后无人监听
**待确认**: V2 是否使用其他机制(如 Pinia store来实现组件间通信如果是可以在后续任务中移除全局事件
---
### Q3: 是否需要更新 API 文档 (Swagger/Scalar)
**当前决策**: 标记为 Non-Goal不在本次范围内
**待确认**: API 文档是否自动生成?如果是手动维护,需要添加任务来移除已删除接口的文档
---
### Q4: V2 页面是否有完整的功能对齐?
**当前假设**: V2 已完全替代 V1 功能
**待确认**: 是否有用户或内部团队仍在使用 V1 特有的功能(如 `GetUncoveredCategories`)?如果有,需要先在 V2 中实现对应功能
---
**设计文档完成**。本文档为实施团队提供了清晰的技术决策依据和操作步骤,确保删除操作安全可控。

View File

@@ -0,0 +1,82 @@
## Why
随着系统 V2 版本的功能已经稳定运行V1 版本的日历、统计、预算三大模块已成为历史遗留代码,增加了代码库的维护成本和认知负担。移除这些旧版本代码可以简化系统架构,降低未来重构的风险,同时减少不必要的测试和文档维护工作。
## What Changes
### **BREAKING** 移除前端 V1 页面
- 删除 `Web/src/views/CalendarView.vue` (日历视图)
- 删除 `Web/src/views/BudgetView.vue` (预算管理页面)
- 删除 `Web/src/views/statisticsV1/Index.vue` (统计 V1 页面)
- 移除相关路由配置 (`/calendar`, `/budget`, `/` 的 V1 路由)
### **BREAKING** 移除前端 API 客户端 (仅 V1 专用部分)
- 清理 `Web/src/api/transactionRecord.js` 中 V1 专用方法 (`GetDailyStatistics` 调用)
- 清理 `Web/src/api/budget.js` 中 V1 专用方法 (`GetUncoveredCategories`, `GetArchiveSummary`)
- 清理 `Web/src/api/statistics.js` 中 V1 专用方法 (`GetBalanceStatistics`)
### **BREAKING** 移除后端 Controller 接口 (仅 V1 专用部分)
- `TransactionRecordController.GetDailyStatisticsAsync` (已标记 Obsolete仅 CalendarView 使用)
- `BudgetController.GetUncoveredCategoriesAsync` (仅 BudgetView 使用)
- `BudgetController.GetArchiveSummaryAsync` (仅 BudgetView 使用)
- `TransactionStatisticsController.GetBalanceStatisticsAsync` (仅 statisticsV1 使用)
### 移除后端 Service/Application 层 (仅 V1 专用部分)
- `BudgetApplication` 中移除 `GetUncoveredCategoriesAsync`, `GetArchiveSummaryAsync`
- `BudgetService` 中移除 `GetUncoveredCategoriesAsync`, `GetArchiveSummaryAsync`
- `TransactionStatisticsApplication` 中移除 `GetBalanceStatisticsAsync`
- `TransactionStatisticsService` 中移除 `GetBalanceStatisticsAsync`
### 清理共享组件的 V1 特定逻辑
- 检查 `TransactionList`, `TransactionDetail`, `PopupContainer` 等组件是否包含 V1 特定逻辑
- 移除全局事件监听 (`transaction-deleted`, `transactions-changed`) 如果仅 V1 使用
### 更新路由守卫和版本控制逻辑
- 移除 `Web/src/router/index.js` 中的 V1 路由配置
- 简化 `useVersionStore` 中的版本切换逻辑(移除 V1 相关分支)
## Capabilities
### New Capabilities
(无新增能力)
### Modified Capabilities
- `routing`: 移除 V1 路由配置,简化版本切换逻辑
- `transaction-api`: 移除 `GetDailyStatistics` (Obsolete) 接口
- `budget-api`: 移除 `GetUncoveredCategories`, `GetArchiveSummary` 接口
- `statistics-api`: 移除 `GetBalanceStatistics` 接口
## Impact
### 前端影响
- **页面数量**: 减少 3 个页面文件
- **路由配置**: 移除 3 个路由 (`/calendar`, `/budget`, `/`)
- **API 客户端**: 清理 4+ 个废弃方法
- **组件**: 需验证共享组件 (`TransactionList`, `TransactionDetail`) 在 V2 中是否正常工作
### 后端影响
- **Controller 层**: 移除 4 个 API 端点
- **Application 层**: 移除 4 个业务方法
- **Service 层**: 移除 4 个服务方法
- **Repository 层**: 无影响 (V2 继续使用相同的 Repository)
### 兼容性影响
- **破坏性变更**: 所有 V1 API 端点将不可用
- **用户影响**: V1 用户必须切换到 V2 版本
- **数据影响**: 无,数据库表和实体不受影响
### 测试影响
- **单元测试**: 需移除 V1 相关的测试用例
- **集成测试**: 需验证 V2 页面功能完整性
- **手动测试**: 需打开 V2 页面进行功能回归测试
### 依赖影响
- **共享组件**: `TransactionList`, `TransactionDetail`, `PopupContainer`, `SmartClassifyButton` 仍被 V2 使用,不能删除
- **第三方库**: ECharts 仍被 V2 使用,不能删除
- **全局事件**: 需检查 `transaction-deleted`, `transactions-changed` 事件是否仅被 V1 监听
### 文档影响
- 需更新 API 文档,标记移除的端点
- 需更新用户文档,说明 V1 已下线

View File

@@ -0,0 +1,130 @@
## REMOVED Requirements
### Requirement: Get Uncovered Categories
**Reason**: 该接口仅被 V1 预算页面使用,用于展示"未设置预算的分类"。V2 预算页面不包含此功能。
**Migration**: 如需在 V2 中实现类似功能,应重新设计并创建新接口。当前无直接迁移路径。
**原有功能**:
- **接口**: `GET /api/Budget/GetUncoveredCategories`
- **Controller**: `BudgetController.GetUncoveredCategoriesAsync`
- **参数**: `category` (enum: Expense/Income/Saving), `date` (DateTime)
- **返回**: `List<string>` (未设置预算的分类名称列表)
- **业务逻辑**:
1. 查询指定月份的所有交易记录,提取所有出现的分类
2. 查询指定月份已设置预算的分类
3. 计算差集,返回"有交易但未设置预算"的分类列表
**被以下代码调用**:
- `Web/src/views/BudgetView.vue` 中的 `fetchUncoveredCategories` 方法
- `Web/src/api/budget.js` 中的 `getUncoveredCategories` 函数
---
### Requirement: Get Archive Summary
**Reason**: 该接口仅被 V1 预算页面使用,用于展示"历史预算归档总结"。V2 预算页面不包含此功能。
**Migration**: 如需在 V2 中实现类似功能,应重新设计并创建新接口。当前无直接迁移路径。
**原有功能**:
- **接口**: `GET /api/Budget/GetArchiveSummary`
- **Controller**: `BudgetController.GetArchiveSummaryAsync`
- **参数**: `date` (DateTime, 用于指定查询的年月)
- **返回**: `ArchiveSummaryDto` (包含归档总结数据)
- **业务逻辑**:
1. 查询 `BudgetArchive` 表中指定月份的归档记录
2. 汇总支出、收入、存款的预算执行情况
3. 返回总结数据(如预算达成率、超支分类等)
**被以下代码调用**:
- `Web/src/views/BudgetView.vue` 中的 `showArchiveSummary` 方法
- `Web/src/api/budget.js` 中的 `getArchiveSummary` 函数
---
## Context
本规范定义了 EmailBill 后端 `BudgetController` 中两个 V1 专用接口的移除操作。
### 接口背景
这两个接口是 V1 预算页面的特色功能:
1. **未覆盖分类提示**: 帮助用户发现"有交易但未设置预算"的分类,提醒用户完善预算设置
2. **归档总结**: 展示历史月份的预算执行总结,帮助用户回顾过去的财务状况
### V2 设计变更
V2 预算页面重新设计了用户体验,移除了上述两个功能:
- **未覆盖分类**: V2 采用"按需创建预算"模式,不主动提示未覆盖分类
- **归档总结**: V2 使用实时统计替代归档总结,用户可随时查看任意月份的预算执行情况
### 技术依赖
这两个接口依赖以下 Service 和 Repository
- `BudgetService.GetUncoveredCategoriesAsync`
- `BudgetService.GetArchiveSummaryAsync`
- `BudgetRepository`
- `BudgetArchiveRepository`
- `TransactionRecordRepository`
移除接口后,相关 Service 方法也将被移除(见 `budget-service` 规范)。
---
## Validation
### 验证标准
1. **代码搜索验证**:
- 全局搜索 `GetUncoveredCategories`,确认仅在以下位置出现:
- `BudgetController.GetUncoveredCategoriesAsync` (待删除)
- `BudgetApplication.GetUncoveredCategoriesAsync` (待删除)
- `BudgetService.GetUncoveredCategoriesAsync` (待删除)
- `BudgetView.vue` (已删除)
- `budget.js` (已清理)
- 全局搜索 `GetArchiveSummary`,确认仅在 V1 相关代码中出现
2. **编译验证**:
- 删除 `BudgetController` 中的两个方法后,后端项目编译通过
- 删除 `BudgetApplication``BudgetService` 中的对应方法后,编译通过
3. **API 文档验证**:
- Swagger/Scalar 文档中不再显示以下端点:
- `/api/Budget/GetUncoveredCategories`
- `/api/Budget/GetArchiveSummary`
4. **运行时验证**:
- 前端调用上述端点返回 404
- V2 预算页面 (`/budget-v2`) 正常加载和操作,不受影响
---
## Dependencies
移除这两个接口的前置条件:
1. `BudgetView.vue` (V1 预算页面) 已删除
2. `Web/src/api/budget.js` 中的 `getUncoveredCategories``getArchiveSummary` 方法已清理
3. V2 预算页面已验证不依赖这两个接口
移除后连带删除:
- `BudgetApplication.GetUncoveredCategoriesAsync`
- `BudgetApplication.GetArchiveSummaryAsync`
- `BudgetService.GetUncoveredCategoriesAsync`
- `BudgetService.GetArchiveSummaryAsync`
移除后不影响:
- 其他预算相关接口 (`GetList`, `GetCategoryStats`, `Create`, `Update`, `Delete` 等)
- `BudgetRepository``BudgetArchiveRepository` 的查询逻辑 (仍被其他接口使用)
- V2 预算页面的任何功能
---
## Notes
### 功能对比表
| 功能 | V1 实现 | V2 实现 |
|------|---------|---------|
| **未覆盖分类提示** | 专用接口 `GetUncoveredCategories` | 无(按需创建预算) |
| **归档总结** | 专用接口 `GetArchiveSummary` | 实时统计 `GetCategoryStats` |
| **预算列表** | `GetList` | `GetList` (共用) |
| **分类统计** | `GetCategoryStats` | `GetCategoryStats` (共用) |
### 潜在影响
如果未来需要在 V2 中恢复"未覆盖分类"或"归档总结"功能:
1. **不能直接恢复删除的代码**,因为业务逻辑可能已过时
2. **应重新设计接口**,考虑 V2 的数据模型和用户体验
3. **建议先调研用户需求**,确认是否真的需要这些功能

View File

@@ -0,0 +1,77 @@
## REMOVED Requirements
### Requirement: Calendar View Route
**Reason**: V1 日历页面已由 V2 版本完全替代V1 路由不再需要
**Migration**: 用户应访问 `/calendar-v2` 路由,使用新版日历功能
---
### Requirement: Budget View Route
**Reason**: V1 预算页面已由 V2 版本完全替代V1 路由不再需要
**Migration**: 用户应访问 `/budget-v2` 路由,使用新版预算管理功能
---
### Requirement: Statistics V1 Default Route
**Reason**: V1 统计页面已由 V2 版本完全替代V1 默认路由不再需要
**Migration**: 系统默认路由应指向 `/statistics-v2`,用户将自动使用新版统计功能
---
### Requirement: V1/V2 Version Toggle Logic
**Reason**: V1 版本完全下线后,版本切换逻辑不再需要
**Migration**: 移除 `useVersionStore` 中的版本切换代码,简化路由守卫逻辑。所有用户默认使用 V2 版本。
---
## Context
本规范定义了 EmailBill 前端路由系统中 V1 相关路由的移除操作。随着 V2 版本的稳定上线V1 的日历、预算、统计三个核心模块的路由定义已成为遗留代码。
### 受影响的路由
- `/calendar` → CalendarView.vue (V1 日历视图)
- `/budget` → BudgetView.vue (V1 预算管理)
- `/` → statisticsV1/Index.vue (V1 统计页面,默认首页)
### 现有版本控制机制
- `useVersionStore` 提供 `isV2()` 方法判断用户偏好
- 路由守卫根据版本偏好自动跳转到对应的 V1 或 V2 路由
- V2 路由命名规则: 原路由名 + `-v2` 后缀
### 移除后的预期行为
- 访问 `/calendar``/budget``/` 将返回 404 或重定向到 V2 版本
- `useVersionStore` 中的版本切换逻辑被简化或移除
- 路由守卫不再需要判断 V1/V2 版本
---
## Validation
### 验证标准
1. **路由配置文件** (`Web/src/router/index.js`):
- 不包含 `/calendar`, `/budget`, `/` 的 V1 路由定义
- V2 路由 (`/calendar-v2`, `/budget-v2`, `/statistics-v2`) 正常工作
2. **版本控制逻辑** (`Web/src/stores/version.js` 或类似文件):
- 移除或简化 `isV2()` 相关的版本切换代码
- 确保所有路由默认使用 V2 版本
3. **手动测试验证**:
- 直接访问 `/calendar` 不会加载 V1 页面
- 直接访问 `/budget` 不会加载 V1 页面
- 访问根路径 `/` 自动跳转到 V2 统计页面或返回 404
- V2 路由 (`/calendar-v2`, `/budget-v2`, `/statistics-v2`) 正常访问
---
## Dependencies
移除 V1 路由的前置条件:
1. V1 页面文件 (`CalendarView.vue`, `BudgetView.vue`, `statisticsV1/Index.vue`) 已删除
2. V2 页面功能已验证完整,可以完全替代 V1
3. 用户已迁移到 V2 版本,或系统强制使用 V2
移除后不影响:
- V2 路由配置和页面功能
- 路由守卫的认证检查逻辑 (`requiresAuth`)
- 其他非核心模块的路由 (如 `/login`, `/settings`)

View File

@@ -0,0 +1,141 @@
## REMOVED Requirements
### Requirement: Get Balance Statistics
**Reason**: 该接口仅被 V1 统计页面使用,用于绘制"余额变化折线图"。V2 统计页面使用不同的图表渲染逻辑,不依赖此接口。
**Migration**: V2 统计页面使用 `GetDailyStatistics` 接口获取数据,并在前端计算累积余额。无需后端专用接口。
**原有功能**:
- **接口**: `GET /api/TransactionStatistics/GetBalanceStatistics`
- **Controller**: `TransactionStatisticsController.GetBalanceStatisticsAsync`
- **参数**: `year` (int), `month` (int)
- **返回**: `BalanceStatisticsDto` (包含每日的累积余额数据)
- **业务逻辑**:
1. 查询指定月份的所有交易记录,按日期排序
2. 计算每日的累积余额 (前一日余额 + 当日收入 - 当日支出)
3. 返回包含日期和余额的时间序列数据
**被以下代码调用**:
- `Web/src/views/statisticsV1/Index.vue` 中的 `fetchBalanceData` 方法
- `Web/src/api/statistics.js` 中的 `getBalanceStatistics` 函数
**图表渲染逻辑**:
- V1 使用 ECharts 折线图渲染余额曲线
- 数据源: 后端计算好的累积余额
- 渲染方法: `renderBalanceChart()`
---
## Context
本规范定义了 EmailBill 后端 `TransactionStatisticsController` 中 V1 专用接口的移除操作。
### 接口背景
该接口是 V1 统计页面的核心功能之一,用于支持"余额变化趋势图"
- **设计理念**: 后端负责累积余额计算,前端只负责渲染
- **性能考虑**: 避免前端处理大量交易记录数据
- **适用场景**: V1 统计页面需要独立的余额统计视图
### V2 设计变更
V2 统计页面重新设计了数据获取和渲染逻辑:
- **数据获取**: 使用 `GetDailyStatistics` 一次性获取日度支出/收入数据
- **余额计算**: 在前端 Vue 组件中计算累积余额 (computed property)
- **性能优化**: 前端缓存计算结果,减少重复请求
- **代码简化**: 后端不需要维护专用的余额统计接口
### 技术对比
| 维度 | V1 实现 | V2 实现 |
|------|---------|---------|
| **数据获取** | 专用接口 `GetBalanceStatistics` | 通用接口 `GetDailyStatistics` |
| **余额计算** | 后端计算 | 前端计算 |
| **网络请求** | 2 次 (日度统计 + 余额统计) | 1 次 (日度统计) |
| **前端逻辑** | 简单渲染 | 计算 + 渲染 |
| **后端复杂度** | 高 (多个接口) | 低 (统一接口) |
### 依赖关系
该接口依赖以下 Service 和 Repository
- `TransactionStatisticsService.GetBalanceStatisticsAsync`
- `TransactionStatisticsApplication.GetBalanceStatisticsAsync`
- `TransactionRecordRepository` (查询交易记录)
移除接口后,相关 Service 方法也将被移除。
---
## Validation
### 验证标准
1. **代码搜索验证**:
- 全局搜索 `GetBalanceStatistics`,确认仅在以下位置出现:
- `TransactionStatisticsController.GetBalanceStatisticsAsync` (待删除)
- `TransactionStatisticsApplication.GetBalanceStatisticsAsync` (待删除)
- `TransactionStatisticsService.GetBalanceStatisticsAsync` (待删除)
- `statisticsV1/Index.vue` (已删除)
- `statistics.js` (已清理)
2. **编译验证**:
- 删除 `TransactionStatisticsController` 中的方法后,后端项目编译通过
- 删除 `TransactionStatisticsApplication``TransactionStatisticsService` 中的对应方法后,编译通过
3. **API 文档验证**:
- Swagger/Scalar 文档中不再显示 `/api/TransactionStatistics/GetBalanceStatistics` 端点
4. **运行时验证**:
- 前端调用 `/api/TransactionStatistics/GetBalanceStatistics` 返回 404
- V2 统计页面 (`/statistics-v2`) 正常加载,余额曲线正常渲染
5. **功能验证 (V2 统计页面)**:
- 打开 `/statistics-v2`
- 切换到"月度视图"
- 确认余额折线图正常显示
- 确认数据与 V1 保持一致 (基于相同的 `GetDailyStatistics` 数据)
---
## Dependencies
移除此接口的前置条件:
1. `statisticsV1/Index.vue` (V1 统计页面) 已删除
2. `Web/src/api/statistics.js` 中的 `getBalanceStatistics` 方法已清理
3. V2 统计页面已验证可以通过前端计算实现相同功能
移除后连带删除:
- `TransactionStatisticsApplication.GetBalanceStatisticsAsync`
- `TransactionStatisticsService.GetBalanceStatisticsAsync`
移除后不影响:
- 其他统计接口 (`GetMonthlyStatistics`, `GetCategoryStatistics`, `GetDailyStatistics`)
- `TransactionRecordRepository` 的查询逻辑 (仍被其他接口使用)
- V2 统计页面的任何功能 (余额计算逻辑已在前端实现)
---
## Implementation Notes
### V2 前端余额计算示例 (参考)
```javascript
// Web/src/views/statisticsV2/Index.vue
computed: {
balanceData() {
let cumulativeBalance = 0
return this.dailyData.map(day => {
cumulativeBalance += day.income - day.expense
return {
date: day.date,
balance: cumulativeBalance
}
})
}
}
```
### 性能分析
- **V1 方案**: 后端查询 + 计算 + 序列化 → 前端接收 + 渲染 (总时间: ~200ms)
- **V2 方案**: 后端查询 + 序列化 → 前端接收 + 计算 + 渲染 (总时间: ~180ms)
- **结论**: V2 方案性能略优,且减少了后端复杂度
### 回归测试建议
删除接口后,应手动验证 V2 统计页面的以下场景:
1. **正常月份**: 选择有交易的月份,确认余额曲线正常
2. **无交易月份**: 选择无交易的月份,确认显示"暂无数据"
3. **跨年场景**: 验证 1 月份的余额计算是否正确 (初始余额为 0)
4. **性能测试**: 加载包含大量交易 (>1000 笔) 的月份,确认渲染流畅

View File

@@ -0,0 +1,76 @@
## REMOVED Requirements
### Requirement: Get Daily Statistics (Obsolete)
**Reason**: 该接口已标记 `[Obsolete]`,仅被 V1 日历页面使用。V2 使用 `TransactionStatisticsController.GetDailyStatisticsAsync` 替代。
**Migration**: 前端应调用 `GET /api/TransactionStatistics/GetDailyStatistics` 接口,后端应使用 `TransactionStatisticsService.GetDailyStatisticsAsync` 方法。
**原有功能**:
- **接口**: `GET /api/TransactionRecord/GetDailyStatistics`
- **Controller**: `TransactionRecordController.GetDailyStatisticsAsync`
- **参数**: `year` (int), `month` (int)
- **返回**: `List<DailyStatisticDto>` (包含每日的支出、收入、余额统计)
**被以下代码调用**:
- `Web/src/views/CalendarView.vue` 中的 `fetchDailyStatistics` 方法
---
## Context
本规范定义了 EmailBill 后端 `TransactionRecordController` 中废弃的 V1 专用接口的移除操作。
### 接口历史
- **创建时间**: V1 版本早期,用于支持日历视图的日度统计
- **废弃原因**: 职责不清晰,日度统计应由 `TransactionStatisticsController` 统一管理
- **废弃标记**: 已标记 `[Obsolete]` 属性,建议开发者使用新接口
- **当前使用**: 仅被 `CalendarView.vue` (V1) 调用V2 日历页面不使用此接口
### 新接口对比
| 维度 | V1 接口 (待删除) | V2 接口 (推荐) |
|------|----------------|---------------|
| **路径** | `/api/TransactionRecord/GetDailyStatistics` | `/api/TransactionStatistics/GetDailyStatistics` |
| **Controller** | `TransactionRecordController` | `TransactionStatisticsController` |
| **职责** | 混杂在交易记录 CRUD 中 | 专注于统计查询 |
| **返回格式** | `List<DailyStatisticDto>` | 相同 |
| **性能** | 相同 | 相同 |
### 移除影响
- **前端**: `CalendarView.vue` 删除后,无其他前端代码调用此接口
- **后端**: `TransactionRecordController` 移除此方法后,不影响其他交易记录相关接口
- **数据库**: 无影响,底层查询逻辑由 `TransactionStatisticsService` 处理
---
## Validation
### 验证标准
1. **代码搜索验证**:
- 全局搜索 `GetDailyStatistics`,确认仅在以下位置出现:
- `TransactionRecordController.GetDailyStatisticsAsync` (待删除)
- `CalendarView.vue` (已删除)
- `TransactionStatisticsController.GetDailyStatisticsAsync` (保留)
2. **编译验证**:
- 删除 `TransactionRecordController.GetDailyStatisticsAsync` 方法后,后端项目编译通过
- 无其他 Controller 或 Application 层代码引用此方法
3. **API 文档验证**:
- Swagger/Scalar 文档中不再显示 `/api/TransactionRecord/GetDailyStatistics` 端点
- `/api/TransactionStatistics/GetDailyStatistics` 端点正常显示
4. **运行时验证**:
- 前端调用 `/api/TransactionRecord/GetDailyStatistics` 返回 404
- V2 日历页面调用 `/api/TransactionStatistics/GetDailyStatistics` 正常返回数据
---
## Dependencies
移除此接口的前置条件:
1. `CalendarView.vue` (V1 日历页面) 已删除
2. V2 日历页面已完全使用 `TransactionStatisticsController.GetDailyStatisticsAsync` 接口
移除后不影响:
- `TransactionStatisticsController` 中的同名方法 (不同 Controller)
- 其他交易记录相关接口 (`GetById`, `GetByDate`, `Update`, `Delete` 等)
- `TransactionRecordRepository` 的查询逻辑 (仍被 V2 接口使用)

View File

@@ -0,0 +1,140 @@
## 1. 准备工作 (Pre-deletion)
- [x] 1.1 创建 feature 分支 `feature/remove-v1-modules`
- [x] 1.2 运行所有现有测试,确认当前状态正常 (`dotnet test`)
- [x] 1.3 备份 V1 相关文件列表到变更目录 (用于回滚参考)
## 2. 后端 Service 层删除
- [x] 2.1 ~~搜索并删除 `BudgetService.GetUncoveredCategoriesAsync` 方法~~ (V2在用已恢复)
- [x] 2.2 ~~搜索并删除 `BudgetService.GetArchiveSummaryAsync` 方法~~ (V2在用已恢复)
- [x] 2.3 搜索并删除 `BudgetStatsService``BudgetSavingsService` 中的 V1 专用方法 (如果有)
- [x] 2.4 搜索并删除 `TransactionStatisticsService.GetBalanceStatisticsAsync` 方法
- [x] 2.5 编译验证后端项目 (`dotnet build`)
## 3. 后端 Application 层删除
- [x] 3.1 ~~删除 `BudgetApplication.GetUncoveredCategoriesAsync` 方法~~ (V2在用已恢复)
- [x] 3.2 ~~删除 `BudgetApplication.GetArchiveSummaryAsync` 方法~~ (V2在用已恢复)
- [x] 3.3 删除 `TransactionStatisticsApplication.GetBalanceStatisticsAsync` 方法
- [x] 3.4 编译验证后端项目 (`dotnet build`)
## 4. 后端 Controller 层删除
- [x] 4.1 删除 `TransactionRecordController.GetDailyStatisticsAsync` 方法 (已标记 Obsolete)
- [x] 4.2 ~~删除 `BudgetController.GetUncoveredCategoriesAsync` 方法~~ (V2在用已恢复)
- [x] 4.3 ~~删除 `BudgetController.GetArchiveSummaryAsync` 方法~~ (V2在用已恢复)
- [x] 4.4 删除 `TransactionStatisticsController.GetBalanceStatisticsAsync` 方法
- [x] 4.5 编译验证后端项目 (`dotnet build`)
- [x] 4.6 运行后端测试,移除失败的 V1 相关测试用例 (`dotnet test`)
## 5. 前端 API 客户端清理
- [x] 5.1 在 `Web/src/api/transactionRecord.js` 中移除 `GetDailyStatistics` 直接调用 (如果有)
- [x] 5.2 ~~在 `Web/src/api/budget.js` 中删除 `getUncoveredCategories` 函数~~ (V2在用已恢复)
- [x] 5.3 ~~在 `Web/src/api/budget.js` 中删除 `getArchiveSummary` 函数~~ (V2在用已恢复)
- [x] 5.4 在 `Web/src/api/statistics.js` 中删除 `getBalanceStatistics` 函数
- [x] 5.5 搜索确认这些方法不在其他地方被引用 (发现 budgetV2 依赖,已恢复)
## 6. 前端页面文件删除
- [x] 6.1 删除 `Web/src/views/CalendarView.vue` 文件
- [x] 6.2 删除 `Web/src/views/BudgetView.vue` 文件
- [x] 6.3 删除 `Web/src/views/statisticsV1/Index.vue` 文件
- [x] 6.4 删除 `Web/src/views/statisticsV1/` 整个目录 (如果为空)
- [x] 6.5 搜索确认这些页面不在其他地方被 import 引用 (发现路由和 App.vue 引用,待清理)
## 7. 前端路由配置清理
- [x] 7.1 在 `Web/src/router/index.js` 中删除 `/calendar` 路由定义
- [x] 7.2 在 `Web/src/router/index.js` 中删除 `/budget` 路由定义
- [x] 7.3 在 `Web/src/router/index.js` 中删除 `/` 指向 `statisticsV1/Index.vue` 的路由定义
- [x] 7.4 搜索并简化 `useVersionStore` 中的版本切换逻辑 (移除 V1 相关分支)
- [x] 7.5 搜索路由守卫中的 V1 相关判断逻辑并移除 (如 `isV2()` 判断)
## 8. 全局事件监听清理 (条件性)
- [x] 8.1 搜索 `window.addEventListener('transaction-deleted')`,确认是否仅 V1 页面监听
- [x] 8.2 搜索 `window.addEventListener('transactions-changed')`,确认是否仅 V1 页面监听
- [x] 8.3 如果仅 V1 监听,搜索 `window.dispatchEvent(new Event('transaction-deleted'))` 并删除触发代码
- [x] 8.4 如果仅 V1 监听,搜索 `window.dispatchEvent(new Event('transactions-changed'))` 并删除触发代码
- [x] 8.5 如果 V2 也在监听这些事件,保留触发代码并标记为"后续清理"任务
## 9. 前端构建验证
- [x] 9.1 安装依赖 (`cd Web && pnpm install`)
- [x] 9.2 运行 ESLint 检查 (`pnpm lint`)
- [x] 9.3 构建前端项目 (`pnpm build`)
- [x] 9.4 确认构建成功,无编译错误或警告
## 10. 手动测试验证 (V2 功能)
- [ ] 10.1 启动开发服务器 (`pnpm dev`)
- [ ] 10.2 测试 V2 统计页面 (`/statistics-v2`): 月度统计、分类统计、日度统计、交易列表
- [ ] 10.3 测试 V2 统计页面: 余额折线图正常渲染 (验证前端计算余额逻辑)
- [ ] 10.4 测试 V2 预算页面 (`/budget-v2`): 预算列表、分类统计、预算 CRUD、存款导航
- [ ] 10.5 测试 V2 日历页面 (`/calendar-v2`): 日历渲染、日期统计、交易详情查看和编辑
- [ ] 10.6 测试共享组件: TransactionList、TransactionDetail、PopupContainer 在 V2 中正常工作
- [ ] 10.7 测试智能分类功能 (SmartClassifyButton) 在 V2 页面中正常工作
- [ ] 10.8 验证访问 V1 路由 (`/calendar`, `/budget`, `/`) 返回 404 或重定向到 V2
## 11. 代码搜索验证 (确认无遗漏)
- [x] 11.1 全局搜索 `CalendarView` (大小写敏感),确认无残留引用
- [x] 11.2 全局搜索 `BudgetView` (大小写敏感),确认无残留引用
- [x] 11.3 全局搜索 `statisticsV1` (大小写敏感),确认无残留引用
- [x] 11.4 全局搜索 `GetDailyStatistics` (TransactionRecordController),确认仅 TransactionStatisticsController 中存在
- [x] 11.5 全局搜索 `GetUncoveredCategories`,确认无残留引用
- [x] 11.6 全局搜索 `GetArchiveSummary`,确认无残留引用
- [x] 11.7 全局搜索 `GetBalanceStatistics`,确认无残留引用
- [x] 11.8 全局搜索 `/calendar` 路由,确认仅出现在测试或配置文件中
- [x] 11.9 全局搜索 `/budget` 路由,确认仅出现在测试或配置文件中
## 12. 测试用例清理
- [x] 12.1 搜索并删除 `WebApi.Test/` 中针对 V1 API 的单元测试
- [x] 12.2 运行所有后端测试 (`dotnet test`),确保无失败测试
- [x] 12.3 如果有前端测试,运行并修复受影响的测试用例
## 13. 代码审查和提交
- [ ] 13.1 使用 `git status` 确认所有修改的文件
- [ ] 13.2 使用 `git diff` 审查每个删除的代码块,确认无误删
- [ ] 13.3 提交变更到本地分支: `git add . && git commit -m "feat: remove V1 calendar/budget/stats modules"`
- [ ] 13.4 推送到远程分支: `git push origin feature/remove-v1-modules`
## 14. Pull Request 和最终验证
- [ ] 14.1 创建 Pull Request填写变更说明和测试结果
- [ ] 14.2 代码审查: 确认删除的代码不在 V2 中被引用
- [ ] 14.3 CI/CD 管道通过 (编译 + 测试)
- [ ] 14.4 合并到主分支
## 15. 生产环境验证 (可选)
- [ ] 15.1 部署到测试环境,验证 V2 页面功能完整性
- [ ] 15.2 监控错误日志,确认无 404 或运行时错误
- [ ] 15.3 部署到生产环境
- [ ] 15.4 监控用户反馈和错误报告
---
## 回滚预案
如果在任何阶段发现 V2 功能异常:
1. **立即回滚**: `git revert <commit-hash>``git reset --hard <previous-commit>`
2. **定位问题**: 使用 `git diff` 找到引起问题的删除操作
3. **部分恢复**: 仅恢复必要的文件或方法 (使用 `git checkout <commit> -- <file>`)
4. **重新测试**: 确认恢复后 V2 功能正常
5. **分析根因**: 更新任务清单,标记需要保留的代码
---
## 后续清理任务 (标记为 Non-Goal不在本次范围内)
- **共享组件优化**: 移除 TransactionList、TransactionDetail 等组件中的 V1 特定逻辑
- **全局事件机制**: 如果 V2 不再需要全局事件监听,迁移到 Pinia store
- **API 文档更新**: 在 Swagger/Scalar 中标记已移除的端点
- **用户文档更新**: 说明 V1 已下线,引导用户使用 V2
- **性能优化**: 基于 V2 的使用数据优化接口和前端渲染逻辑

View File

@@ -0,0 +1,31 @@
# V1 相关文件列表备份 (用于回滚参考)
# 生成时间: 2026-02-13
## 前端页面文件
Web/src/views/CalendarView.vue
Web/src/views/BudgetView.vue
Web/src/views/statisticsV1/Index.vue
## 前端 API 客户端 (部分方法)
Web/src/api/transactionRecord.js (GetDailyStatistics 调用)
Web/src/api/budget.js (getUncoveredCategories, getArchiveSummary)
Web/src/api/statistics.js (getBalanceStatistics)
## 前端路由配置 (部分路由)
Web/src/router/index.js (/calendar, /budget, / 的 V1 路由)
## 后端 Controller 方法
WebApi/Controllers/TransactionRecordController.cs::GetDailyStatisticsAsync
WebApi/Controllers/BudgetController.cs::GetUncoveredCategoriesAsync
WebApi/Controllers/BudgetController.cs::GetArchiveSummaryAsync
WebApi/Controllers/TransactionStatisticsController.cs::GetBalanceStatisticsAsync
## 后端 Application 方法
Application/BudgetApplication.cs::GetUncoveredCategoriesAsync
Application/BudgetApplication.cs::GetArchiveSummaryAsync
Application/TransactionStatisticsApplication.cs::GetBalanceStatisticsAsync
## 后端 Service 方法
Service/Budget/BudgetService.cs::GetUncoveredCategoriesAsync
Service/Budget/BudgetService.cs::GetArchiveSummaryAsync
Service/Transaction/TransactionStatisticsService.cs::GetBalanceStatisticsAsync