status_text 标签系统设计方案
1. 概述
1.1 需求背景
用户在我的点赞作品页面需要看到每个作品的动态状态标签(如"屠榜顶流"、"火速破圈"等),用于直观展示作品的热度和表现。
1.2 实现方案
采用 后端计算返回 方案:由后端计算每个作品的 status_text 状态标签,前端直接展示。
1.3 优势
- 后端拥有完整的排行榜数据和用户行为数据,可准确计算
- 前端无需关心业务逻辑复杂度,保持轻量
- 状态计算逻辑集中,便于维护和修改
- 减少前后端字段依赖,减少数据冗余
2. 标签体系定义
2.1 标签分类
| 优先级 |
类型 |
说明 |
| T0 |
收益型 |
最高优先级,用户点赞后作品表现极佳 |
| T1 |
排名型 |
排行榜相关,作品在榜上表现优秀 |
| T3 |
状态型 |
涨粉速度,体现作品热度变化 |
| T4 |
状态型 |
涨粉速度,体现作品热度变化 |
2.2 标签详情
| 优先级 |
标签名 |
显示条件 |
背后逻辑 |
| T0 |
眼光拉满 |
用户点赞后,新增点赞≥50 且作品仍在展出 |
用户点赞后作品持续火热,用户收益已达峰值 |
| T1 |
屠榜顶流TopX |
排行榜排名为 1、2、3、4、5 |
作品稳居排行榜前五,顶级流量 |
| T1 |
第Y爆款 |
排行榜排名为 Y(10≥Y>5) |
作品进入排行榜前10但未进前5 |
| T1 |
排名破Z |
排行榜排名达到 Z(Z∈{20,50,100,200}) |
里程碑式突破,达到特定门槛 |
| T3 |
火速破圈 |
过去1小时新增点赞≥20 |
作品热度急剧上升中 |
| T4 |
小爆出圈 |
过去1小时新增点赞:20>新增点赞≥10 |
作品热度稳步上升 |
| T4 |
热度积累 |
过去1小时新增点赞:10>新增点赞≥5 |
作品热度温和增长 |
| T4 |
缓慢涨粉 |
过去1小时新增点赞:5>新增点赞≥0 |
作品热度缓慢增长 |
| - |
潜力待挖 |
无任何标签满足 |
默认状态,等待挖掘 |
2.3 优先级规则
当多个标签条件同时满足时,按优先级取最高级别(T0>T1>T3>T4)。
计算流程:
1. 检查 T0「眼光拉满」→ 满足则返回
2. 检查 T1 排名型(屠榜顶流/第Y爆款/排名破Z)→ 满足则返回
3. 检查 T3/T4 状态型(火速破圈/小爆出圈/热度积累/缓慢涨粉)→ 满足则返回
4. 默认返回「潜力待挖」
3. 后端接口设计
3.1 修改接口
| 接口 |
方法 |
说明 |
/api/v1/me/liked-assets |
GET |
获取我点赞的作品列表 |
3.2 响应新增字段
在 GetMyLikedAssets 接口的响应 items 数组元素中新增:
{
"asset_id": 12345,
"name": "作品名称",
"cover_url": "https://...",
"like_count": 1000,
"liked_at": "2026-05-26T10:00:00Z",
"earnings": 500.00,
"hourly_earnings": 10.00,
"is_lenticular": false,
"expire_at": "2026-05-27T10:00:00Z",
"status_text": "屠榜顶流Top3"
}
| 字段 |
类型 |
说明 |
| status_text |
string |
动态状态标签,默认「潜力待挖」 |
4. 后端实现设计
4.1 数据依赖
| 字段 |
来源 |
说明 |
| 用户点赞时间 |
liked_assets 表 |
用于计算用户点赞后新增点赞数 |
| 用户点赞后新增点赞数 |
likes 表聚合 |
用户点赞时刻起到当前时刻,作品累计新增点赞数 |
| 排行榜排名 |
ranking 或 likes 表 |
当前作品排名 |
| 过去1小时新增点赞 |
likes 表聚合 |
需要按时间窗口聚合 |
4.2 Service 层计算逻辑
// pkg/service/social_service.go
func (s *SocialService) GetMyLikedAssets(ctx context.Context, req *pbSocial.GetMyLikedAssetsRequest) (*pbSocial.GetMyLikedAssetsResponse, error) {
// 1. 获取用户点赞作品列表(JOIN exhibition 获取 start_time,避免 N+1)
items, total, hasMore := s.getLikedAssetsList(ctx, userID, page, pageSize)
assetIDs := extractAssetIDs(items)
// 2. 批量获取用户点赞时间
likedAtMap := s.batchGetUserLikedAtMap(ctx, userID, assetIDs)
// 3. 批量获取作品排名(排名数据变化不频繁,可加缓存)
rankMap := s.batchGetAssetRanks(ctx, assetIDs)
// 4. 批量获取过去1小时新增点赞
hourlyNewLikesMap := s.batchGetHourlyNewLikes(ctx, assetIDs)
// 5. 为每个作品计算 status_text
for _, item := range items {
item.UserLikedAt = likedAtMap[item.AssetId]
item.Rank = rankMap[item.AssetId]
item.HourlyNewLikes = hourlyNewLikesMap[item.AssetId]
item.StatusText = computeStatusText(item)
}
return resp, nil
}
性能优化说明:
| 优化项 |
优化前 |
优化后 |
收益 |
| exhibition 查询 |
循环内逐条查询(N 次) |
JOIN 一次获取 |
30 次查询 → 1 次 |
| 排名查询 |
- |
批量 IN 查询 |
1 次 |
| 小时级新增点赞 |
- |
批量聚合查询 |
1 次 |
关键索引建议:
likes.asset_id + likes.created_at(联合索引,时间窗口聚合)
likes.asset_id + likes.created_at + user_id(用户点赞后新增统计)
exhibitions.asset_id + exhibitions.deleted_at(JOIN 优化)
4.3 status_text 计算函数
func computeStatusText(item *LikedAssetItem) string {
// T0: 眼光拉满
if item.UserLikedCountAfter >= 50 && !item.IsExpired {
return "眼光拉满"
}
// T1: 排名型
switch {
case item.Rank >= 1 && item.Rank <= 5:
return fmt.Sprintf("屠榜顶流Top%d", item.Rank)
case item.Rank > 5 && item.Rank <= 10:
return fmt.Sprintf("第%d爆款", item.Rank)
case item.Rank == 20 || item.Rank == 50 || item.Rank == 100 || item.Rank == 200:
return fmt.Sprintf("排名破%d", item.Rank)
}
// T3/T4: 状态型
switch {
case item.HourlyNewLikes >= 20:
return "火速破圈"
case item.HourlyNewLikes >= 10:
return "小爆出圈"
case item.HourlyNewLikes >= 5:
return "热度积累"
case item.HourlyNewLikes >= 0:
return "缓慢涨粉"
default:
return "潜力待挖"
}
}
4.4 新增字段结构
// proto/social.proto
message LikedAssetItem {
int64 asset_id = 1;
string name = 2;
string cover_url = 3;
int32 like_count = 4;
int64 liked_at = 5;
double earnings = 6;
double hourly_earnings = 7;
bool is_lenticular = 8;
int64 expire_at = 9;
// 新增字段
string status_text = 10;
}
5. 前端修改设计
5.1 修改文件
frontend/pages/profile/myWorks.vue
5.2 修改点
修改前 (line 919):
status_text: index < 3 ? '排名进榜' : '潜力待挖',
修改后:
status_text: item.status_text || '潜力待挖',
5.3 完整修改的代码块
if (res.data && res.data.items) {
likedWorks.value = res.data.items.map((item, index) => ({
id: item.asset_id,
cover_url: item.cover_url,
like_count: item.like_count,
earnings: item.earnings,
liked_at: item.liked_at,
expire_at: item.expire_at,
name: item.name,
is_lenticular: item.is_lenticular ?? false,
status_text: item.status_text || '潜力待挖', // 直接使用后端返回
score: item.like_count,
reward: Math.floor(item.earnings || 0),
}));
// ...
}
6. 测试用例
6.1 标签测试用例
| 用例编号 |
前提条件 |
输入 |
预期输出 |
| TC-01 |
用户点赞后作品新增≥50点赞 |
status_text |
眼光拉满 |
| TC-02 |
作品排名第1 |
status_text |
屠榜顶流Top1 |
| TC-03 |
作品排名第3 |
status_text |
屠榜顶流Top3 |
| TC-04 |
作品排名第7 |
status_text |
第7爆款 |
| TC-05 |
作品排名第20 |
status_text |
排名破20 |
| TC-06 |
过去1小时新增点赞=25 |
status_text |
火速破圈 |
| TC-07 |
过去1小时新增点赞=15 |
status_text |
小爆出圈 |
| TC-08 |
过去1小时新增点赞=7 |
status_text |
热度积累 |
| TC-09 |
过去1小时新增点赞=2 |
status_text |
缓慢涨粉 |
| TC-10 |
无任何标签满足 |
status_text |
潜力待挖 |
6.2 优先级测试用例
| 用例编号 |
前提条件 |
预期输出 |
说明 |
| TC-11 |
排名第2 且 过去1小时新增点赞=25 |
眼光拉满 |
T0 > T1 |
| TC-12 |
排名第5 且 过去1小时新增点赞=30 |
屠榜顶流Top5 |
T1 > T3 |
| TC-13 |
排名第15 且 过去1小时新增点赞=22 |
火速破圈 |
无T0/T1满足 |
7. 里程碑
| 阶段 |
任务 |
负责人 |
状态 |
| 1 |
后端 proto/social.proto 新增 status_text 字段 |
后端 |
- |
| 2 |
后端 Service 层实现 computeStatusText 逻辑 |
后端 |
- |
| 3 |
后端修改 GetMyLikedAssets 接口返回 status_text |
后端 |
- |
| 4 |
前端 myWorks.vue 修改 status_text 取值逻辑 |
前端 |
- |
| 5 |
联调测试 + 回归测试 |
前端+后端 |
- |
8. 高并发性能评估
7.1 单请求成本
| 查询操作 |
次数 |
说明 |
| 点赞列表 + exhibition JOIN |
1 |
批量获取 30 条 |
| 批量获取排名 |
1 |
IN 查询 30 条 |
| 批量获取小时级新增 |
1 |
IN + 时间聚合 |
| 批量获取点赞后新增 |
1 |
IN + 时间聚合 |
| 总计 |
4 次 |
|
computeStatusText 计算复杂度为 O(1),耗时 < 1μs,可忽略。
7.2 并发容量估算
假设:单请求 DB 耗时 20ms,DB 连接池 500
单个连接处理能力:1000ms / 20ms = 50,000 请求/秒/连接
500 连接 × 50 = 25,000 理论上限 QPS
10,000 并发用户 → 约 3,000-5,000 实际 QPS
7.3 必要配置
| 配置项 |
推荐值 |
说明 |
| DB 连接池 |
300-500 |
根据 DB 服务器规格调整 |
| 排名缓存 TTL |
60s |
排名数据变化不频繁 |
| 索引 |
必建 |
参见 4.2 节索引建议 |
7.4 风险点
| 风险 |
缓解方案 |
| 点赞时频繁触发查询 |
点赞后可异步计算 status_text,不阻塞主流程 |
| DB 连接池耗尽 |
限流 + 连接池监控 |
| 慢查询 |
确保索引生效,定期 EXPLAIN 分析 |
9. 附录
8.1 标签文案汇总
| 标签名 |
字数 |
| 眼光拉满 |
4 |
| 屠榜顶流Top1~5 |
6~7 |
| 第6~10爆款 |
4~5 |
| 排名破20/50/100/200 |
5~6 |
| 火速破圈 |
4 |
| 小爆出圈 |
4 |
| 热度积累 |
4 |
| 缓慢涨粉 |
4 |
| 潜力待挖 |
4 |
8.2 相关文件
| 文件路径 |
说明 |
| backend/proto/social.proto |
Protobuf 定义 |
| backend/pkg/service/social_service.go |
Service 层实现 |
| backend/gateway/controller/social_controller.go |
Controller 层(返回格式) |
| frontend/pages/profile/myWorks.vue |
前端页面 |