topfans/docs/figma-analysis-data-dashboard.md
2026-06-02 17:35:44 +08:00

733 lines
29 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.

# 数据看板页面 - 完整设计文档
> **Figma Source**: [数据看板 - 节点 29-40](https://www.figma.com/design/EMJR1LQpXBnJNSfea4kq4o/数据看板?node-id=29-40)
> **页面名称**: 数据看板 / Data Dashboard
> **画板尺寸**: 375 × 1281 (iPhone 12/13/14)
> **版本**: 初版设计稿 v0.1
> **文档版本**: 1.0
> **最后更新**: 2026-06-02
---
## 〇、文档概览
| 项目 | 内容 |
|------|------|
| 目标用户 | 已入驻顶粉星城的活跃用户 |
| 核心价值 | 让用户一目了然地看到自己的水晶收益、藏品表现、升级进度 |
| 页面定位 | 粉丝应援类数据可视化页(与 square 排行、exhibition 展出、tasks 任务并列) |
| 入口位置 | 个人中心 / 顶部 Banner 入口 / 任务完成跳转 |
| 主要功能 | 6 大模块水晶概览、7日曲线、展出收益、点赞收益、藏品矩阵、升级进度 |
| 技术栈 | Vue + uni-app前端 / Go + gRPC后端galleryService + userService |
---
## 一、页面布局结构
```
┌──────────────────────────────────────┐ 0px
│ ⌚ iPhone Status Bar │ 44px
├──────────────────────────────────────┤
│ 🟣 毛绒怪头像 "数据看板" 渐变标题 │ 77px
│ [水晶相关] [赛季总览] Tab 切换 │ 133px
│ ╭──────────╮ ╭──────────╮ │
│ │ 水晶余额 │ │ 今日收益 │ │ 184px
│ │ 2713 │ │ + 213 │ │
│ ╰──────────╯ ╰──────────╯ │
├──────────────────────────────────────┤
│ 📈 七日收益曲线 │ 184-288px
│ + 312 2026.06.01 柱状+折线图 │
├──────────────────────────────────────┤
│ 🖼 展出收益中心 │ 295px
│ 21/33 712:13:56 39721 │ 顶部3联统计
│ ┌──┬─────────┬──────┬──────┐ │
│ │图│144:13:56│ 2173 │ 15/H │ │ 5行藏品表格
│ │图│ 77:13:56│ 1332 │ 15/H │ │
│ │图│ 64:15:37│ 1201 │ 12/H │ │
│ │图│ 51:22:12│ 783 │ 12/H │ │
│ │图│ 51:22:12│ 783 │ 12/H │ │
│ └──┴─────────┴──────┴──────┘ │
├──────────────────────────────────────┤
│ ❤️ 点赞收益看板 │ 580px
│ 累积点赞 231 │ 等级 │ 收益 │
│ 累计收益 12719 │ UR │ 723 │
│ │ SSR │ 381 │
│ │ SR │ 233 │
│ │ SR │ 169 │
│ │ R │ 57 │
├──────────────────────────────────────┤
│ 🏆 藏品矩阵 │ 870px
│ ┌─ 历史藏品收益TOP5 ──────────────┐ │
│ │ [图1] [图2] [图3] [图4] [图5] │ │
│ │ TOP1 TOP2 TOP3 TOP4 TOP5 │ │
│ └─────────────────────────────────┘ │
│ ┌─ 藏品等级分布(环形) ──────────┐ │
│ │ ⓤ ⓢ ⓢ ⓡ ⓝ │ │
│ │ 1 2 5 6 0 │ │
│ │ 3% 6% 13% 17% 0% │ │
│ └─────────────────────────────────┘ │
│ ┌─ 即将升级藏品 ┐ ┌─ 最近升级藏品 ┐│
│ │ [图1] 73%/92% │ │ [图1] Lv UP ││
│ │ [图2] 75%/96% │ │ [图2] Lv UP ││
│ │ [图3] 97%/71% │ │ [图3] Lv UP ││
│ └───────────────┘ └────────────────┘│
└──────────────────────────────────────┘ 1281px
```
---
## 二、核心组件详解
### 2.1 状态栏 (iPhone=Status Bar)
- 引用 Figma Component Set `11:6` (Iphone) 的 `11:7` 实例
- 高 44px黑底白字y: 0-44
### 2.2 顶部装饰区 (y: 77-178)
| 元素 | 类型 | 位置 (x, y) | 尺寸 | 关键样式 |
|------|------|-------------|------|----------|
| 毛绒怪头像 | 图片 | (141, 77) | 104×99 | 红色模糊阴影 `box-shadow: 2px 2px 4px rgba(242, 21, 21, 0.47)` + 模糊 `blur(29.8px)` |
| "数据看板" 标题 | 文字 | (229, 37) | 127×33 | 渐变文字 + 黑色投影 |
| Tab 1 - 水晶相关 | 文字 | (165, 92) | 60×18 | Inter Bold 15px, 白字+阴影 |
| Tab 2 - 赛季总览 | 文字 | (275, 101) | 60×18 | 同上 |
| Tab 胶囊背景 | 渐变矩形 | (16, 133) (192, 133) | 168×45 | 紫蓝粉渐变 `231deg, #A8A6ED → #88C8D8 → #F380EF` |
| 装饰光晕 | 渐变 + 模糊 | (0, -350) | 375×2393 | `linear-gradient(179deg, #FFE5E5 → #F3A0A1 → #FF9C9C 86% → #FF2024)` + `blur(4px)` |
### 2.3 数据卡片 - 双列 (y: 184-288)
| 字段 | 数值 | 字体 | 颜色 | 阴影 |
|------|------|------|------|------|
| 水晶余额 | 2713 | Baloo Bhai 35px | #FFFABD 金黄 | `-1px 1px 4px rgba(206, 9, 9, 0.84)` |
| 今日收益 | + 213 | Baloo Bhai 35px | #FFFABD | 同上 |
| 标签 - 水晶余额 | - | Inter Medium 12px | #FFFFFF | `0px 4px 4px rgba(164, 60, 60, 0.55)` |
| 标签 - 今日收益 | - | 同上 | 同上 | 同上 |
### 2.4 七日收益曲线 (y: 184-288)
- **背景**: 渐变卡片 `135deg, #FFDF77 → #8E95E2 → #F48CFF` + 红色投影
- **柱状图**: 3 根渐变柱(左下到右上排列)尺寸 106×40px
- 柱 1 渐变: `135deg, #FFDF77 → #B984FF → #FF8183`
- **折线 + 高亮**: 蓝黄渐变线 `90deg, #1BAFEE → #FFCC14`
- 高亮点数据: `+ 312` (2026.06.01)
- **日期标签**: "2026.06.01" - Inter 9px
- **标题**: "七日收益曲线" - Inter 12px Medium
### 2.5 展出收益中心 (y: 295-574)
- **标题**: "展出收益中心" - Inter Bold 18px
- **装饰圆点**: Ellipse 4 (装饰性发光圆)
- **3 联顶部统计**:
| 字段 | 数值 | 字体 |
|------|------|------|
| 展出中/星册中 | 21 / 33 | Baloo Bhai 14px |
| 累计展出时长 | 712:13:56 | Baloo Bhai 14px |
| 累计展出收益 | 39721 | Baloo Bhai 14px |
- **数据表格**5行
| 七日展出时长 | 七日收益 | 平均收益 |
| 144:13:56 | 2173 | 15 / H |
| 77:13:56 | 1332 | 15 / H |
| 64:15:37 | 1201 | 12 / H |
| 51:22:12 | 783 | 12 / H |
| 51:22:12 | 783 | 12 / H |
- 每行左侧 4×5 网格布局的藏品缩略图3px 圆角5 种渐变 fill
### 2.6 点赞收益看板 (y: 580-870)
- **标题**: "点赞收益看板" - Inter Bold 18px
- **左侧双统计**:
- 累积点赞次数: `231` (Baloo Bhai 18px)
- 累计点赞收益: `12719` (Baloo Bhai 18px)
- **右侧等级列表**:
| 藏品 | 等级 | 水晶收益 |
| [图] | UR | 723 |
| [图] | SSR | 381 |
| [图] | SR | 233 |
| [图] | SR | 169 |
| [图] | R | 57 |
- 等级徽章有 5 种不同的渐变背景
### 2.7 藏品矩阵 (y: 870-1281)
#### 2.7.1 历史藏品收益TOP5
- 5 张缩略图水平排列,间距均匀
- 每张图下方有渐变 TOP 徽章 (TOP 1 ~ TOP 5)
- 徽章背景: `opacity 0.66` 渐变 + 投影
#### 2.7.2 藏品等级分布(环形进度图)
- 5 个圆形,分别对应 UR/SSR/SR/R/N 等级
- 数据(中心数字 + 百分比):
- UR: 1 (3%)
- SSR: 2 (6%)
- SR: 5 (13%)
- R: 6 (17%)
- N: 0 (0%)
- 圆环粗细: 17px外环/ 5px内环发光效果
#### 2.7.3 即将升级藏品左列3 行)
- 每行结构: 藏品缩略图 + 双进度条
- 进度条颜色:
- 上行(获赞数): `90deg, #5EDFFF → #FFC8C8` 渐变
- 下行(展出时长): `90deg, #FFF375 → #FF6B84` 渐变
- 进度条背景: `rgba(217, 217, 217, 0.2)`
- 当前显示数据:
- 藏品1: 73% / 92%
- 藏品2: 75% / 96%
- 藏品3: 97% / 71%
#### 2.7.4 最近升级藏品右列3 行)
- 每行结构: 藏品缩略图 + "Lv UP" 文字 + 等级徽章
- 等级徽章顺序(自上而下): SSR、SR、SR
---
## 三、设计令牌Design Tokens
### 3.1 颜色
| Token | 值 | 用途 |
|------|------|------|
| `--color-bg-gradient` | `linear-gradient(153deg, #FF9597 0%, #80DFFF 33%, #B8B8B8 74%, #D9D9D9 100%)` | 页面主背景 |
| `--color-text-primary` | `#FFFFFF` | 主文字 |
| `--color-text-data` | `#FFFABD` | 数字(水晶、收益) |
| `--color-text-dark` | `#000000` | 状态栏 |
| `--color-tab-active` | `linear-gradient(231deg, #A8A6ED 0%, #88C8D8 64%, #F380EF 100%)` | Tab 选中态 |
| `--color-tab-bg-1` | `linear-gradient(135deg, #FFDF77 0%, #8E95E2 40%, #F48CFF 100%)` | 卡片 1水晶 |
| `--color-tab-bg-2` | `linear-gradient(137deg, #FFDF77 0%, #8E95E2 40%, #F48CFF 100%)` + 蓝绿红 | 卡片 2今日收益 |
| `--color-progress-pink` | `linear-gradient(90deg, #FFF375 0%, #FF6B84 100%)` | 进度条 |
| `--color-progress-cyan` | `linear-gradient(90deg, #5EDFFF 0%, #FFC8C8 100%)` | 进度条 |
| `--color-bar-blue-yellow` | `linear-gradient(90deg, #1BAFEE 0%, #FFCC14 100%)` | 折线/柱状图 |
### 3.2 阴影
| Token | 值 | 用途 |
|------|------|------|
| `--shadow-card` | `0px 4px 4px rgba(189, 50, 50, 0.25)` | 卡片通用阴影 |
| `--shadow-data-text` | `-1px 1px 4px rgba(206, 9, 9, 0.84)` | 数字文字阴影 |
| `--shadow-mascot` | `2px 2px 4px rgba(242, 21, 21, 0.47) blur(29.8px)` | 头像光晕 |
| `--shadow-tab` | `0px 4px 4px rgba(0, 0, 0, 0.25)` | Tab 胶囊阴影 |
| `--shadow-inner-card` | `0px 4px 4px rgba(96, 13, 13, 0.25)` | 内嵌卡片阴影 |
| `--blur-bg` | `blur(4px)` | 背景模糊 |
| `--blur-mascot` | `blur(29.8px)` | 头像发光模糊 |
| `--blur-portrait` | `blur(68.7px)` | 装饰人物模糊 |
### 3.3 圆角
| Token | 值 | 用途 |
|------|------|------|
| `--radius-thumb` | 3px | 藏品缩略图 |
| `--radius-progress` | 6px | 进度条 |
| `--radius-top-badge` | 8px | TOP 徽章 |
| `--radius-card-sm` | 14px | 小卡片 |
| `--radius-card-md` | `17px 14px 14px 14px` | 主卡片(异形) |
| `--radius-card-lg` | 22px | 胶囊/大容器 |
### 3.4 字体
| Token | 字体 | 字号 | 字重 | 用途 |
|------|------|------|------|------|
| `--font-num-xl` | Baloo Bhai | 35px | 400 | 顶部水晶/收益数字 |
| `--font-num-lg` | Baloo Bhai | 18px | 400 | 点赞统计数字 |
| `--font-num-md` | Baloo Bhai | 14px | 400 | 表格数字 |
| `--font-num-sm` | Baloo Bhai | 9px | 400 | 进度条百分比 |
| `--font-title-lg` | Inter | 18-20px | 700 | 模块大标题("展出收益中心" |
| `--font-title-md` | Inter | 15px | 700 | Tab 文字 |
| `--font-label` | Inter | 12px | 500 | 字段标签 |
| `--font-stat-label` | Baloo Bhai | 5-9px | 400 | 进度条小标签("获赞数"等) |
### 3.5 间距
| Token | 值 | 用途 |
|------|------|------|
| `--space-card-pad` | 16px | 卡片外边距(左右) |
| `--space-card-pad-y` | 8px | 卡片内边距(上下) |
| `--space-section` | 24px | 模块间垂直间距 |
| `--space-cell` | 12px | 表格行间距 |
---
## 四、数据模型与 API 设计
### 4.1 数据来源
设计稿中需要的数据均已存在于 backend 现有 proto 中,本节梳理 **复用 + 新增** 接口。
| 模块 | 数据 | 数据源 proto | 是否需要新增 |
|------|------|-------------|------------|
| 水晶余额 | `crystal_balance` | `user.proto::FanProfile.crystal_balance` | ❌ 复用 |
| 今日收益 | `+ 213` | 新增 `daily_income` 聚合字段 | ✅ 新增 |
| 七日收益曲线 | 7 天 daily 数据 | 新增接口 `Get7DayIncomeCurve` | ✅ 新增 |
| 展出收益中心 | 顶部 3 联 | 聚合 `gallery.proto` + `task.proto::ExhibitionRevenueItem` | ✅ 新增聚合 |
| 展出收益 - 表格 5 行 | 5 条按收益排序的展出记录 | 复用 `task.proto::ExhibitionRevenueItem` | ❌ 复用(限定 limit=5 |
| 点赞收益 - 累计 | 点赞总数、收益总数 | 复用 `gallery.proto::AssetInfo.like_count/earnings` | ❌ 复用 |
| 点赞收益 - 等级 | 按等级分组的点赞收益 | 新增接口 `GetLikeIncomeByLevel` | ✅ 新增 |
| 藏品矩阵 - TOP5 | 收益前 5 藏品 | 新增接口 `GetTopAssetsByEarning` | ✅ 新增 |
| 藏品矩阵 - 等级分布 | 各等级数量 | 新增接口 `GetAssetLevelDistribution` | ✅ 新增 |
| 即将升级藏品 | 升级进度数据 | 新增接口 `GetUpcomingLevelUpAssets` | ✅ 新增 |
| 最近升级藏品 | 最近升级记录 | 新增接口 `GetRecentLevelUpAssets` | ✅ 新增 |
### 4.2 新增 Proto 定义(建议)
> 新增位置: `backend/proto/dashboard.proto`(新建文件)
```protobuf
syntax = "proto3";
package dashboard;
option go_package = "github.com/topfans/backend/pkg/proto/dashboard";
// ============ 数据看板聚合接口 ============
// 七日收益曲线
message Get7DayIncomeCurveRequest {
int64 user_id = 1;
int64 star_id = 2; // 顶粉星城 ID区分赛季
}
message DailyIncomePoint {
string date = 1; // "2026.05.27"
int64 income = 2; // 当日收益
bool is_today = 3; // 是否今日
bool is_peak = 4; // 是否 7 日最高(用于高亮显示)
}
message Get7DayIncomeCurveResponse {
repeated DailyIncomePoint points = 1;
int64 total_income = 2; // 7 日累计
int64 avg_income = 3; // 7 日日均
}
// 今日收益概览
message GetTodayOverviewRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message GetTodayOverviewResponse {
int64 crystal_balance = 1; // 水晶余额
int64 today_income = 2; // 今日收益
int32 week_rank = 3; // 本周排名(可选)
}
// 展出收益中心聚合
message GetExhibitionIncomeSummaryRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message ExhibitionIncomeSummary {
int32 exhibiting_count = 1; // 展出中数量
int32 starbook_count = 2; // 星册中数量
string total_duration = 3; // "712:13:56"
int64 total_earnings = 4; // 39721
repeated TopExhibitionItem top5 = 5; // 表格 5 行
}
message TopExhibitionItem {
int64 asset_id = 1;
string asset_name = 2;
string asset_thumb = 3;
string duration_7d = 4; // "144:13:56"
int64 earnings_7d = 5; // 2173
int32 avg_earnings = 6; // 15 (单位: /H)
}
message GetExhibitionIncomeSummaryResponse {
ExhibitionIncomeSummary data = 1;
}
// 点赞收益按等级分组
message GetLikeIncomeByLevelRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message LikeIncomeLevelItem {
string level = 1; // "UR" / "SSR" / "SR" / "R" / "N"
int32 asset_count = 2;
int64 total_income = 3; // 723
string thumb = 4; // 第一个该等级藏品的缩略图
}
message GetLikeIncomeByLevelResponse {
int64 total_like_count = 1; // 累积点赞次数
int64 total_income = 2; // 累计点赞收益
repeated LikeIncomeLevelItem levels = 3;
}
// 藏品矩阵 - 历史 TOP5
message GetTopAssetsByEarningRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message TopAssetItem {
int64 asset_id = 1;
string asset_name = 2;
string asset_thumb = 3;
int64 total_earnings = 4;
int32 rank = 5; // 1-5
}
message GetTopAssetsByEarningResponse {
repeated TopAssetItem items = 1;
}
// 藏品矩阵 - 等级分布
message GetAssetLevelDistributionRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message AssetLevelItem {
string level = 1; // "UR"
int32 count = 2; // 1
int32 total = 3; // 33藏品总数用于计算百分比
}
message GetAssetLevelDistributionResponse {
repeated AssetLevelItem items = 1;
}
// 藏品矩阵 - 即将升级 / 最近升级
message GetAssetUpgradeProgressRequest {
int64 user_id = 1;
int64 star_id = 2;
}
message UpcomingLevelUpItem {
int64 asset_id = 1;
string asset_name = 2;
string asset_thumb = 3;
int32 like_progress = 4; // 73
int32 duration_progress = 5; // 92
}
message RecentLevelUpItem {
int64 asset_id = 1;
string asset_name = 2;
string asset_thumb = 3;
string new_level = 4; // "SSR"
int64 upgrade_time = 5; // ms timestamp
}
message GetAssetUpgradeProgressResponse {
repeated UpcomingLevelUpItem upcoming = 1;
repeated RecentLevelUpItem recent = 2;
}
// ============ Service 定义 ============
service DashboardService {
rpc GetTodayOverview(GetTodayOverviewRequest) returns (GetTodayOverviewResponse);
rpc Get7DayIncomeCurve(Get7DayIncomeCurveRequest) returns (Get7DayIncomeCurveResponse);
rpc GetExhibitionIncomeSummary(GetExhibitionIncomeSummaryRequest) returns (GetExhibitionIncomeSummaryResponse);
rpc GetLikeIncomeByLevel(GetLikeIncomeByLevelRequest) returns (GetLikeIncomeByLevelResponse);
rpc GetTopAssetsByEarning(GetTopAssetsByEarningRequest) returns (GetTopAssetsByEarningResponse);
rpc GetAssetLevelDistribution(GetAssetLevelDistributionRequest) returns (GetAssetLevelDistributionResponse);
rpc GetAssetUpgradeProgress(GetAssetUpgradeProgressRequest) returns (GetAssetUpgradeProgressResponse);
}
```
### 4.3 后端实现位置
| 新服务 | 路径 | 备注 |
|------|------|------|
| `dashboardService` | `backend/services/dashboardService/` | 全新服务,参考 `galleryService` 目录结构 |
| 聚合查询 | `service/dashboard_service.go` | 主要逻辑 |
| 数据访问 | `repository/dashboard_repository.go` | 跨表聚合exhibition + asset + crystal_log |
| Proto | `backend/proto/dashboard.proto` | 新建 |
| 路由 | `backend/gateway/router/router.go` | `/api/v1/dashboard/*` 网关路由 |
| Controller | `backend/gateway/controller/dashboard_controller.go` | HTTP 网关层 |
### 4.4 数据来源 SQL 聚合(伪代码)
```sql
-- 七日收益曲线
SELECT
DATE(FROM_UNIXTIME(created_at/1000)) AS date,
SUM(crystal_change) AS income
FROM crystal_log
WHERE user_id = ? AND star_id = ?
AND created_at >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) * 1000
AND change_type IN ('exhibition_revenue', 'level_up_bonus')
GROUP BY DATE(FROM_UNIXTIME(created_at/1000))
ORDER BY date ASC;
-- 展出收益中心聚合
SELECT
COUNT(DISTINCT CASE WHEN e.status='active' THEN e.id END) AS exhibiting_count,
COUNT(DISTINCT CASE WHEN e.status='starbook' THEN e.id END) AS starbook_count,
SUM(e.accumulated_duration) AS total_duration,
SUM(e.accumulated_earnings) AS total_earnings
FROM exhibitions e
WHERE e.user_id = ? AND e.star_id = ?;
-- 点赞收益按等级
SELECT
a.level,
COUNT(DISTINCT a.id) AS asset_count,
SUM(li.crystal_amount) AS total_income
FROM assets a
LEFT JOIN like_income_log li ON li.asset_id = a.id AND li.user_id = a.user_id
WHERE a.user_id = ? AND a.star_id = ?
GROUP BY a.level
ORDER BY FIELD(a.level, 'UR', 'SSR', 'SR', 'R', 'N');
-- 藏品等级分布
SELECT
a.level,
COUNT(*) AS count,
(SELECT COUNT(*) FROM assets WHERE user_id = ? AND star_id = ?) AS total
FROM assets a
WHERE a.user_id = ? AND a.star_id = ?
GROUP BY a.level;
-- 即将升级藏品(按升级进度倒序,取前 3
SELECT a.id, a.name, a.thumb, a.like_progress, a.duration_progress
FROM assets a
WHERE a.user_id = ? AND a.star_id = ? AND a.like_progress < 100
ORDER BY GREATEST(a.like_progress, a.duration_progress) DESC
LIMIT 3;
-- 最近升级藏品(升级时间倒序)
SELECT a.id, a.name, a.thumb, a.level, a.upgrade_time
FROM asset_upgrade_log aul
JOIN assets a ON a.id = aul.asset_id
WHERE aul.user_id = ? AND aul.star_id = ?
ORDER BY aul.upgrade_time DESC
LIMIT 3;
```
---
## 五、前端实现
### 5.1 目录结构
```
frontend/
├── pages/
│ └── dashboard/
│ ├── dashboard.vue # 主页面
│ └── components/
│ ├── DashboardHeader.vue # 顶部装饰 + Tab
│ ├── CrystalOverview.vue # 顶部双卡(水晶余额+今日收益)
│ ├── IncomeCurve.vue # 七日收益曲线
│ ├── ExhibitionCenter.vue # 展出收益中心
│ ├── LikeIncomeBoard.vue # 点赞收益看板
│ ├── CollectionMatrix.vue # 藏品矩阵容器
│ ├── TopFiveAssets.vue # 历史 TOP5
│ ├── LevelDistribution.vue # 等级分布环形图
│ ├── UpcomingUpgrades.vue # 即将升级(左)
│ └── RecentUpgrades.vue # 最近升级(右)
├── api/
│ └── dashboard.js # API 封装
├── store/
│ └── modules/
│ └── dashboard.js # Vuex 模块
└── static/
└── dashboard/
├── mascot-star.png # 毛绒怪头像
├── tab-bg-active.png # Tab 选中态背景
├── progress-cyan.png # 青粉进度条
├── progress-pink.png # 黄红进度条
└── top-badge.png # TOP 徽章
```
### 5.2 组件职责拆分
| 组件 | 职责 | Props | 关键状态 |
|------|------|-------|----------|
| `dashboard.vue` | 页面容器,负责 Tab 切换和数据请求分发 | - | `activeTab: 'crystal' \| 'season'` |
| `DashboardHeader` | 装饰背景 + 标题 + Tab | - | - |
| `CrystalOverview` | 显示水晶余额+今日收益 | `{ balance, today }` | - |
| `IncomeCurve` | 七日柱状+折线图 | `{ points, peak }` | - |
| `ExhibitionCenter` | 顶部 3 联 + 5 行表格 | `{ summary }` | - |
| `LikeIncomeBoard` | 左侧统计 + 右侧等级列表 | `{ stats, levels }` | - |
| `CollectionMatrix` | 嵌套 4 个子组件 | `{ topFive, levels, upcoming, recent }` | - |
| `TopFiveAssets` | TOP5 水平卡片 | `{ items }` | - |
| `LevelDistribution` | 5 个环形图 | `{ levels }` | - |
| `UpcomingUpgrades` | 进度条列表 | `{ items }` | - |
| `RecentUpgrades` | Lv UP 列表 | `{ items }` | - |
### 5.3 API 封装(`frontend/api/dashboard.js`
```javascript
import request from '@/utils/request';
const PREFIX = '/api/v1/dashboard';
export const dashboardApi = {
// 今日收益概览
getTodayOverview: (starId) =>
request.get(`${PREFIX}/today-overview`, { params: { star_id: starId } }),
// 七日收益曲线
get7DayIncomeCurve: (starId) =>
request.get(`${PREFIX}/income-curve`, { params: { star_id: starId } }),
// 展出收益中心
getExhibitionSummary: (starId) =>
request.get(`${PREFIX}/exhibition-summary`, { params: { star_id: starId } }),
// 点赞收益按等级
getLikeIncomeByLevel: (starId) =>
request.get(`${PREFIX}/like-income-by-level`, { params: { star_id: starId } }),
// 藏品 TOP5
getTopAssets: (starId) =>
request.get(`${PREFIX}/top-assets`, { params: { star_id: starId } }),
// 藏品等级分布
getLevelDistribution: (starId) =>
request.get(`${PREFIX}/level-distribution`, { params: { star_id: starId } }),
// 升级进度(即将+最近)
getUpgradeProgress: (starId) =>
request.get(`${PREFIX}/upgrade-progress`, { params: { star_id: starId } }),
};
```
### 5.4 Vuex Store 模块(`frontend/store/modules/dashboard.js`
```javascript
import { dashboardApi } from '@/api/dashboard';
const state = () => ({
loading: false,
activeTab: 'crystal', // 'crystal' | 'season'
currentStarId: null, // 当前顶粉星城 ID
today: { balance: 0, income: 0 },
incomeCurve: [],
exhibitionSummary: null,
likeIncome: { total: 0, income: 0, levels: [] },
topAssets: [],
levelDistribution: [],
upgradeProgress: { upcoming: [], recent: [] },
});
const actions = {
async loadAll({ commit, state }) {
commit('setLoading', true);
try {
const starId = state.currentStarId;
const [today, curve, exh, like, top, level, up] = await Promise.all([
dashboardApi.getTodayOverview(starId),
dashboardApi.get7DayIncomeCurve(starId),
dashboardApi.getExhibitionSummary(starId),
dashboardApi.getLikeIncomeByLevel(starId),
dashboardApi.getTopAssets(starId),
dashboardApi.getLevelDistribution(starId),
dashboardApi.getUpgradeProgress(starId),
]);
commit('setToday', today);
commit('setIncomeCurve', curve.points);
commit('setExhibitionSummary', exh);
commit('setLikeIncome', like);
commit('setTopAssets', top.items);
commit('setLevelDistribution', level.items);
commit('setUpgradeProgress', up);
} finally {
commit('setLoading', false);
}
},
// ... mutations
};
export default { namespaced: true, state, actions, mutations };
```
### 5.5 pages.json 注册
`frontend/pages.json``pages` 数组中添加:
```json
{
"path": "pages/dashboard/dashboard",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "数据看板",
"app-plus": { "bounce": "none" }
}
}
```
### 5.6 关键技术点
| 点 | 实现方式 |
|------|------|
| 七日柱状图 | 使用 Canvas 2D 手绘(轻量);或引入 `uCharts`(如果项目未引入,需评估) |
| 环形进度图 | CSS `conic-gradient` 实现 5 种等级环(无需额外依赖) |
| 渐变文字 | `-webkit-background-clip: text; color: transparent` |
| 玻璃拟态 | `backdrop-filter: blur(10px)` + 半透明白色背景 |
| Tab 切换 | 简单 v-show不做路由切换页面无滚动状态保持 |
| 数据懒加载 | 首屏只请求前 3 个接口,滚动到底部再请求矩阵接口 |
| 空数据 | 所有模块必须有空态(暂无数据插画 + 引导文案) |
---
## 六、实施计划
### 6.1 阶段划分
| 阶段 | 内容 | 工期估算 | 验收 |
|------|------|----------|------|
| **M1 - 后端基础** | 创建 `dashboard.proto`、实现 7 个 RPC、SQL 聚合、单元测试 | 3 天 | gRPC 接口联调通过 |
| **M2 - 前端骨架** | `pages.json` 注册、空页面路由、Vuex 模块、API 封装 | 1 天 | 页面可访问loading 态正常 |
| **M3 - 模块实现 P1** | Header + CrystalOverview + IncomeCurve顶部三模块 | 2 天 | 视觉稿 1:1 还原 |
| **M4 - 模块实现 P2** | ExhibitionCenter + LikeIncomeBoard | 2 天 | 视觉稿 1:1 还原 |
| **M5 - 模块实现 P3** | CollectionMatrix含 4 个子组件) | 3 天 | 视觉稿 1:1 还原 |
| **M6 - 联调优化** | 接口联调、空态、错误处理、动效打磨 | 2 天 | 全链路通过 |
| **总计** | | **13 工作日** | |
### 6.2 依赖与风险
| 风险 | 影响 | 应对 |
|------|------|------|
| 7 日曲线跨表聚合性能 | M1 阶段 | 加索引 `crystal_log(user_id, star_id, created_at)` |
| uCharts 体积(如果引入) | 包体积+200KB | 优先 Canvas 手绘,复杂图表才用 uCharts |
| 藏品等级排序国际化 | 显示顺序 | 后端按 `FIELD()` 硬编码 UR > SSR > SR > R > N |
| 升级进度算法 | 业务复杂度 | 与产品确认升级公式(是点赞数+展出时长加权,还是分开的双进度条) |
| 资源下载 | 头像/徽章 | 用 `mcp__figma-developer-mcp__download_figma_images` 批量下载到 `static/dashboard/` |
### 6.3 验收清单
- [ ] 视觉还原1:1 还原 Figma 稿,色差 ΔE < 5
- [ ] 性能首屏 < 1.5s完整加载 < 3s
- [ ] 兼容性iOS 13+ / Android 7+
- [ ] 数据准确性 `tasks/revenue.vue` 页面的数字一致
- [ ] 空态所有模块有"暂无数据"占位
- [ ] 错误处理网络异常时 Toast 提示 + 重试按钮
- [ ] 加载态骨架屏Skeleton
- [ ] 单元测试核心 store action 覆盖率 > 80%
- [ ] E2E用 Playwright 跑通 1 条用户路径(进入页面 → 切换 Tab → 下拉刷新)
---
## 七、附录
### 7.1 资源文件清单
需要从 Figma 下载的素材:
- 毛绒怪头像: `mascot-star.png` (104×99)
- Tab 选中态背景: `tab-bg-active.png` (168×45)
- TOP 徽章: `top-badge-1~5.png` (80×33)
- 等级徽章: `level-badge-ur/ssr/sr/r/n.png` (40×40)
- 装饰人物图: `decoration-portrait.png` (580×296)
### 7.2 参考文档
- Figma 文件: [数据看板 - 节点 29-40](https://www.figma.com/design/EMJR1LQpXBnJNSfea4kq4o/数据看板?node-id=29-40)
- 现有 Figma 分析参考: `docs/figma-analysis-topfans-ranking.md`
- 收益相关 Proto: `backend/proto/task.proto`ExhibitionRevenueItem
- 用户水晶 Proto: `backend/proto/user.proto`FanProfile.crystal_balance
- 展出 Proto: `backend/proto/gallery.proto`ExhibitionService
### 7.3 后续可扩展
- 数据看板分享:生成海报图片分享到站外
- 7 日曲线交互:点击柱子查看当日收益明细弹窗
- 升级提醒:达到 95% 进度时推送通知
- 多赛季切换赛季结束后归档数据Tab 2 "赛季总览" 展示历史赛季
- 对比模式:本周 vs 上周水晶收益对比柱状图
---
**文档维护**: 任何与本页面相关的需求变更或技术调整,请同步更新本文档。
**负责人**: 待指派
**Review**: 待指派