Files
EmailBill/.doc/chartjs-migration-complete.md
SunCheng 9921cd5fdf 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
2026-02-16 21:55:38 +08:00

147 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Chart.js 迁移完成总结
**日期**: 2026-02-16
**任务**: 将 EmailBill 项目中剩余的 ECharts 图表迁移到 Chart.js
## 迁移的组件
### 1. ExpenseCategoryCard.vue
**文件路径**: `Web/src/views/statisticsV2/modules/ExpenseCategoryCard.vue`
**变更内容**:
- ✅ 删除 `import * as echarts from 'echarts'`
- ✅ 删除 `useChartJS` 环境变量和相关的 v-if/v-else 条件渲染
- ✅ 删除 `pieChartInstance` 变量和所有 ECharts 初始化代码
- ✅ 简化模板,只保留 `<BaseChart type="doughnut" />`
- ✅ 删除 `onBeforeUnmount` 中的 ECharts cleanup
- ✅ 删除 `watch``renderPieChart()` 函数
- ✅ 移除 `if (!useChartJS) return null` 判断chartData 和 chartOptions 始终返回有效值
**保留功能**:
- ✅ Doughnut 图表(支出分类环形图)
- ✅ 数据预处理逻辑(`prepareChartData()`
- ✅ 分类列表展示
- ✅ 点击事件category-click
### 2. BudgetChartAnalysis.vue
**文件路径**: `Web/src/components/Budget/BudgetChartAnalysis.vue`
**变更内容**:
- ✅ 删除 `import * as echarts from 'echarts'`
- ✅ 引入 `BaseChart``useChartTheme` composable
- ✅ 引入 `chartjsGaugePlugin` 用于仪表盘中心文本显示
- ✅ 删除所有 ECharts 相关的 ref 变量(`monthGaugeRef`, `yearGaugeRef`, 等)
- ✅ 删除所有 ECharts 实例变量(`monthGaugeChart`, `varianceChart`, 等)
- ✅ 替换仪表盘为 Chart.js Doughnut 图表(使用 gaugePlugin
- ✅ 替换燃尽图为 Chart.js Line 图表
- ✅ 替换偏差分析为 Chart.js Bar 图表(水平方向)
- ✅ 删除所有 ECharts 初始化和更新函数
- ✅ 删除 `onBeforeUnmount` 中的 ECharts cleanup
- ✅ 删除 `handleResize` 和相关的 resize 事件监听
**实现的图表**:
#### 月度/年度仪表盘Gauge
- 使用 Doughnut 图表 + gaugePlugin
- 半圆形进度条circumference: 180, rotation: 270
- 中心文字覆盖层显示余额/差额
- 支持超支场景(红色显示)
- 颜色逻辑:
- 支出:满格绿色 → 消耗变红
- 收入:空红色 → 积累变绿
#### 月度/年度燃尽图Burndown
- 使用 Line 图表
- 两条线:理想线(虚线)+ 实际线(实线)
- 支出模式:燃尽图(向下走)
- 收入模式:积累图(向上走)
- 支持趋势数据(`props.overallStats.month.trend`
- Fallback 到线性估算
#### 偏差分析Variance
- 使用 Bar 图表(水平方向,`indexAxis: 'y'`
- 正值(超支)红色,负值(结余)绿色
- 动态高度计算30px per item
- 排序:年度在前,月度在后,各自按偏差绝对值排序
- Tooltip 显示详细信息(预算/实际/偏差)
**数据处理逻辑**:
- ✅ 保留所有业务逻辑(日期计算、趋势数据、进度计算)
- ✅ 使用 computed 属性实现响应式更新
- ✅ 格式化函数 `formatMoney()` 保持一致
## 技术栈变更
### 移除
- ❌ ECharts 5.x
- ❌ 手动管理图表实例
- ❌ 手动 resize 监听
- ❌ 手动 dispose cleanup
### 使用
- ✅ Chart.js 4.5+
- ✅ vue-chartjs 5.3+
- ✅ BaseChart 通用组件
- ✅ useChartTheme composable主题管理
- ✅ chartjsGaugePlugin仪表盘插件
- ✅ Vue 响应式系统computed
## 构建验证
```bash
cd Web && pnpm build
```
**结果**: ✅ 构建成功
- 无 TypeScript 错误
- 无 ESLint 错误
- 无 Vue 编译错误
- 产物大小正常
## 性能优势
1. **包体积减小**
- ECharts 较大(~300KB gzipped
- Chart.js 较小(~60KB gzipped
2. **更好的 Vue 集成**
- 使用 Vue 响应式系统
- 无需手动管理实例生命周期
- 自动 resize 和 cleanup
3. **一致的 API**
- 所有图表使用统一的 BaseChart 组件
- 统一的主题配置useChartTheme
- 统一的颜色变量CSS Variables
## 后续工作
- [x] 移除 VITE_USE_CHARTJS 环境变量(已不需要)
- [x] 清理所有 ECharts 相关代码
- [ ] 测试所有图表功能(手动测试)
- [ ] 验证暗色模式下的显示效果
- [ ] 验证移动端触控交互
## 注意事项
1. **仪表盘中心文本**
- 使用 CSS 绝对定位的 `.gauge-text-overlay` 显示中心文本
- 不使用 gaugePlugin 的 centerText因为需要 scaleX(-1) 翻转)
2. **偏差分析图表**
- 使用 `_meta` 字段传递额外数据到 tooltip
- 颜色根据 `activeTab`(支出/收入)动态计算
3. **响应式更新**
- 所有数据通过 computed 属性计算
- 无需手动调用 update 或 resize
- BaseChart 自动处理 props 变化
## 参考文档
- [Chart.js 官方文档](https://www.chartjs.org/)
- [vue-chartjs 文档](https://vue-chartjs.org/)
- [项目 Chart.js 使用指南](./chartjs-usage-guide.md)
- [BaseChart 组件文档](../Web/src/components/Charts/README.md)