chore: migrate remaining ECharts components to Chart.js

- Migrated 4 components from ECharts to Chart.js:
  * MonthlyExpenseCard.vue (折线图)
  * DailyTrendChart.vue (双系列折线图)
  * ExpenseCategoryCard.vue (环形图)
  * BudgetChartAnalysis.vue (仪表盘 + 多种图表)

- Removed all ECharts imports and environment variable switches
- Unified all charts to use BaseChart.vue component
- Build verified: pnpm build success ✓
- No echarts imports remaining ✓

Refs: openspec/changes/migrate-remaining-echarts-to-chartjs
This commit is contained in:
SunCheng
2026-02-16 21:55:38 +08:00
parent a88556c784
commit 9921cd5fdf
77 changed files with 6964 additions and 1632 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-15

View File

@@ -0,0 +1,260 @@
## Context
当前 EmailBill 项目中存在两个 `TransactionList.vue` 实现:
1. **旧版**`Web/src/components/TransactionList.vue`):传统一行一卡片布局,功能完整但样式较旧
2. **v2 版**`Web/src/views/calendarV2/modules/TransactionList.vue`):现代卡片式设计,视觉层次更好
两个组件分别服务不同页面,导致:
- 代码重复格式化、API 调用、交互逻辑)
- 样式不一致(用户体验割裂)
- 维护成本高(修改需同步两处)
**技术栈约束:**
- Vue 3 Composition API + `<script setup>` (JavaScript)
- Vant UI 组件库(移动端)
- Pinia 状态管理
- 后端 API`@/api/transactionRecord`
**重要说明:**
- 项目使用 **JavaScript** 而非 TypeScript
- 使用 JSDoc 注释提供类型提示
- Props 和 Emits 使用 `defineProps()``defineEmits()` 的对象语法
**设计目标:**
创建统一的 `BillListComponent.vue`,整合两者优点,高内聚设计,支持筛选、排序、分页、左滑删除、详情查看。
## Goals / Non-Goals
**Goals:**
- 创建可复用的账单列表组件 `BillListComponent.vue`(位于 `Web/src/components/Bill/`
- 基于 v2 风格,但调整为紧凑列表(非一行一卡片)
- 内置筛选(类型、分类、日期范围)、排序(金额、时间)、分页加载
- 支持左滑删除van-swipe-cell、点击详情emit 事件)
- 保留旧版的特殊功能checkbox 选择模式)
- 迁移所有使用旧组件的页面到新组件
- 删除旧版 `Web/src/components/TransactionList.vue`
**Non-Goals:**
- 不改变后端 API 接口
- 不涉及新增数据字段
- 不处理账单编辑功能(仅展示和删除)
- 暂不支持拖拽排序
## Decisions
### 决策 1组件命名和位置
**选择**`Web/src/components/Bill/BillListComponent.vue`
**理由**
- 放在 `Bill/` 目录下与现有 `BillForm.vue``ManualBillAdd.vue` 等保持一致
- 命名为 `BillListComponent` 而非 `TransactionList`,避免与旧组件混淆
- 符合项目 BEM 命名规范
**备选方案**
- 直接覆盖旧版 `TransactionList.vue`**拒绝**:迁移期间需要并存,且容易引起冲突
### 决策 2Props 设计(高内聚 vs 灵活配置)
**选择****高内聚** - 组件内部管理筛选、排序、分页状态
**Props 定义**
```javascript
// 使用 defineProps 对象语法 + JSDoc
const props = defineProps({
// 数据源模式
dataSource: {
type: String, // 'api' | 'custom'
default: 'api'
},
// API 模式参数
apiParams: {
type: Object, // { dateRange?: [string, string], category?: string, type?: 0|1|2 }
default: () => ({})
},
// Custom 模式参数
transactions: {
type: Array, // Transaction[]
default: () => []
},
// 功能开关
showDelete: {
type: Boolean,
default: true
},
showCheckbox: {
type: Boolean,
default: false
},
enableFilter: {
type: Boolean,
default: true
},
enableSort: {
type: Boolean,
default: true
},
// 样式配置
compact: {
type: Boolean,
default: true
},
// 多选状态
selectedIds: {
type: Set,
default: () => new Set()
}
})
```
**理由**
- 大部分场景只需传 `apiParams`,组件自动处理筛选、排序、分页
- `dataSource='custom'` 模式兼容特殊场景(如离线数据、缓存数据)
- 功能开关满足不同页面需求(如 TransactionsRecord 需要 checkbox
**备选方案**
- 低内聚(父组件管理所有状态)→ **拒绝**:每个使用方都要重复实现筛选、排序逻辑,违背复用目标
### 决策 3筛选 UI 实现
**选择**`van-dropdown-menu` + `van-popup`(日期选择器)
**布局**
```
[类型 ▼] [分类 ▼] [日期 ▼] [排序 ▼]
```
**理由**
- Vant 的 `van-dropdown-menu` 适合移动端,节省空间
- 日期范围选择使用 `van-calendar` 弹出层
- 与项目现有 UI 风格一致
**备选方案**
- 使用 `van-tabs` 切换筛选项 → **拒绝**:占用空间大,不适合同时筛选多个维度
### 决策 4数据加载策略
**选择**:虚拟滚动 + 分页加载(`van-list`
**实现**
- 初始加载 20 条
- 滚动到底部触发 `@load` 事件,追加 20 条
- 筛选/排序变更时,重置列表并重新加载
**理由**
- Vant 的 `van-list` 内置分页逻辑,简单易用
- 账单数据量通常不大(日常使用 < 1000 条),无需复杂虚拟滚动库
**备选方案**
- 一次性加载全部数据 → **拒绝**:账单数量多时性能差
### 决策 5删除功能的事务处理
**选择**:组件内部调用 `deleteTransaction` API删除成功后 emit 事件并派发全局事件
**流程**
```javascript
const handleDelete = async (transaction) => {
await showConfirmDialog({ message: '确定删除?' })
await deleteTransaction(transaction.id) // API 调用
emit('delete', transaction.id) // 通知父组件
window.dispatchEvent(new CustomEvent('transaction-deleted', { detail: transaction.id })) // 全局事件
// 刷新当前列表
}
```
**理由**
- 保持与旧版一致的删除逻辑(已验证可用)
- 全局事件通知其他组件刷新(如统计图表)
- 父组件可通过 `@delete` 监听执行额外逻辑
**备选方案**
- 父组件负责删除 → **拒绝**:增加使用成本,每个页面都要实现删除逻辑
### 决策 6样式调整紧凑列表
**选择**:修改 v2 的卡片布局,减少卡片间距和内边距
**调整细节**
```scss
.bill-card {
margin-top: 6px; // 原 10px
padding: 10px 12px; // 原 var(--spacing-xl) (约 16px)
gap: 10px; // 原 14px
}
```
**理由**
- v2 原始设计间距较大,适合日历单日视图
- 列表视图需要更紧凑以显示更多条目
- 保留 v2 的视觉元素(图标、标签、颜色)
## Risks / Trade-offs
### 风险 1迁移期间功能遗漏
**风险**:旧版组件可能有未文档化的特殊用法,迁移时遗漏
**缓解措施**
- 迁移前全面梳理旧版所有 props 和 emits
- 保留 `showCheckbox``selectedIds` 功能TransactionsRecord 批量操作依赖)
- 迁移分阶段进行,逐个页面验证
### 风险 2性能退化
**风险**:新增筛选、排序逻辑可能影响渲染性能
**缓解措施**
- 使用 `computed` 缓存筛选结果
- 大数据量时依赖后端 API 筛选(而非前端过滤)
- 测试场景1000+ 条数据的滚动流畅度
### 风险 3样式兼容性
**风险**:不同页面的主题色、暗黑模式可能导致显示异常
**缓解措施**
- 使用 CSS 变量(`var(--van-danger-color)` 等),自动适配主题
- 测试暗黑模式下的视觉效果
- 提供 `themeOverride` prop 允许父组件覆盖样式
### Trade-off组件复杂度 vs 易用性
**权衡**高内聚设计会增加组件内部复杂度300+ 行代码)
**选择**:接受复杂度换取易用性
**理由**
- 简化所有使用方的代码10+ 处引用)
- 统一维护点,避免分散的重复逻辑
- 内部复杂度可通过单元测试覆盖
## Migration Plan
### 阶段 1组件开发第 1-2 天)
1. 创建 `Web/src/components/Bill/BillListComponent.vue`
2. 实现核心功能:数据展示、分页、左滑删除
3. 实现筛选、排序 UI 和逻辑
4. 单元测试覆盖Vue Test Utils
### 阶段 2试点迁移第 3 天)
1. 选择一个简单页面试点(如 `BillAnalysisView.vue`
2. 替换旧组件为新组件
3. 验证功能完整性和视觉效果
4. 修复发现的问题
### 阶段 3全面迁移第 4-5 天)
1. 迁移 `TransactionsRecord.vue`(重点验证 checkbox 功能)
2. 迁移其他引用旧组件的页面
3. 回归测试所有相关页面
### 阶段 4清理第 6 天)
1. 删除旧版 `Web/src/components/TransactionList.vue`
2. 删除 `Web/src/views/calendarV2/modules/TransactionList.vue`(如不再需要)
3. 更新文档和 AGENTS.md
### Rollback 策略
- 保留旧版组件直到所有页面迁移完成
- 使用 Git 分支隔离迁移工作
- 如发现严重问题,可快速恢复旧版(修改 import 路径)
## Open Questions
1. **calendarV2 的 TransactionList 是否有特殊逻辑?**
需要确认 calendarV2 是否依赖其特有功能(如 Smart 按钮、日期联动)。如果有,可能需要保留该文件,仅迁移其他页面。
2. **是否需要支持自定义列渲染?**
当前设计固定显示字段reason, amount, classify 等)。未来是否需要 slot 支持自定义?暂时不实现,等实际需求再扩展。
3. **筛选条件的持久化?**
用户设置的筛选条件是否需要保存到 localStorage当前设计不持久化每次刷新恢复默认。

