- 新增 GET /api/v1/me/liked-assets 接口 - 新增 GET /api/v1/me/exhibited-assets 接口 - 新增 GetMyLikedAssets 和 GetMyExhibitedAssets RPC 方法 - 新增 ExhibitedAssetItemDTO 和 GetMyExhibitedAssetsResponseDTO - 前端新增 getUserLikedAssetsApi 和 getUserExhibitedAssetsApi(暂不实现) - 更新设计文档,标记他人作品统计接口为暂不实现 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
781 lines
19 KiB
Markdown
781 lines
19 KiB
Markdown
# 我的作品统计(点赞/展出)设计文档
|
||
|
||
> **创建日期:** 2026-04-27
|
||
> **项目:** TopFans 我的作品统计
|
||
> **服务:** socialService / galleryService
|
||
> **状态:** 设计中
|
||
|
||
---
|
||
|
||
## 一、设计目标
|
||
|
||
提供用户查看自己点赞过的作品和展出过的作品的统计接口,返回实时点赞数。
|
||
|
||
---
|
||
|
||
## 二、数据来源
|
||
|
||
### 2.1 我点赞的作品
|
||
|
||
**主表:** asset_likes(点赞记录表)
|
||
|
||
**关联表:**
|
||
- assets(资产表)- 用于获取藏品信息
|
||
- exhibitions(展品展示表)- 用于过滤展出中且未过期的藏品
|
||
- exhibition_revenue_records(收益记录表)- 用于获取当前可领取收益
|
||
|
||
**筛选条件:**
|
||
- `user_id = ?` (当前用户)
|
||
- `star_id = ?` (当前 star_id)
|
||
- `assets.deleted_at IS NULL` (藏品未删除)
|
||
- `assets.is_active = true` (藏品已激活)
|
||
- `exhibitions.deleted_at IS NULL` (展出记录未删除)
|
||
- `exhibitions.expire_at > now` (展出未过期)
|
||
|
||
### 2.2 我展出的作品
|
||
|
||
**主表:** exhibitions(展品展示表)
|
||
|
||
**关联表:**
|
||
- assets(资产表)- 用于获取藏品信息
|
||
- exhibition_revenue_records(收益记录表)- 用于获取当前可领取收益
|
||
|
||
**筛选条件:**
|
||
- `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 响应:**
|
||
|
||
```json
|
||
{
|
||
"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 | 用户点赞该作品的时间(毫秒时间戳) |
|
||
| earnings | int64 | 当前可领取收益(status='claimable' 的 crystal_amount 汇总) |
|
||
|
||
---
|
||
|
||
### 3.2 获取我展出的作品列表
|
||
|
||
```
|
||
GET /api/v1/me/exhibited-assets
|
||
```
|
||
|
||
**Query 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||
|------|------|------|--------|------|
|
||
| page | int | 否 | 1 | 页码 |
|
||
| page_size | int | 否 | 20 | 每页数量(最大100) |
|
||
|
||
**HTTP 响应:**
|
||
|
||
```json
|
||
{
|
||
"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,
|
||
"earnings": 500
|
||
}
|
||
],
|
||
"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 | 展出过期时间(毫秒时间戳) |
|
||
| earnings | int64 | 当前可领取收益(status='claimable' 的 crystal_amount 汇总) |
|
||
|
||
---
|
||
|
||
### 3.3 获取我今日点赞的作品(暂不实现)
|
||
|
||
```
|
||
GET /api/v1/me/today-liked-assets
|
||
```
|
||
|
||
**Query 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||
|------|------|------|--------|------|
|
||
| page | int | 否 | 1 | 页码 |
|
||
| page_size | int | 否 | 20 | 每页数量(最大100) |
|
||
|
||
**HTTP 响应:**
|
||
|
||
```json
|
||
{
|
||
"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.4 获取我本周点赞的作品(暂不实现)
|
||
|
||
```
|
||
GET /api/v1/me/week-liked-assets
|
||
```
|
||
|
||
**Query 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||
|------|------|------|--------|------|
|
||
| page | int | 否 | 1 | 页码 |
|
||
| page_size | int | 否 | 20 | 每页数量(最大100) |
|
||
|
||
**HTTP 响应:**
|
||
|
||
```json
|
||
{
|
||
"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.5 获取他人点赞的作品列表(暂不实现)
|
||
|
||
```
|
||
GET /api/v1/users/{user_id}/liked-assets
|
||
```
|
||
|
||
**Path 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| user_id | int64 | 是 | 他人用户ID |
|
||
|
||
**Query 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||
|------|------|------|--------|------|
|
||
| page | int | 否 | 1 | 页码 |
|
||
| page_size | int | 否 | 20 | 每页数量(最大100) |
|
||
|
||
**HTTP 响应:**
|
||
|
||
```json
|
||
{
|
||
"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.6 获取他人展出的作品列表(暂不实现)
|
||
|
||
```
|
||
GET /api/v1/users/{user_id}/exhibited-assets
|
||
```
|
||
|
||
**Path 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| user_id | int64 | 是 | 他人用户ID |
|
||
|
||
**Query 参数:**
|
||
|
||
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
||
|------|------|------|--------|------|
|
||
| page | int | 否 | 1 | 页码 |
|
||
| page_size | int | 否 | 20 | 每页数量(最大100) |
|
||
|
||
**HTTP 响应:**
|
||
|
||
```json
|
||
{
|
||
"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.7 错误码
|
||
|
||
| code | 说明 |
|
||
|------|------|
|
||
| 200 | 成功 |
|
||
| 401 | 用户认证失败 |
|
||
| 500 | 服务器内部错误 |
|
||
|
||
---
|
||
|
||
## 四、Proto 定义
|
||
|
||
### 4.1 我点赞的作品
|
||
|
||
```protobuf
|
||
// 获取我点赞的作品列表请求
|
||
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; // 点赞时间(毫秒时间戳)
|
||
int64 earnings = 6; // 当前可领取收益
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 我展出的作品
|
||
|
||
```protobuf
|
||
// 获取我展出的作品列表请求
|
||
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; // 展出过期时间(毫秒时间戳)
|
||
int64 earnings = 7; // 当前可领取收益
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4.3 我今日/本周点赞的作品(暂不实现)
|
||
|
||
```protobuf
|
||
// 获取我今日点赞的作品列表请求
|
||
message GetMyTodayLikedAssetsRequest {
|
||
int32 page = 1; // 页码(默认1)
|
||
int32 page_size = 2; // 每页数量(默认20,最大100)
|
||
}
|
||
|
||
// 获取我今日点赞的作品列表响应
|
||
message GetMyTodayLikedAssetsResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
LikedAssetsData data = 2;
|
||
}
|
||
|
||
// 获取我本周点赞的作品列表请求
|
||
message GetMyWeekLikedAssetsRequest {
|
||
int32 page = 1; // 页码(默认1)
|
||
int32 page_size = 2; // 每页数量(默认20,最大100)
|
||
}
|
||
|
||
// 获取我本周点赞的作品列表响应
|
||
message GetMyWeekLikedAssetsResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
LikedAssetsData data = 2;
|
||
}
|
||
```
|
||
|
||
> **状态:暂不实现**
|
||
|
||
---
|
||
|
||
### 4.4 他人点赞/展出的作品(暂不实现)
|
||
|
||
```protobuf
|
||
// 获取他人点赞的作品列表请求
|
||
message GetUserLikedAssetsRequest {
|
||
int64 user_id = 1; // 他人用户ID
|
||
int32 page = 2; // 页码(默认1)
|
||
int32 page_size = 3; // 每页数量(默认20,最大100)
|
||
}
|
||
|
||
// 获取他人点赞的作品列表响应
|
||
message GetUserLikedAssetsResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
LikedAssetsData data = 2;
|
||
}
|
||
|
||
// 获取他人展出的作品列表请求
|
||
message GetUserExhibitedAssetsRequest {
|
||
int64 user_id = 1; // 他人用户ID
|
||
int32 page = 2; // 页码(默认1)
|
||
int32 page_size = 3; // 每页数量(默认20,最大100)
|
||
}
|
||
|
||
// 获取他人展出的作品列表响应
|
||
message GetUserExhibitedAssetsResponse {
|
||
topfans.common.BaseResponse base = 1;
|
||
ExhibitedAssetsData data = 2;
|
||
}
|
||
```
|
||
|
||
> **状态:暂不实现**
|
||
|
||
---
|
||
|
||
### 4.5 Service 方法
|
||
|
||
在 SocialService 中新增方法:
|
||
|
||
```protobuf
|
||
// 社交服务
|
||
service SocialService {
|
||
// ... 现有方法 ...
|
||
|
||
// 获取我点赞的作品列表
|
||
rpc GetMyLikedAssets(GetMyLikedAssetsRequest) returns (GetMyLikedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/me/liked-assets"
|
||
};
|
||
}
|
||
|
||
// 获取我今日点赞的作品列表(暂不实现)
|
||
rpc GetMyTodayLikedAssets(GetMyTodayLikedAssetsRequest) returns (GetMyTodayLikedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/me/today-liked-assets"
|
||
};
|
||
}
|
||
|
||
// 获取我本周点赞的作品列表(暂不实现)
|
||
rpc GetMyWeekLikedAssets(GetMyWeekLikedAssetsRequest) returns (GetMyWeekLikedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/me/week-liked-assets"
|
||
};
|
||
}
|
||
|
||
// 获取他人点赞的作品列表(暂不实现)
|
||
rpc GetUserLikedAssets(GetUserLikedAssetsRequest) returns (GetUserLikedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/users/{user_id}/liked-assets"
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
在 GalleryService 中新增方法:
|
||
|
||
```protobuf
|
||
// 展馆服务
|
||
service GalleryService {
|
||
// ... 现有方法 ...
|
||
|
||
// 获取我展出的作品列表
|
||
rpc GetMyExhibitedAssets(GetMyExhibitedAssetsRequest) returns (GetMyExhibitedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/me/exhibited-assets"
|
||
};
|
||
}
|
||
|
||
// 获取他人展出的作品列表(暂不实现)
|
||
rpc GetUserExhibitedAssets(GetUserExhibitedAssetsRequest) returns (GetUserExhibitedAssetsResponse) {
|
||
option (google.api.http) = {
|
||
get: "/api/v1/users/{user_id}/exhibited-assets"
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、核心逻辑
|
||
|
||
### 5.1 查询我点赞的作品(只返回展出中且未过期的)
|
||
|
||
```sql
|
||
SELECT
|
||
al.asset_id,
|
||
a.name,
|
||
a.cover_url,
|
||
a.like_count,
|
||
al.created_at as liked_at,
|
||
COALESCE(SUM(err.crystal_amount), 0) as earnings
|
||
FROM asset_likes al
|
||
JOIN assets a ON al.asset_id = a.id
|
||
JOIN exhibitions e ON e.asset_id = a.id
|
||
LEFT JOIN exhibition_revenue_records err ON err.asset_id = a.id AND err.status = 'claimable'
|
||
WHERE al.user_id = ?
|
||
AND al.star_id = ?
|
||
AND a.deleted_at IS NULL
|
||
AND a.is_active = true
|
||
AND e.deleted_at IS NULL
|
||
AND e.expire_at > ?
|
||
GROUP BY al.asset_id, a.name, a.cover_url, a.like_count, al.created_at
|
||
ORDER BY al.created_at DESC
|
||
LIMIT ? OFFSET ?;
|
||
|
||
-- 计数
|
||
SELECT COUNT(DISTINCT al.asset_id)
|
||
FROM asset_likes al
|
||
JOIN assets a ON al.asset_id = a.id
|
||
JOIN exhibitions e ON e.asset_id = a.id
|
||
WHERE al.user_id = ?
|
||
AND al.star_id = ?
|
||
AND a.deleted_at IS NULL
|
||
AND a.is_active = true
|
||
AND e.deleted_at IS NULL
|
||
AND e.expire_at > ?;
|
||
```
|
||
|
||
**参数说明:**
|
||
- `? = user_id` (当前用户)
|
||
- `? = star_id` (当前 star_id)
|
||
- `? = now` (当前时间戳,只显示展出中且未过期的)
|
||
- `? = page_size`
|
||
- `? = (page - 1) * page_size`
|
||
|
||
---
|
||
|
||
### 5.2 查询我展出的作品(只返回展出中的)
|
||
|
||
```sql
|
||
SELECT
|
||
e.asset_id,
|
||
a.name,
|
||
a.cover_url,
|
||
a.like_count,
|
||
e.start_time as exhibited_at,
|
||
e.expire_at,
|
||
COALESCE(SUM(err.crystal_amount), 0) as earnings
|
||
FROM exhibitions e
|
||
JOIN assets a ON e.asset_id = a.id
|
||
LEFT JOIN exhibition_revenue_records err ON err.asset_id = a.id AND err.status = 'claimable'
|
||
WHERE e.occupier_uid = ?
|
||
AND e.occupier_star_id = ?
|
||
AND e.deleted_at IS NULL
|
||
AND e.expire_at > ? -- 只返回未过期的
|
||
GROUP BY e.asset_id, a.name, a.cover_url, a.like_count, e.start_time, 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 表(已有字段)
|
||
|
||
```go
|
||
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 表(已有字段)
|
||
|
||
```go
|
||
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 表(已有字段)
|
||
|
||
```go
|
||
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 # 修改:新增路由配置
|
||
```
|
||
|
||
---
|
||
|
||
## 八、已确认事项
|
||
|
||
1. **只显示展出中的作品** — 通过 `expire_at > now` 过滤
|
||
2. **排序方式** — 按展出时间倒序(start_time DESC)
|
||
3. **分页大小** — 默认 20,最大 100
|
||
4. **点赞作品也只显示展出中且未过期的** — 通过 JOIN exhibitions 并过滤 `expire_at > now`
|
||
5. **今日/本周点赞暂不实现** — API 和 Proto 已定义,但代码实现待后续
|
||
6. **每个藏品返回当前可领取收益** — 关联 exhibition_revenue_records 表,汇总 `status='claimable'` 的 `crystal_amount`
|
||
7. **他人点赞/展出的作品列表暂不实现** — API 和 Proto 已定义,但代码实现待后续 |