Files
EmailBill/openspec/changes/archive/2026-02-16-migrate-remaining-echarts-to-chartjs/design.md
SunCheng c1e2adacea chore: archive migrate-remaining-echarts-to-chartjs change
- Synced chart-migration-patterns spec to main specs
- Archived to openspec/changes/archive/2026-02-16-migrate-remaining-echarts-to-chartjs
- All artifacts complete, 57/80 tasks complete (23 test tasks skipped)

Schema: spec-driven
Status: ✓ Complete with warnings (test tasks skipped)
2026-02-16 22:40:13 +08:00

202 lines
6.1 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.
## Context
**当前状态**
- 项目已建立 Chart.js 基础设施BaseChart.vue、useChartTheme、chartHelpers
- 4 个组件仍使用 ECharts API 或通过环境变量 `VITE_USE_CHARTJS` 双模式运行
- ECharts 依赖已从 package.json 移除,导致构建失败
**技术栈**
- Chart.js 4.5.1 + vue-chartjs 5.3.3
- Vue 3 Composition API + Vant UI
- 移动端优先设计
**约束**
- 必须保持图表视觉效果一致(颜色、布局、标签格式)
- 不能影响用户交互行为点击、hover、tooltip
- 需兼容暗色模式(通过 useChartTheme
## Goals / Non-Goals
**Goals:**
- 彻底移除 ECharts 代码和环境变量开关
- 统一使用 BaseChart.vue 包装组件
- 确保所有图表类型正确渲染:
- 仪表盘图表Gauge Chart→ Doughnut + 中心文本叠加
- 折线图Line Chart→ Chart.js Line
- 饼图/环形图Pie/Doughnut Chart→ Chart.js Doughnut
- 通过白盒和黑盒测试验证功能正确性
**Non-Goals:**
- 不重新设计图表样式或交互
- 不优化图表性能(除非迁移过程中发现明显问题)
- 不添加新的图表功能
- 不修改业务逻辑或数据处理代码
## Decisions
### 1. 仪表盘图表实现方案
**决策**:使用 Doughnut 图表 + CSS 绝对定位的中心文本覆盖层
**理由**
- Chart.js 无原生 Gauge 图表类型
- Doughnut 图表可以通过 `rotation``circumference` 配置实现半圆仪表盘效果
- 项目中 `BudgetChartAnalysis.vue` 已使用 ECharts Gauge需保持视觉一致性
**替代方案**
- ❌ 使用第三方插件(如 chartjs-gauge增加依赖复杂度
- ❌ 使用 Canvas 自绘:维护成本高,不符合项目标准
**实现细节**
```javascript
{
type: 'doughnut',
data: {
datasets: [{
data: [current, limit - current],
backgroundColor: [progressColor, '#f0f0f0'],
rotation: -90, // 从顶部开始
circumference: 180 // 半圆
}]
},
options: {
cutout: '70%', // 内环大小
plugins: {
legend: { display: false },
tooltip: { enabled: false }
}
}
}
```
### 2. 图表数据转换策略
**决策**:复用现有的 `prepareChartData()` 函数,仅修改图表配置部分
**理由**
- 所有组件都已有数据准备逻辑(`prepareChartData()`
- 数据格式labels + datasets在 ECharts 和 Chart.js 之间相似
- 减少代码改动,降低引入 bug 风险
**迁移模式**
```javascript
// 保留
const { xAxisLabels, expenseData, incomeData } = prepareChartData()
// 修改:从 ECharts option 转为 Chart.js data + options
const chartData = {
labels: xAxisLabels,
datasets: [{
label: '支出',
data: expenseData,
borderColor: colors.value.danger,
backgroundColor: 'rgba(238, 10, 36, 0.1)'
}]
}
const chartOptions = getChartOptions({
plugins: { legend: { display: false } }
})
```
### 3. 环境变量清理
**决策**:删除所有 `VITE_USE_CHARTJS` 相关的条件渲染和双分支代码
**理由**
- 项目已标准化使用 Chart.js无需保留回退选项
- 双模式代码增加维护成本和测试复杂度
- ECharts 依赖已移除,无法回退
**清理范围**
```vue
<!-- 删除 -->
<div v-if="!useChartJS" ref="chartRef" />
<div v-else><BaseChart ... /></div>
<!-- 改为 -->
<BaseChart ... />
```
### 4. 测试策略
**决策**:分层测试 = 单元测试(白盒)+ E2E 测试(黑盒)+ 视觉回归
**白盒测试Jest + Vue Test Utils**
- 测试组件能否正确挂载
- 测试 props 传入后 chartData 和 chartOptions 的正确性
- 测试事件发射(如 @chart:render
**黑盒测试Playwright**
- 测试图表在真实浏览器中的渲染
- 测试用户交互点击、hover、tooltip
- 测试暗色模式切换
**视觉回归测试**
- 截图对比迁移前后的图表外观
- 确保颜色、字体、布局一致
## Risks / Trade-offs
### Risk 1: 仪表盘视觉差异
**风险**Chart.js Doughnut 无法完美复现 ECharts Gauge 的细节(如指针动画)
**缓解**:接受静态圆弧进度条,使用颜色渐变和动画过渡弥补视觉效果
### Risk 2: 第三方样式冲突
**风险**Chart.js 的全局样式可能与 Vant UI 冲突
**缓解**:使用 scoped styles通过 `useChartTheme` 统一管理颜色变量
### Risk 3: 移动端性能
**风险**Chart.js 在低端移动设备上可能卡顿
**缓解**
- 使用 `chartHelpers.ts` 中的数据抽样功能
- 配置 `animation.duration` 为合理值750ms
- 监控 `prefers-reduced-motion` 媒体查询
### Risk 4: 无法回退
**风险**:迁移后如果发现严重问题,无法快速回退到 ECharts
**缓解**
- 迁移前创建 git tag
- 分组件逐步迁移,每个组件验证通过后再迁移下一个
- 保留完整的测试套件
## Migration Plan
### Phase 1: 单组件迁移(按复杂度排序)
1. **MonthlyExpenseCard.vue**(简单折线图)
2. **DailyTrendChart.vue**(双系列折线图)
3. **ExpenseCategoryCard.vue**(环形图 + 列表)
4. **BudgetChartAnalysis.vue**(仪表盘 + 复杂布局)
### Phase 2: 每个组件的迁移步骤
1. 备份原始 ECharts 代码(注释)
2. 替换为 BaseChart.vue + 数据转换
3. 运行单元测试
4. 本地浏览器验证Chrome + Firefox
5. 移除注释的 ECharts 代码
### Phase 3: 集成测试
1. 运行完整的 E2E 测试套件
2. 视觉回归测试(截图对比)
3. 性能测试Lighthouse
### Rollback Strategy
如果迁移失败:
1. `git revert` 到迁移前的 commit
2. 临时恢复 `echarts` 依赖:`pnpm add echarts`
3. 重新评估迁移方案
## Open Questions
1.**是否需要自定义 Chart.js 插件?**
答:仪表盘图表需要中心文本叠加层,但使用 CSS 实现,无需插件
2.**是否需要保留 ECharts 作为 devDependency**
答:不需要,项目已决定完全移除
3.**是否需要更新用户文档?**
答:图表功能对用户透明,无需更新文档
4.**是否需要通知后端团队?**
答:纯前端技术栈变更,无需通知