View File

@@ -0,0 +1,42 @@
## Why
当前项目中存在多个账单列表实现(`TransactionList.vue``components/``calendarV2/modules/`导致代码重复、样式不统一、维护成本高。v2 版本的账单列表calendarV2/modules/TransactionList.vue采用了更现代的卡片式设计和更好的视觉层次应当作为标准组件在全项目范围内复用。
## What Changes
- **新增**:创建高内聚、可复用的 `BillListComponent.vue` 组件(基于 v2 风格)
- **调整**:修改 v2 的一行一卡片布局,支持更紧凑的列表展示
- **新增**:内置筛选(按类型、分类、日期)、排序(金额、时间)、分页功能
- **新增**左滑删除交互Vant SwipeCell
- **新增**点击查看详情功能emit 事件)
- **删除**:移除旧版本的 `TransactionList.vue`Web/src/components/
- **迁移**现有使用旧组件的页面TransactionsRecord.vue、BillAnalysisView.vue 等)改为引用新组件
## Capabilities
### New Capabilities
- `bill-list-component`: 可复用的账单列表组件,支持筛选、排序、分页、左滑删除、点击详情等功能,样式基于 calendarV2 的现代化设计
### Modified Capabilities
- `transaction-list-display`: 现有的交易列表展示能力需要统一到新组件,旧版本 TransactionList.vue 的功能将被新组件替代
## Impact
**受影响的代码:**
- `Web/src/components/TransactionList.vue` - 将被删除
- `Web/src/views/calendarV2/modules/TransactionList.vue` - 作为参考基础,可能需要重构
- `Web/src/views/TransactionsRecord.vue` - 需要切换到新组件
- `Web/src/views/BillAnalysisView.vue` - 需要切换到新组件
- 其他可能引用旧版 TransactionList 的视图
**API 依赖:**
- `@/api/transactionRecord` - deleteTransaction, getTransactionsByDate 等接口
- 保持现有 API 调用方式不变
**UI 依赖:**
- Vant UI: van-swipe-cell, van-list, van-loading, van-empty, van-icon, van-tag
- 需要新增筛选/排序 UI 组件van-dropdown-menu, van-popup
**用户体验影响:**
- 正面:统一的视觉风格、更流畅的交互、更好的性能(高内聚设计)
- 迁移风险:需要确保功能对等,避免遗漏旧版本的特殊功能(如 checkbox 选择模式)

