12 KiB
12 KiB
展馆接口数据库字段说明
接口说明
GET /api/v1/galleries/{target_uid} - 获取他人展馆
路径参数:
target_uid: 目标用户ID(数据库users.id)
功能:查看指定用户的展馆信息(展位列表、展品展示情况)
数据库表与字段映射
1. 主要数据表
booth_slots 表(展位表)
| 数据库字段 | Go 模型字段 | 类型 | 说明 |
|---|---|---|---|
slot_id |
SlotID |
int64 |
展位ID(主键,自增) |
host_profile_id |
HostProfileID |
int64 |
展馆所有者ID(计算值:user_id * 1000000 + star_id) |
user_id |
UserID |
int64 |
用户ID(外键关联 users.id) |
star_id |
StarID |
int64 |
明星ID(用于数据隔离) |
slot_index |
SlotIndex |
int |
展位序号(1, 2, 3...,与 host_profile_id 联合唯一) |
visibility |
Visibility |
string |
可见性(默认 'public') |
is_enabled |
IsEnabled |
bool |
是否已解锁(false=未解锁/LOCKED,true=已解锁) |
unlock_type |
UnlockType |
string |
解锁类型('level' 或 'crystal') |
unlock_value |
UnlockValue |
int |
解锁条件值(等级或水晶数量) |
created_at |
CreatedAt |
int64 |
创建时间(毫秒时间戳) |
updated_at |
UpdatedAt |
int64 |
更新时间(毫秒时间戳) |
查询逻辑:
SELECT * FROM booth_slots
WHERE user_id = ? AND star_id = ?
ORDER BY slot_index ASC
exhibitions 表(展品展示表)
| 数据库字段 | Go 模型字段 | 类型 | 说明 |
|---|---|---|---|
id |
ID |
int64 |
主键(自增) |
asset_id |
AssetID |
int64 |
资产ID(外键关联 assets.id,唯一索引) |
slot_id |
SlotID |
int64 |
展位ID(外键关联 booth_slots.slot_id) |
host_profile_id |
HostProfileID |
int64 |
展馆所有者ID(与 booth_slots.host_profile_id 一致) |
occupier_uid |
OccupierUID |
int64 |
占位者用户ID(实际放置藏品的用户) |
occupier_star_id |
OccupierStarID |
int64 |
占位者明星ID |
start_time |
StartTime |
int64 |
占用开始时间(毫秒时间戳) |
expire_at |
ExpireAt |
int64 |
占用过期时间(毫秒时间戳,有索引) |
created_at |
CreatedAt |
int64 |
创建时间 |
updated_at |
UpdatedAt |
int64 |
更新时间 |
查询逻辑(判断展位是否被占用):
SELECT * FROM exhibitions
WHERE slot_id = ?
LIMIT 1
响应包字段说明
响应结构
{
"code": 200,
"message": "ok",
"data": {
"gallery_owner_id": 37000088,
"slot_total": 3,
"slots": [...]
}
}
字段详解
gallery_owner_id(展馆所有者ID)
- 计算方式:
user_id * 1000000 + star_id - 示例:
37000088=37 * 1000000 + 88- 表示:用户ID=37,明星ID=88 的展馆
- 用途:
- 用于标识展馆的唯一所有者(同一用户在不同明星下有不同的展馆)
- 在放置藏品时,需要传入此 ID 作为
gallery_owner_id参数
slot_total(展位总数)
- 来源:
booth_slots表中该用户在该明星下的展位数量 - 说明:初始展位数量由配置决定(通常为 3 个)
slots[](展位列表)
每个展位对象包含:
| 字段 | 类型 | 说明 | 数据来源 |
|---|---|---|---|
slot_id |
int64 |
展位ID(主键) | booth_slots.slot_id |
slot_index |
int32 |
展位序号(1, 2, 3...) | booth_slots.slot_index |
status |
string |
展位状态 | 计算得出(见下方) |
is_enabled |
bool |
是否已解锁 | booth_slots.is_enabled |
asset |
object|null |
展品信息(仅 status=OCCUPIED 时存在) |
从 exhibitions + assets 表关联查询 |
occupier_uid |
int64|null |
占位者用户ID(仅 status=OCCUPIED 时存在) |
exhibitions.occupier_uid |
occupied_at |
int64|null |
占用开始时间(仅 status=OCCUPIED 时存在) |
exhibitions.start_time |
expire_at |
int64|null |
占用过期时间(仅 status=OCCUPIED 时存在) |
exhibitions.expire_at |
unlock_condition |
object|null |
解锁条件(仅 status=LOCKED 时存在) |
从 booth_slots.unlock_type + unlock_value 计算 |
status 状态计算逻辑
if !slot.IsEnabled {
status = "LOCKED" // 未解锁
} else {
exhibition := GetExhibitionBySlot(slot.SlotID)
if exhibition == nil {
status = "EMPTY" // 已解锁但空展位
} else {
status = "OCCUPIED" // 已解锁且有展品
}
}
状态值说明:
LOCKED:展位未解锁(is_enabled=false),需要满足解锁条件才能使用EMPTY:展位已解锁(is_enabled=true),但当前没有展品OCCUPIED:展位已解锁且有展品展示(exhibitions表中有对应记录)
asset 对象(展品信息)
当 status=OCCUPIED 时,asset 字段包含:
| 字段 | 类型 | 说明 | 数据来源 |
|---|---|---|---|
asset_id |
int64 |
资产ID | exhibitions.asset_id → assets.id |
name |
string |
资产名称 | assets.name |
cover_url |
string |
封面图URL | assets.cover_url |
like_count |
int32 |
点赞数 | assets.like_count |
remain_time |
int64 |
剩余时间(秒) | (exhibitions.expire_at - now) / 1000 |
注意:asset 信息通过 RPC 调用 AssetService.GetAsset 获取,需要传入 occupier_uid 和 occupier_star_id(因为资产属于占位者,不是展馆所有者)。
unlock_condition 对象(解锁条件)
当 status=LOCKED 时,unlock_condition 字段包含:
| 字段 | 类型 | 说明 | 数据来源 |
|---|---|---|---|
type |
string |
解锁类型:"level" 或 "crystal" |
booth_slots.unlock_type 或配置规则 |
value |
int32 |
解锁条件值(等级或水晶数量) | booth_slots.unlock_value 或配置规则 |
与 /api/v1/galleries/me 的响应格式对比
响应格式是否一致?
答案:是的,响应格式完全一致。
代码证据
-
DTO 定义(
gateway/dto/gallery_dto.go):// GetMyGalleryResponseDTO 获取我的展馆响应 type GetMyGalleryResponseDTO struct { GalleryOwnerID int64 `json:"gallery_owner_id"` SlotTotal int32 `json:"slot_total"` Slots []SlotInfoDTO `json:"slots"` } // GetUserGalleryResponseDTO 获取他人展馆响应(与我的展馆响应相同) type GetUserGalleryResponseDTO struct { GalleryOwnerID int64 `json:"gallery_owner_id"` SlotTotal int32 `json:"slot_total"` Slots []SlotInfoDTO `json:"slots"` }注释明确说明:
GetUserGalleryResponseDTO与GetMyGalleryResponseDTO相同 -
转换函数(
gateway/dto/gallery_converter.go):// ConvertGalleryData 转换展馆数据(我的展馆) func ConvertGalleryData(pbData *pbGallery.GalleryData) *GetMyGalleryResponseDTO { // ... 转换逻辑 } // ConvertGalleryDataToUser 转换展馆数据(他人展馆) func ConvertGalleryDataToUser(pbData *pbGallery.GalleryData) *GetUserGalleryResponseDTO { // ... 转换逻辑(与 ConvertGalleryData 完全相同) }两个函数的转换逻辑完全一致
-
Service 层返回(
services/galleryService/service/gallery_service.go):// GetMyGallery 和 GetUserGallery 都返回 *pb.GalleryData // 结构完全相同,只是查询的目标用户不同
实际差异
虽然响应格式相同,但数据内容有区别:
| 对比项 | /api/v1/galleries/me |
/api/v1/galleries/{target_uid} |
|---|---|---|
| 查询目标 | 当前登录用户(user_id 从 JWT 获取) |
指定用户(target_uid 从路径参数获取) |
gallery_owner_id |
user_id * 1000000 + star_id(当前用户) |
target_uid * 1000000 + star_id(目标用户) |
slots[] 数据 |
当前用户的展位 | 目标用户的展位 |
| 权限 | 可查看自己的所有展位(包括未解锁的) | 只能查看目标用户已解锁的展位(is_enabled=true) |
注意:代码中 buildSlotInfos 的 isOwner 参数用于区分是否显示解锁条件等细节,但响应结构本身是一致的。
使用示例
1. 查看他人展馆
# 查看用户ID=37的展馆
curl -X GET "http://localhost:8080/api/v1/galleries/37" \
-H "Authorization: Bearer <JWT_TOKEN>"
响应示例:
{
"code": 200,
"message": "ok",
"data": {
"gallery_owner_id": 37000088, // 37 * 1000000 + 88
"slot_total": 3,
"slots": [
{
"slot_id": 46,
"slot_index": 1,
"status": "EMPTY", // 已解锁但空展位
"is_enabled": true,
// asset, occupier_uid 等字段不存在(因为 status=EMPTY)
},
{
"slot_id": 47,
"slot_index": 2,
"status": "OCCUPIED", // 有展品
"is_enabled": true,
"asset": {
"asset_id": 123,
"name": "数字艺术品",
"cover_url": "https://...",
"like_count": 10,
"remain_time": 86400
},
"occupier_uid": 20, // 占位者用户ID
"occupied_at": 1705747200000,
"expire_at": 1705833600000
},
{
"slot_id": 48,
"slot_index": 3,
"status": "LOCKED", // 未解锁
"is_enabled": false,
"unlock_condition": {
"type": "crystal",
"value": 100
}
}
]
}
}
2. 前端使用建议
-
展示展位列表:
- 遍历
data.slots[],根据status显示不同状态 EMPTY:显示空展位占位图OCCUPIED:显示asset.cover_url和资产信息LOCKED:显示锁定图标和unlock_condition
- 遍历
-
放置藏品:
- 需要
gallery_owner_id、slot_id、asset_id - 调用
POST /api/v1/galleries/place
- 需要
-
权限判断:
- 只有展馆所有者可以放置/移除展品
- 他人只能查看已解锁的展位(
is_enabled=true)
数据库查询示例
查询展位列表
-- 查询用户ID=37,明星ID=88的所有展位
SELECT
slot_id,
slot_index,
is_enabled,
unlock_type,
unlock_value
FROM booth_slots
WHERE user_id = 37 AND star_id = 88
ORDER BY slot_index ASC;
查询展品展示情况
-- 查询展位ID=47的展品信息
SELECT
e.asset_id,
e.occupier_uid,
e.start_time,
e.expire_at,
a.name AS asset_name,
a.cover_url
FROM exhibitions e
LEFT JOIN assets a ON e.asset_id = a.id
WHERE e.slot_id = 47;
总结
-
数据库表:
booth_slots:展位基础信息exhibitions:展品展示关系
-
响应格式:
/api/v1/galleries/me和/api/v1/galleries/{target_uid}响应格式完全一致- 都返回
{ gallery_owner_id, slot_total, slots[] } - 差异仅在于数据内容(查询的目标用户不同)
-
gallery_owner_id计算:- 公式:
user_id * 1000000 + star_id - 示例:用户37、明星88 →
37000088
- 公式:
-
status状态:LOCKED:未解锁(is_enabled=false)EMPTY:已解锁但空展位(is_enabled=true且exhibitions无记录)OCCUPIED:有展品(is_enabled=true且exhibitions有记录)