syntax = "proto3"; package topfans.gallery; import "google/api/annotations.proto"; import "proto/common.proto"; option go_package = "github.com/topfans/backend/pkg/proto/gallery;gallery"; // 展馆服务 service GalleryService { // 获取我的展馆 rpc GetMyGallery(GetMyGalleryRequest) returns (GetMyGalleryResponse) { option (google.api.http) = { get: "/api/mygalleries" }; } // 获取他人展馆 rpc GetUserGallery(GetUserGalleryRequest) returns (GetUserGalleryResponse) { option (google.api.http) = { get: "/api/galleries/{target_uid}" }; } // 在展位展示藏品 rpc PlaceAsset(PlaceAssetRequest) returns (PlaceAssetResponse) { option (google.api.http) = { post: "/api/galleries/place" body: "*" }; } // 解锁/购买新展位 rpc UnlockSlot(UnlockSlotRequest) returns (UnlockSlotResponse) { option (google.api.http) = { post: "/api/galleries/slots_unlock" body: "*" }; } // 从展位移除资产(统一接口,支持展位所有者踢走和占位者下架) rpc RemoveFromSlot(RemoveFromSlotRequest) returns (RemoveFromSlotResponse) { option (google.api.http) = { delete: "/api/galleries/slots/{slot_id}/asset" }; } } // 请求和响应消息定义 message GetMyGalleryRequest {} message GetMyGalleryResponse { topfans.common.BaseResponse base = 1; GalleryData data = 2; } message GetUserGalleryRequest { int64 target_uid = 1; } message GetUserGalleryResponse { topfans.common.BaseResponse base = 1; GalleryData data = 2; } message PlaceAssetRequest { int64 asset_id = 1; int64 gallery_owner_id = 2; int64 slot_id = 3; } message PlaceAssetResponse { topfans.common.BaseResponse base = 1; PlaceAssetData data = 2; } message UnlockSlotRequest {} message UnlockSlotResponse { topfans.common.BaseResponse base = 1; UnlockSlotData data = 2; } // 数据模型 message GalleryData { int64 gallery_owner_id = 1; int32 slot_total = 2; repeated SlotInfo slots = 3; string nickname = 4; // 展馆所有者昵称(从 fan_profiles 表获取) } message SlotInfo { int64 slot_id = 1; int32 slot_index = 2; string status = 3; // EMPTY, OCCUPIED, LOCKED bool is_enabled = 4; AssetInfo asset = 5; int64 occupier_uid = 6; int64 occupied_at = 7; int64 expire_at = 8; UnlockCondition unlock_condition = 9; string visibility = 10; // public / private bool can_operate = 11; // 当前用户是否可以操作此展位 string operation = 12; // 操作类型: "place" | "remove" | "none" } message AssetInfo { int64 asset_id = 1; string name = 2; string cover_url = 3; int32 like_count = 4; int64 remain_time = 5; // 剩余时间(秒) } message UnlockCondition { string type = 1; // level, crystal int32 value = 2; } message PlaceAssetData { string status = 1; // OCCUPIED string occupied_until = 2; // ISO 8601格式 int64 occupier_uid = 3; // 占位者用户ID } message UnlockSlotData { int32 slot_total = 1; // 展位总数 int64 crystal_balance = 2; // 水晶余额(如果使用水晶购买,显示扣除后的余额) } // 从展位移除资产请求 message RemoveFromSlotRequest { int64 slot_id = 1; // 展位ID(必填) } // 从展位移除资产响应 message RemoveFromSlotResponse { topfans.common.BaseResponse base = 1; }