View File

@@ -0,0 +1,191 @@
## ADDED Requirements
### Requirement: Component accepts configuration props
组件必须接受配置 props 以支持不同的使用场景,包括数据源模式、功能开关、样式配置等。
#### Scenario: API 数据源模式
- **WHEN** 父组件传入 `dataSource="api"``apiParams={ dateRange: ['2026-01-01', '2026-01-31'] }`
- **THEN** 组件调用后端 API 获取指定日期范围内的账单数据
#### Scenario: 自定义数据源模式
- **WHEN** 父组件传入 `dataSource="custom"``transactions` 数组
- **THEN** 组件直接使用传入的数据进行展示,不调用 API
#### Scenario: 禁用筛选功能
- **WHEN** 父组件传入 `enableFilter={false}`
- **THEN** 组件不显示筛选栏(类型、分类、日期下拉菜单)
#### Scenario: 启用多选模式
- **WHEN** 父组件传入 `showCheckbox={true}`
- **THEN** 每个账单项左侧显示复选框,支持多选
### Requirement: 账单列表展示
组件必须以紧凑列表形式展示账单数据,每个账单项包含关键信息(摘要、金额、分类、时间)。
#### Scenario: 展示支出账单
- **WHEN** 账单类型为支出type=0
- **THEN** 金额显示为红色负数(如 "- ¥50.00"),右上角显示红色"支出"标签
#### Scenario: 展示收入账单
- **WHEN** 账单类型为收入type=1
- **THEN** 金额显示为绿色正数(如 "+ ¥1000.00"),右上角显示绿色"收入"标签
#### Scenario: 显示账单图标
- **WHEN** 账单有分类信息(如"餐饮"
- **THEN** 卡片左侧显示对应的图标(如 food 图标),背景色与分类关联
#### Scenario: 空列表状态
- **WHEN** 筛选结果为空或无账单数据
- **THEN** 显示空状态提示"暂无交易记录",带有图标和友好文案
### Requirement: 筛选功能
组件必须提供内置的筛选功能,支持按类型、分类、日期范围筛选账单。
#### Scenario: 按类型筛选
- **WHEN** 用户在筛选栏选择"支出"
- **THEN** 列表仅显示类型为支出的账单type=0
#### Scenario: 按分类筛选
- **WHEN** 用户在筛选栏选择"餐饮"
- **THEN** 列表仅显示分类为"餐饮"的账单
#### Scenario: 按日期范围筛选
- **WHEN** 用户选择日期范围"2026-02-01 至 2026-02-15"
- **THEN** 列表仅显示该日期范围内的账单
#### Scenario: 多条件组合筛选
- **WHEN** 用户同时选择"支出"、"餐饮"和日期范围
- **THEN** 列表显示满足所有条件的账单AND 逻辑)
#### Scenario: 清空筛选条件
- **WHEN** 用户点击"重置"或清空所有筛选项
- **THEN** 列表恢复显示全部账单
### Requirement: 排序功能
组件必须支持按金额或时间排序账单列表。
#### Scenario: 按金额降序排序
- **WHEN** 用户在排序下拉菜单选择"金额从高到低"
- **THEN** 列表按金额降序重新排列
#### Scenario: 按时间升序排序
- **WHEN** 用户在排序下拉菜单选择"时间从早到晚"
- **THEN** 列表按交易时间升序排列
#### Scenario: 默认排序
- **WHEN** 组件初始加载且用户未设置排序
- **THEN** 列表按时间降序排列(最新的在前)
### Requirement: 分页加载
组件必须支持滚动分页加载,优化大数据量时的性能。
#### Scenario: 初始加载
- **WHEN** 组件首次渲染
- **THEN** 加载前 20 条账单数据并显示
#### Scenario: 滚动加载更多
- **WHEN** 用户滚动到列表底部
- **THEN** 自动加载下一页 20 条数据并追加到列表
#### Scenario: 加载完成提示
- **WHEN** 所有数据加载完毕
- **THEN** 列表底部显示"没有更多了"提示
#### Scenario: 筛选后重新分页
- **WHEN** 用户修改筛选条件
- **THEN** 列表重置到第一页,重新开始分页加载
### Requirement: 左滑删除功能
组件必须支持左滑显示删除按钮,并处理删除操作。
#### Scenario: 左滑显示删除按钮
- **WHEN** 用户在账单项上左滑
- **THEN** 右侧显示红色"删除"按钮
#### Scenario: 确认删除
- **WHEN** 用户点击"删除"按钮并在确认对话框中选择"确定"
- **THEN** 调用 API 删除该账单,成功后从列表移除,显示"删除成功"提示
#### Scenario: 取消删除
- **WHEN** 用户点击"删除"按钮并在确认对话框中选择"取消"
- **THEN** 不执行删除操作,滑块自动归位
#### Scenario: 删除失败处理
- **WHEN** API 删除失败(如网络错误)
- **THEN** 显示"删除失败"提示,列表不变
#### Scenario: 删除后广播事件
- **WHEN** 账单删除成功
- **THEN** 组件派发全局事件 `transaction-deleted`,携带删除的账单 ID
#### Scenario: 禁用删除功能
- **WHEN** 父组件传入 `showDelete={false}`
- **THEN** 左滑不显示删除按钮
### Requirement: 点击查看详情
组件必须支持点击账单项查看详情,通过 emit 事件通知父组件。
#### Scenario: 点击账单卡片
- **WHEN** 用户点击账单项(非复选框、非删除按钮区域)
- **THEN** 组件触发 `@click` 事件,传递完整的账单对象
#### Scenario: 父组件处理详情显示
- **WHEN** 父组件监听 `@click` 事件
- **THEN** 父组件接收账单对象,自行决定详情展示方式(如弹窗、路由跳转)
### Requirement: 多选功能
组件必须支持多选模式,用于批量操作场景。
#### Scenario: 启用多选模式
- **WHEN** 父组件传入 `showCheckbox={true}`
- **THEN** 每个账单项左侧显示复选框
#### Scenario: 选中账单
- **WHEN** 用户点击复选框
- **THEN** 该账单被标记为选中状态,复选框显示勾选
#### Scenario: 取消选中
- **WHEN** 用户再次点击已选中的复选框
- **THEN** 该账单取消选中状态
#### Scenario: 同步选中状态
- **WHEN** 父组件更新 `selectedIds` prop
- **THEN** 组件更新复选框的选中状态以匹配传入的 ID 集合
#### Scenario: 通知父组件选中变更
- **WHEN** 用户切换复选框状态
- **THEN** 组件触发 `@update:selectedIds` 事件,传递新的选中 ID 集合
### Requirement: 样式适配
组件必须适配移动端主题和暗黑模式。
#### Scenario: 亮色主题
- **WHEN** 应用使用亮色主题
- **THEN** 组件使用浅色背景、深色文字,边框和标签使用主题色
#### Scenario: 暗黑模式
- **WHEN** 应用切换到暗黑模式
- **THEN** 组件使用深色背景、浅色文字,自动适配 Vant 的暗黑主题变量
#### Scenario: 紧凑模式
- **WHEN** 父组件传入 `compact={true}`(默认)
- **THEN** 卡片间距为 6px内边距为 10px显示更多条目
#### Scenario: 舒适模式
- **WHEN** 父组件传入 `compact={false}`
- **THEN** 卡片间距和内边距增大(如 v2 原始尺寸)
### Requirement: 加载状态
组件必须显示加载状态,提供良好的用户反馈。
#### Scenario: 首次加载中
- **WHEN** 组件调用 API 获取数据且尚未返回
- **THEN** 显示加载动画van-loading和"加载中..."文案
#### Scenario: 分页加载中
- **WHEN** 用户滚动触发分页加载
- **THEN** 列表底部显示加载动画
#### Scenario: 删除操作中
- **WHEN** 用户点击删除且 API 调用进行中
- **THEN** 删除按钮显示加载状态,防止重复点击

