10 KiB
10 KiB
我的作品统计(点赞/展出)设计文档
创建日期: 2026-04-27 项目: TopFans 我的作品统计 服务: socialService / galleryService 状态: 设计中
一、设计目标
提供用户查看自己点赞过的作品和展出过的作品的统计接口,返回实时点赞数。
二、数据来源
2.1 我点赞的作品
主表: asset_likes(点赞记录表)
关联表: assets(资产表)- 用于获取藏品信息
筛选条件:
user_id = ?(当前用户)star_id = ?(当前 star_id)assets.deleted_at IS NULL(藏品未删除)assets.is_active = true(藏品已激活)
2.2 我展出的作品
主表: exhibitions(展品展示表)
关联表: assets(资产表)- 用于获取藏品信息
筛选条件:
occupier_uid = ?(当前用户)occupier_star_id = ?(当前 star_id)deleted_at IS NULL(未删除)
三、API 设计
3.1 获取我点赞的作品列表
GET /api/v1/me/liked-assets
Query 参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| page | int | 否 | 1 | 页码 |
| page_size | int | 否 | 20 | 每页数量(最大100) |
HTTP 响应:
{
"code": 200,
"message": "ok",
"data": {
"items": [
{
"asset_id": 123,
"name": "藏品名称",
"cover_url": "https://xxx.com/cover.png",
"like_count": 100,
"liked_at": 1714214400000
}
],
"page": 1,
"page_size": 20,
"total": 50,
"has_more": true
}
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| asset_id | int64 | 资产ID |
| name | string | 藏品名称 |
| cover_url | string | 封面图URL |
| like_count | int32 | 实时点赞数(来自 assets 表) |
| liked_at | int64 | 用户点赞该作品的时间(毫秒时间戳) |
3.2 获取我展出的作品列表
GET /api/v1/me/exhibited-assets
Query 参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| page | int | 否 | 1 | 页码 |
| page_size | int | 否 | 20 | 每页数量(最大100) |
HTTP 响应:
{
"code": 200,
"message": "ok",
"data": {
"items": [
{
"asset_id": 123,
"name": "藏品名称",
"cover_url": "https://xxx.com/cover.png",
"like_count": 100,
"exhibited_at": 1714214400000,
"expire_at": 1714278400000
}
],
"page": 1,
"page_size": 20,
"total": 10,
"has_more": false
}
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| asset_id | int64 | 资产ID |
| name | string | 藏品名称 |
| cover_url | string | 封面图URL |
| like_count | int32 | 实时点赞数(来自 assets 表) |
| exhibited_at | int64 | 展出开始时间(毫秒时间戳) |
| expire_at | int64 | 展出过期时间(毫秒时间戳) |
3.3 错误码
| code | 说明 |
|---|---|
| 200 | 成功 |
| 401 | 用户认证失败 |
| 500 | 服务器内部错误 |
四、Proto 定义
4.1 我点赞的作品
// 获取我点赞的作品列表请求
message GetMyLikedAssetsRequest {
int32 page = 1; // 页码(默认1)
int32 page_size = 2; // 每页数量(默认20,最大100)
}
// 获取我点赞的作品列表响应
message GetMyLikedAssetsResponse {
topfans.common.BaseResponse base = 1;
LikedAssetsData data = 2;
}
// 点赞作品数据
message LikedAssetsData {
repeated LikedAssetItem items = 1; // 作品列表
int32 page = 2; // 当前页码
int32 page_size = 3; // 每页数量
int64 total = 4; // 总数量
bool has_more = 5; // 是否有更多
}
// 点赞作品项
message LikedAssetItem {
int64 asset_id = 1; // 资产ID
string name = 2; // 藏品名称
string cover_url = 3; // 封面图URL
int32 like_count = 4; // 实时点赞数
int64 liked_at = 5; // 点赞时间(毫秒时间戳)
}
4.2 我展出的作品
// 获取我展出的作品列表请求
message GetMyExhibitedAssetsRequest {
int32 page = 1; // 页码(默认1)
int32 page_size = 2; // 每页数量(默认20,最大100)
}
// 获取我展出的作品列表响应
message GetMyExhibitedAssetsResponse {
topfans.common.BaseResponse base = 1;
ExhibitedAssetsData data = 2;
}
// 展出作品数据
message ExhibitedAssetsData {
repeated ExhibitedAssetItem items = 1; // 作品列表
int32 page = 2; // 当前页码
int32 page_size = 3; // 每页数量
int64 total = 4; // 总数量
bool has_more = 5; // 是否有更多
}
// 展出作品项
message ExhibitedAssetItem {
int64 asset_id = 1; // 资产ID
string name = 2; // 藏品名称
string cover_url = 3; // 封面图URL
int32 like_count = 4; // 实时点赞数
int64 exhibited_at = 5; // 展出开始时间(毫秒时间戳)
int64 expire_at = 6; // 展出过期时间(毫秒时间戳)
}
4.3 Service 方法
在 SocialService 中新增方法:
// 社交服务
service SocialService {
// ... 现有方法 ...
// 获取我点赞的作品列表
rpc GetMyLikedAssets(GetMyLikedAssetsRequest) returns (GetMyLikedAssetsResponse) {
option (google.api.http) = {
get: "/api/v1/me/liked-assets"
};
}
}
在 GalleryService 中新增方法:
// 展馆服务
service GalleryService {
// ... 现有方法 ...
// 获取我展出的作品列表
rpc GetMyExhibitedAssets(GetMyExhibitedAssetsRequest) returns (GetMyExhibitedAssetsResponse) {
option (google.api.http) = {
get: "/api/v1/me/exhibited-assets"
};
}
}
五、核心逻辑
5.1 查询我点赞的作品
SELECT
al.asset_id,
a.name,
a.cover_url,
a.like_count,
al.created_at as liked_at
FROM asset_likes al
JOIN assets a ON al.asset_id = a.id
WHERE al.user_id = ?
AND al.star_id = ?
AND a.deleted_at IS NULL
AND a.is_active = true
ORDER BY al.created_at DESC
LIMIT ? OFFSET ?;
-- 计数
SELECT COUNT(*)
FROM asset_likes al
JOIN assets a ON al.asset_id = a.id
WHERE al.user_id = ?
AND al.star_id = ?
AND a.deleted_at IS NULL
AND a.is_active = true;
参数说明:
? = user_id(当前用户)? = star_id(当前 star_id)? = page_size? = (page - 1) * page_size
5.2 查询我展出的作品(只返回展出中的)
SELECT
e.asset_id,
a.name,
a.cover_url,
a.like_count,
e.start_time as exhibited_at,
e.expire_at
FROM exhibitions e
JOIN assets a ON e.asset_id = a.id
WHERE e.occupier_uid = ?
AND e.occupier_star_id = ?
AND e.deleted_at IS NULL
AND e.expire_at > ? -- 只返回未过期的
ORDER BY e.start_time DESC
LIMIT ? OFFSET ?;
-- 计数
SELECT COUNT(*)
FROM exhibitions e
WHERE e.occupier_uid = ?
AND e.occupier_star_id = ?
AND e.deleted_at IS NULL
AND e.expire_at > ?; -- 只返回未过期的
参数说明:
? = user_id(当前用户)? = star_id(当前 star_id)? = now(当前时间戳,只显示未过期的)? = page_size? = (page - 1) * page_size
六、数据模型
6.1 asset_likes 表(已有字段)
type AssetLike struct {
ID int64 `gorm:"primaryKey"`
AssetID int64 `gorm:"not null;uniqueIndex:uk_asset_likes_user_asset"`
UserID int64 `gorm:"not null;uniqueIndex:uk_asset_likes_user_asset"`
StarID int64 `gorm:"not null;index"`
CreatedAt int64 `gorm:"not null;index"`
}
6.2 exhibitions 表(已有字段)
type Exhibition struct {
ID int64 `gorm:"primaryKey"`
AssetID int64 `gorm:"not null"`
SlotID int64 `gorm:"not null"`
HostProfileID int64 `gorm:"not null"`
OccupierUID int64 `gorm:"not null;index"`
OccupierStarID int64 `gorm:"not null;index"`
StartTime int64 `gorm:"not null"`
ExpireAt int64 `gorm:"not null;index"`
CreatedAt int64 `gorm:"not null"`
UpdatedAt int64 `gorm:"not null"`
DeletedAt *int64 `gorm:"index"`
}
6.3 assets 表(已有字段)
type Asset struct {
ID int64 `gorm:"primaryKey"`
Name string `gorm:"type:varchar(100);not null"`
CoverURL string `gorm:"type:varchar(500);not null"`
LikeCount int32 `gorm:"not null;default:0"`
Status int32 `gorm:"not null;default:0"`
DeletedAt *int64 `gorm:"index"`
IsActive bool `gorm:"default:true;not null"`
}
七、项目文件结构
backend/
├── proto/
│ ├── social.proto # 修改:新增 GetMyLikedAssets 方法
│ └── gallery.proto # 修改:新增 GetMyExhibitedAssets 方法
│
├── pkg/proto/
│ ├── social/
│ │ ├── social.pb.go # 重新生成
│ │ └── social.triple.go # 重新生成
│ └── gallery/
│ ├── gallery.pb.go # 重新生成
│ └── gallery.triple.go # 重新生成
│
├── services/socialService/
│ ├── repository/
│ │ └── asset_like_repository.go # 修改:新增查询方法
│ │
│ ├── service/
│ │ └── asset_like_service.go # 修改:新增 GetMyLikedAssets 方法
│ │
│ └── provider/
│ └── social_provider.go # 修改:新增 GetMyLikedAssets Handler
│
├── services/galleryService/
│ ├── repository/
│ │ └── gallery_repository.go # 修改:新增 GetExhibitionsByOccupier 方法
│ │
│ ├── service/
│ │ └── exhibition_service.go # 修改:新增 GetMyExhibitedAssets 方法
│ │
│ └── provider/
│ └── gallery_provider.go # 修改:新增 GetMyExhibitedAssets Handler
│
└── gateway/
├── controller/
│ ├── social_controller.go # 修改:新增 /api/v1/me/liked-assets 路由
│ └── gallery_controller.go # 修改:新增 /api/v1/me/exhibited-assets 路由
│
└── router/
└── router.go # 修改:新增路由配置
八、已确认事项
- 只显示展出中的作品 — 通过
expire_at > now过滤 - 排序方式 — 按展出时间倒序(start_time DESC)
- 分页大小 — 默认 20,最大 100