1
Some checks failed
Docker Build & Deploy / Build Docker Image (push) Waiting to run
Docker Build & Deploy / Deploy to Production (push) Has been cancelled
Docker Build & Deploy / Cleanup Dangling Images (push) Has been cancelled
Docker Build & Deploy / WeChat Notification (push) Has been cancelled

This commit is contained in:
SunCheng
2026-02-18 21:16:45 +08:00
parent 77c9b47246
commit c49f66757e
116 changed files with 6909 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,56 @@
## Context
当前统计页面使用 Chart.js 渲染折线图和饼图,但存在以下技术问题:
1. **折线图溢出**: 图表 canvas 尺寸计算未考虑容器边界,导致图表绘制超出卡片范围
2. **时间范围显示**: 折线图 X 轴显示整个自然周期(如整月),但数据仅到当前日期,导致后半段为平直线
3. **饼图标签**: 当前饼图使用图例(legend)展示分类,用户需要在图例和图表间来回查看
项目使用 Vue 3 + Chart.js + vue-chartjs 技术栈,图表配置通过 `useChartTheme` composable 统一管理。
## Goals / Non-Goals
**Goals:**
- 实现图表在容器内的自适应布局,无溢出
- 折线图动态计算数据截止时间,仅显示有效数据范围
- 饼图扇区直接渲染分类名称标签
- 保持现有主题配置和响应式行为
**Non-Goals:**
- 不更换图表库(保持 Chart.js
- 不修改数据 API 或数据结构
- 不添加新的图表类型
- 不影响其他页面的图表显示
## Decisions
### 1. 布局约束方案: CSS 容器 + Chart.js responsive 配置
- **选择**: 结合 CSS `overflow: hidden` 和 Chart.js `maintainAspectRatio: false` + `responsive: true`
- **理由**: 利用 Chart.js 内置的响应式机制,同时通过 CSS 确保容器边界约束
- **替代方案**: 手动计算 canvas 尺寸(复杂,需监听 resize
### 2. 折线图数据过滤: 前端日期截断
- **选择**: 在组件内根据当前日期过滤数据数组,仅传递有效数据给 Chart.js
- **理由**: 最小化改动,不修改 API保持数据完整性以备他用
- **替代方案**: 后端 API 支持日期参数(需后端改动,过度设计)
### 3. 饼图标签方案: Chart.js datalabels 插件
- **选择**: 使用 `chartjs-plugin-datalabels` 插件在扇区上渲染标签
- **理由**: 官方推荐方案,支持自动位置计算和碰撞检测
- **替代方案**: 自定义绘制(复杂,需处理重叠)
## Risks / Trade-offs
| Risk | Mitigation |
|------|------------|
| 饼图标签在扇区过小时显示不全 | 设置最小扇区角度阈值,小分类合并为"其他" |
| 暗色模式切换时标签颜色适配 | 通过 `useChartTheme` 动态计算对比色 |
| 性能影响datalabels 插件) | 仅在饼图启用,监控渲染耗时 |
## Migration Plan
无需迁移,纯视觉修复,向后兼容。
## Open Questions
- 饼图标签在移动端小屏幕上的显示策略(待实现时验证)

View File

@@ -0,0 +1,29 @@
## Why
统计页面的图表存在两个影响用户体验的显示问题:折线图超出卡片边界且显示未来日期的平直线段,饼图缺少直接的分类标签展示。这些问题降低了数据可视化的直观性和美观度,需要修复以提升用户查看统计数据的体验。
## What Changes
- 修复折线图Line Chart在统计卡片中的溢出布局问题确保图表完全包含在卡片边界内
- 修改折线图数据截止时间逻辑,从显示完整自然周期(如整月)改为仅显示至当前日期,避免未来日期形成无意义的平直线段
- 优化支出分类饼图Pie Chart在饼图扇区上直接显示分类名称标签提升可读性
## Capabilities
### New Capabilities
- `chart-layout-constraint`: 图表在容器内的自适应布局和边界约束控制
- `chart-data-filtering`: 基于当前日期的动态数据过滤和范围控制
- `chart-label-overlay`: 饼图扇区上的直接标签渲染和位置计算
### Modified Capabilities
- (无现有能力需要修改需求)
## Impact
- **受影响组件**:
- `Web/src/components/Charts/BaseChart.vue` - 基础图表组件
- `Web/src/views/Statistics/` 下的统计页面组件
- `Web/src/composables/useChartTheme.ts` - 图表主题配置
- **图表库**: Chart.js 配置选项调整
- **无API变更**: 纯前端显示层修复
- **向后兼容**: 无破坏性变更

View File

@@ -0,0 +1,21 @@
## ADDED Requirements
### Requirement: Line chart date range truncation
The line chart SHALL display data only up to the current date, not the full natural period.
#### Scenario: Monthly view shows data to current day
- **GIVEN** today is the 15th of the month
- **WHEN** the user views the monthly statistics chart
- **THEN** the chart SHALL display data from the 1st to the 15th only
- **AND** the X-axis SHALL NOT show dates beyond the current day
#### Scenario: Weekly view shows data to current day
- **GIVEN** today is Wednesday
- **WHEN** the user views the weekly statistics chart
- **THEN** the chart SHALL display data from Monday to Wednesday only
- **AND** no flat line segments SHALL appear for future dates
#### Scenario: Yearly view shows data to current month
- **GIVEN** today is in June
- **WHEN** the user views the yearly statistics chart
- **THEN** the chart SHALL display data from January to June only

View File

@@ -0,0 +1,21 @@
## ADDED Requirements
### Requirement: Pie chart direct category labeling
The pie chart SHALL display category names directly on or adjacent to their corresponding sectors.
#### Scenario: Category labels rendered on pie sectors
- **WHEN** the expense category pie chart is displayed
- **THEN** each sector SHALL display its category name as a label
- **AND** the label SHALL be positioned to not obscure the sector
#### Scenario: Labels adapt to sector size
- **GIVEN** a category represents less than 5% of total expenses
- **WHEN** the pie chart renders
- **THEN** the label for that small sector MAY be hidden to avoid clutter
- **AND** the category SHALL still be identifiable via tooltip on hover
#### Scenario: Label visibility in dark mode
- **GIVEN** the application is in dark mode
- **WHEN** the pie chart displays labels on sectors
- **THEN** the label text color SHALL provide sufficient contrast against the sector color
- **AND** labels SHALL remain readable against both light and dark sector colors

View File

@@ -0,0 +1,14 @@
## ADDED Requirements
### Requirement: Chart container boundary enforcement
The chart SHALL be fully contained within its parent card container without overflow.
#### Scenario: Chart renders within card boundaries
- **WHEN** the statistics page displays a line chart in a card component
- **THEN** the chart canvas SHALL NOT extend beyond the card's padding boundaries
- **AND** the chart SHALL adapt to container resize events
#### Scenario: Chart adapts to mobile viewport
- **WHEN** the viewport width is less than 375px
- **THEN** the chart SHALL scale down proportionally
- **AND** no horizontal scrolling SHALL be required to view the full chart

View File

@@ -0,0 +1,27 @@
## 1. 图表布局修复
- [x] 1.1 检查 BaseChart.vue 响应式配置,确保 maintainAspectRatio: false 和 responsive: true
- [x] 1.2 为统计卡片添加 CSS 约束,设置 overflow: hidden 和固定高度
- [x] 1.3 验证图表在移动端(<375px下正常缩放无溢出
## 2. 折线图数据过滤
- [x] 2.1 在统计页面组件中添加当前日期获取逻辑
- [x] 2.2 实现数据过滤函数,根据周期类型(日/周/月/年)截断未来日期数据
- [x] 2.3 更新折线图数据传递,仅传递过滤后的数据
- [x] 2.4 验证 X 轴不再显示未来日期
## 3. 饼图标签渲染
- [x] 3.1 安装 chartjs-plugin-datalabels 插件
- [x] 3.2 在 useChartTheme.ts 中添加饼图标签配置
- [x] 3.3 实现标签位置计算和扇区大小阈值控制(<5% 隐藏标签)
- [x] 3.4 添加暗色模式下的标签颜色适配逻辑
- [x] 3.5 验证标签在各类别扇区上正确显示
## 4. 测试与验证
- [x] 4.1 运行前端 lint 检查
- [x] 4.2 在桌面端验证所有图表显示正常
- [x] 4.3 在移动端验证响应式布局
- [x] 4.4 验证暗色模式下图表标签可读性