View File

@@ -0,0 +1,59 @@
## ADDED Requirements
### Requirement: 统一组件实现
系统必须使用统一的 BillListComponent 替代现有的多个账单列表实现,确保代码复用和样式一致性。
#### Scenario: 替换旧版 TransactionList
- **WHEN** 页面需要展示账单列表
- **THEN** 使用 `BillListComponent.vue` 而非 `components/TransactionList.vue`
#### Scenario: CalendarV2 模块迁移
- **WHEN** CalendarV2 需要展示交易列表
- **THEN** 使用 `BillListComponent.vue` 或保留其特有实现(如有特殊需求)
### Requirement: 功能对等性
新组件必须保持旧版所有功能,确保迁移不丢失特性。
#### Scenario: 批量选择功能
- **WHEN** TransactionsRecord 需要批量操作
- **THEN** 新组件通过 `showCheckbox``selectedIds` 提供相同功能
#### Scenario: 删除后刷新
- **WHEN** 账单删除成功
- **THEN** 新组件派发 `transaction-deleted` 全局事件,保持与旧版相同的事件机制
#### Scenario: 自定义数据源
- **WHEN** 页面需要展示离线或缓存数据
- **THEN** 新组件通过 `dataSource="custom"``transactions` prop 支持自定义数据
### Requirement: 视觉升级
新组件必须基于 v2 的现代化设计,提供更好的视觉体验。
#### Scenario: 卡片样式
- **WHEN** 展示账单列表
- **THEN** 使用 v2 的卡片样式(圆角、阴影、图标),但调整为紧凑间距
#### Scenario: 图标展示
- **WHEN** 账单有分类信息
- **THEN** 显示对应的分类图标(如餐饮用 food 图标),带有彩色背景
#### Scenario: 标签样式
- **WHEN** 显示账单类型
- **THEN** 使用彩色标签(支出红色、收入绿色),位于卡片右上角
### Requirement: 迁移计划
系统必须按阶段迁移,确保平滑过渡。
#### Scenario: 并存期
- **WHEN** 迁移进行中
- **THEN** 新旧组件共存,已迁移页面使用新组件,未迁移页面继续使用旧组件
#### Scenario: 清理旧代码
- **WHEN** 所有页面迁移完成
- **THEN** 删除 `components/TransactionList.vue`,移除相关 import
## REMOVED Requirements
### Requirement: 一行一卡片布局
**Reason**: 间距过大,不适合列表视图,需要滚动过多才能查看更多账单
**Migration**: 使用新的紧凑布局(`compact={true}`),卡片间距减少至 6px

View File

@@ -0,0 +1,135 @@
## 1. 组件基础结构搭建
- [x] 1.1 创建 `Web/src/components/Bill/BillListComponent.vue` 文件
- [x] 1.2 定义 TypeScript Props 接口dataSource, apiParams, transactions, showDelete, showCheckbox, enableFilter, enableSort, compact
- [x] 1.3 定义 Emits 接口load, click, delete, update:selectedIds
- [x] 1.4 创建组件骨架template、script setup、style scoped
- [x] 1.5 添加必要的 Vant 组件导入van-list, van-swipe-cell, van-dropdown-menu, van-loading, van-empty, van-icon, van-tag
## 2. 数据管理和状态
- [x] 2.1 实现 `dataSource` 模式切换逻辑api vs custom
- [x] 2.2 创建响应式数据状态transactions, loading, finished, page, pageSize
- [x] 2.3 实现筛选状态管理selectedType, selectedCategory, dateRange, sortBy
- [x] 2.4 实现多选状态管理localSelectedIds, 与 prop 同步)
- [x] 2.5 创建 computed 计算属性用于筛选和排序逻辑
## 3. API 数据加载
- [x] 3.1 导入 `@/api/transactionRecord` 的相关 API 方法
- [x] 3.2 实现初始加载逻辑fetchTransactions 方法)
- [x] 3.3 实现分页加载逻辑onLoad 方法,支持 van-list
- [x] 3.4 实现筛选条件变更时的数据重载逻辑
- [x] 3.5 处理 API 错误和加载状态
## 4. 筛选功能实现
- [x] 4.1 创建筛选栏 UIvan-dropdown-menu包含类型、分类、日期、排序四个下拉菜单
- [x] 4.2 实现类型筛选(支出、收入、不计入、全部)
- [x] 4.3 实现分类筛选(动态获取分类列表或预设常用分类)
- [x] 4.4 实现日期范围筛选(使用 van-calendar 弹出层)
- [x] 4.5 实现排序功能(金额降序、金额升序、时间降序、时间升序)
- [x] 4.6 添加筛选重置功能
- [x] 4.7 根据 `enableFilter` prop 控制筛选栏显示/隐藏
## 5. 账单列表展示
- [x] 5.1 创建账单卡片布局(基于 v2 风格,左侧图标、中间内容、右侧金额)
- [x] 5.2 实现紧凑模式样式(减少卡片间距至 6px内边距至 10px
- [x] 5.3 实现账单图标显示(根据分类映射图标,使用 getIconByClassify 方法)
- [x] 5.4 实现金额格式化(带符号、颜色区分支出/收入)
- [x] 5.5 实现类型标签显示(右上角,支出红色、收入绿色)
- [x] 5.6 实现时间格式化显示HH:MM 或 YYYY-MM-DD HH:MM
- [x] 5.7 实现空状态展示van-empty带友好文案
## 6. 左滑删除功能
- [x] 6.1 为每个账单项添加 van-swipe-cell 包裹
- [x] 6.2 创建删除按钮插槽(右侧滑出,红色按钮)
- [x] 6.3 实现删除确认对话框van-dialog
- [x] 6.4 实现删除 API 调用deleteTransaction
- [x] 6.5 删除成功后更新本地列表(移除对应项)
- [x] 6.6 显示删除成功/失败提示van-toast
- [x] 6.7 派发全局事件 `transaction-deleted`
- [x] 6.8 触发父组件 `@delete` 事件
- [x] 6.9 根据 `showDelete` prop 控制删除功能启用/禁用
## 7. 点击详情功能
- [x] 7.1 为账单卡片添加 @click 事件监听
- [x] 7.2 实现 handleClick 方法,触发 `@click` 事件并传递账单对象
- [x] 7.3 确保点击复选框或删除按钮时不触发详情事件(事件冒泡处理)
## 8. 多选功能
- [x] 8.1 在账单项左侧添加 van-checkbox根据 `showCheckbox` prop 控制显示)
- [x] 8.2 实现 checkbox 选中状态与 `selectedIds` prop 同步
- [x] 8.3 实现 toggleSelection 方法(切换选中状态)
- [x] 8.4 触发 `@update:selectedIds` 事件更新父组件状态
- [ ] 8.5 添加全选/取消全选功能(可选,视需求)
## 9. 样式和主题适配
- [x] 9.1 使用 SCSS 编写组件样式
- [x] 9.2 使用 CSS 变量适配 Vant 主题(`var(--van-danger-color)` 等)
- [x] 9.3 实现暗黑模式适配(检查暗色背景下的显示效果)
- [x] 9.4 根据 `compact` prop 调整卡片间距和内边距
- [x] 9.5 确保移动端响应式布局(处理小屏幕、横屏等情况)
- [x] 9.6 添加过渡动画(卡片删除、列表加载等)
## 10. 页面迁移 - TransactionsRecord
- [x] 10.1 在 `TransactionsRecord.vue` 中导入新组件 `BillListComponent`
- [x] 10.2 替换旧 `TransactionList` 组件为 `BillListComponent`
- [x] 10.3 传递必要的 propsshowCheckbox, selectedIds, apiParams
- [x] 10.4 更新事件监听(@click, @delete, @update:selectedIds
- [ ] 10.5 验证批量操作功能正常(选中、删除、导出等)
- [ ] 10.6 测试页面功能完整性
## 11. 页面迁移 - BillAnalysisView
- [x] 11.1 在 `BillAnalysisView.vue` 中导入新组件 `BillListComponent` (页面未使用旧组件,跳过)
- [x] 11.2 替换旧组件为 `BillListComponent` (页面未使用旧组件,跳过)
- [x] 11.3 传递筛选参数(如按分类、日期范围)(页面未使用旧组件,跳过)
- [x] 11.4 更新事件监听 (页面未使用旧组件,跳过)
- [x] 11.5 测试页面功能正常 (页面未使用旧组件,跳过)
## 12. 页面迁移 - 其他引用页面
- [x] 12.1 使用 grep 搜索所有引用旧 `TransactionList` 的文件
- [x] 12.2 逐个页面进行迁移(重复步骤 10-11 的流程)
- [x] 12.3 验证每个页面的功能和样式
- [x] 12.4 检查是否有遗漏的引用
## 13. CalendarV2 模块处理
- [x] 13.1 评估 `calendarV2/modules/TransactionList.vue` 的特殊功能Smart 按钮、日期联动等)
- [x] 13.2 决定是保留该文件还是迁移到新组件
- [x] 13.3 如保留,添加注释说明其特殊性;如迁移,确保功能对等
- [x] 13.4 测试 CalendarV2 的交易列表功能
## 14. 清理旧代码
- [x] 14.1 删除 `Web/src/components/TransactionList.vue`
- [x] 14.2 检查并删除相关的未使用导入
- [x] 14.3 更新 `AGENTS.md` 或相关文档,说明新组件的使用方式
- [x] 14.4 提交代码变更Git commit
## 15. 测试和验证
- [ ] 15.1 编写单元测试Vue Test Utils测试 props、emits、筛选、排序逻辑
- [ ] 15.2 手动测试所有功能点(筛选、排序、分页、删除、多选、详情)
- [ ] 15.3 测试暗黑模式显示效果
- [ ] 15.4 测试不同屏幕尺寸的响应式布局
- [ ] 15.5 测试 API 错误处理和边界情况(空数据、网络错误等)
- [ ] 15.6 回归测试所有迁移页面,确保无功能丢失
- [ ] 15.7 性能测试(加载 1000+ 条数据时的流畅度)
## 16. 文档和收尾
- [x] 16.1 编写组件使用文档Props、Emits、Slots 说明)
- [x] 16.2 更新 `Web/src/views/AGENTS.md`(如有)
- [x] 16.3 在组件文件顶部添加 JSDoc 注释
- [x] 16.4 代码格式化pnpm lint
- [x] 16.5 构建测试pnpm build
- [x] 16.6 最终代码审查