From dcd8cd452707ec2d0c9f80316b3bbbdf6b7dac9c Mon Sep 17 00:00:00 2001 From: zerosaturation Date: Wed, 29 Apr 2026 13:35:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=88=91=E7=9A=84?= =?UTF-8?q?=E4=BD=9C=E5=93=81=E7=BB=9F=E8=AE=A1=E6=8E=A5=E5=8F=A3=EF=BC=88?= =?UTF-8?q?=E7=82=B9=E8=B5=9E/=E5=B1=95=E5=87=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 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 --- .../gateway/controller/gallery_controller.go | 103 ++- .../gateway/controller/social_controller.go | 63 ++ backend/gateway/dto/gallery_dto.go | 20 + backend/gateway/router/router.go | 8 +- backend/pkg/proto/gallery/gallery.pb.go | 391 ++++++++-- backend/pkg/proto/gallery/gallery.triple.go | 29 +- backend/pkg/proto/social/social.pb.go | 706 +++++++++++++++--- backend/pkg/proto/social/social.triple.go | 29 +- backend/proto/gallery.proto | 45 +- backend/proto/social.proto | 80 ++ .../provider/gallery_provider.go | 23 + .../repository/gallery_repository.go | 61 ++ backend/services/socialService/main.go | 2 +- .../socialService/provider/social_provider.go | 27 + .../repository/social_repository.go | 67 ++ .../specs/2026-04-27-my-assets-design.md | 361 ++++++++- frontend/utils/api.js | 22 + 17 files changed, 1892 insertions(+), 145 deletions(-) diff --git a/backend/gateway/controller/gallery_controller.go b/backend/gateway/controller/gallery_controller.go index bc0236e..c8cb49f 100644 --- a/backend/gateway/controller/gallery_controller.go +++ b/backend/gateway/controller/gallery_controller.go @@ -525,7 +525,7 @@ func (ctrl *GalleryController) GetRandomGallery(c *gin.Context) { galleryDTO := dto.ConvertGalleryDataToUser(galleryResp.Data) - logger.Logger.Info("GetRandomGallery success", +logger.Logger.Info("GetRandomGallery success", zap.Any("user_id", userID), zap.Int64("target_uid", targetUID), zap.Int32("slot_total", galleryDTO.SlotTotal), @@ -533,3 +533,104 @@ func (ctrl *GalleryController) GetRandomGallery(c *gin.Context) { response.Success(c, galleryDTO) } + +// GetMyExhibitedAssets 获取我展出的作品列表 +// @Summary 获取我展出的作品列表 +// @Description 获取当前用户正在展出的作品列表 +// @Tags galleries +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param page query int false "页码" default(1) +// @Param page_size query int false "每页数量" default(20) +// @Success 200 {object} response.Response{data=dto.GetMyExhibitedAssetsResponseDTO} +// @Router /api/v1/me/exhibited-assets [get] +func (ctrl *GalleryController) GetMyExhibitedAssets(c *gin.Context) { + // 从上下文获取用户信息(中间件已验证) + userID, exists := c.Get("user_id") + if !exists { + response.Error(c, http.StatusUnauthorized, "用户未认证") + return + } + + starID, exists := c.Get("star_id") + if !exists { + response.Error(c, http.StatusUnauthorized, "明星身份未设置") + return + } + + // 解析分页参数 + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) + if page <= 0 { + page = 1 + } + if pageSize <= 0 { + pageSize = 20 + } + if pageSize > 100 { + pageSize = 100 + } + + // 创建带有附加信息的context(Triple协议要求attachments值为string类型) + ctx := context.WithValue(context.Background(), constant.AttachmentKey, map[string]interface{}{ + "user_id": strconv.FormatInt(userID.(int64), 10), + "star_id": strconv.FormatInt(starID.(int64), 10), + }) + + // 调用RPC服务 + resp, err := ctrl.galleryService.GetMyExhibitedAssets(ctx, &pbGallery.GetMyExhibitedAssetsRequest{ + Page: int32(page), + PageSize: int32(pageSize), + }) + if err != nil { + logger.Logger.Error("GetMyExhibitedAssets RPC failed", + zap.Any("user_id", userID), + zap.Any("star_id", starID), + zap.Error(err), + ) + _, msg := parseRPCError(err) + errorMsg := "获取展出的作品列表失败" + if msg != "" { + errorMsg += "," + msg + } + response.Error(c, http.StatusInternalServerError, errorMsg) + return + } + + // 检查业务错误 + if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { + response.Error(c, http.StatusBadRequest, resp.Base.Message) + return + } + + // 转换为DTO + items := make([]*dto.ExhibitedAssetItemDTO, 0, len(resp.Data.Items)) + for _, item := range resp.Data.Items { + items = append(items, &dto.ExhibitedAssetItemDTO{ + AssetID: item.AssetId, + Name: item.Name, + CoverURL: item.CoverUrl, + LikeCount: item.LikeCount, + ExhibitedAt: item.ExhibitedAt, + ExpireAt: item.ExpireAt, + Earnings: item.Earnings, + }) + } + +result := &dto.GetMyExhibitedAssetsResponseDTO{ + Items: items, + Page: resp.Data.Page, + PageSize: resp.Data.PageSize, + Total: resp.Data.Total, + HasMore: resp.Data.HasMore, + } + + logger.Logger.Info("GetMyExhibitedAssets success", + zap.Any("user_id", userID), + zap.Any("star_id", starID), + zap.Int32("count", int32(len(items))), + ) + + response.Success(c, result) +} \ No newline at end of file diff --git a/backend/gateway/controller/social_controller.go b/backend/gateway/controller/social_controller.go index f980a44..5034155 100644 --- a/backend/gateway/controller/social_controller.go +++ b/backend/gateway/controller/social_controller.go @@ -884,3 +884,66 @@ func (ctrl *SocialController) UnlikeAsset(c *gin.Context) { // 注意:CheckAssetLike 已被删除 // 检查点赞状态请通过 GET /api/v1/assets/:asset_id 获取,响应中的 is_liked 字段表示当前用户是否已点赞 + +// GetMyLikedAssets 获取我点赞的作品列表 +// @Summary 获取我点赞的作品列表 +// @Description 获取当前用户点赞过的作品列表(只返回展出中且未过期的) +// @Tags social +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param page query int false "页码,默认1" +// @Param page_size query int false "每页数量,默认20,最大100" +// @Success 200 {object} response.Response +// @Router /api/v1/me/liked-assets [get] +func (ctrl *SocialController) GetMyLikedAssets(c *gin.Context) { + userID, _ := c.Get("user_id") + starID, _ := c.Get("star_id") + + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ + "user_id": strconv.FormatInt(userID.(int64), 10), + "star_id": strconv.FormatInt(starID.(int64), 10), + }) + + resp, err := ctrl.socialService.GetMyLikedAssets(ctx, &pbSocial.GetMyLikedAssetsRequest{ + Page: int32(page), + PageSize: int32(pageSize), + }) + + if err != nil { + logger.Logger.Error("GetMyLikedAssets RPC failed", zap.Error(err)) + response.Error(c, http.StatusInternalServerError, "服务调用失败") + return + } + + if resp.Base.Code != pbCommon.StatusCode_STATUS_OK { + response.ErrorWithCode(c, int(resp.Base.Code), resp.Base.Message) + return + } + + items := make([]map[string]interface{}, 0, len(resp.Data.Items)) + for _, item := range resp.Data.Items { + items = append(items, map[string]interface{}{ + "asset_id": item.AssetId, + "name": item.Name, + "cover_url": item.CoverUrl, + "like_count": item.LikeCount, + "liked_at": item.LikedAt, + "earnings": item.Earnings, + }) + } + + response.Success(c, gin.H{ + "items": items, + "total": resp.Data.Total, + "page": resp.Data.Page, + "page_size": resp.Data.PageSize, + "has_more": resp.Data.HasMore, + }) +} diff --git a/backend/gateway/dto/gallery_dto.go b/backend/gateway/dto/gallery_dto.go index ec11d28..18f729d 100644 --- a/backend/gateway/dto/gallery_dto.go +++ b/backend/gateway/dto/gallery_dto.go @@ -70,3 +70,23 @@ type UnlockSlotResponseDTO struct { SlotTotal int32 `json:"slot_total"` // 展位总数 CrystalBalance int64 `json:"crystal_balance"` // 水晶余额(如果使用水晶购买,显示扣除后的余额) } + +// ExhibitedAssetItemDTO 展出的作品项 +type ExhibitedAssetItemDTO struct { + AssetID int64 `json:"asset_id"` // 资产ID + Name string `json:"name"` // 藏品名称 + CoverURL string `json:"cover_url"` // 封面图URL + LikeCount int32 `json:"like_count"` // 实时点赞数 + ExhibitedAt int64 `json:"exhibited_at"` // 展出开始时间(毫秒时间戳) + ExpireAt int64 `json:"expire_at"` // 展出过期时间(毫秒时间戳) + Earnings int64 `json:"earnings"` // 当前可领取收益 +} + +// GetMyExhibitedAssetsResponseDTO 获取我展出的作品列表响应 +type GetMyExhibitedAssetsResponseDTO struct { + Items []*ExhibitedAssetItemDTO `json:"items"` // 作品列表 + Page int32 `json:"page"` // 当前页码 + PageSize int32 `json:"page_size"` // 每页数量 + Total int64 `json:"total"` // 总数量 + HasMore bool `json:"has_more"` // 是否有更多 +} diff --git a/backend/gateway/router/router.go b/backend/gateway/router/router.go index 9f54416..c81de4d 100644 --- a/backend/gateway/router/router.go +++ b/backend/gateway/router/router.go @@ -120,9 +120,11 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl me := v1.Group("/me") me.Use(middleware.AuthMiddleware()) { - me.GET("/profile", userCtrl.GetMyProfile) // 获取当前用户粉丝档案 - me.PUT("/nickname", userCtrl.UpdateNickname) // 更新昵称 - me.PUT("/avatar", userCtrl.UpdateAvatar) // 更新头像 + me.GET("/profile", userCtrl.GetMyProfile) // 获取当前用户粉丝档案 + me.PUT("/nickname", userCtrl.UpdateNickname) // 更新昵称 + me.PUT("/avatar", userCtrl.UpdateAvatar) // 更新头像 + me.GET("/liked-assets", socialCtrl.GetMyLikedAssets) // 获取我点赞的作品列表 + me.GET("/exhibited-assets", galleryCtrl.GetMyExhibitedAssets) // 获取我展出的作品列表 } // 账户管理路由(需要认证) diff --git a/backend/pkg/proto/gallery/gallery.pb.go b/backend/pkg/proto/gallery/gallery.pb.go index b6a27ec..27a730e 100644 --- a/backend/pkg/proto/gallery/gallery.pb.go +++ b/backend/pkg/proto/gallery/gallery.pb.go @@ -939,11 +939,287 @@ func (x *RemoveFromSlotResponse) GetBase() *common.BaseResponse { return nil } +// 获取我展出的作品列表请求 +type GetMyExhibitedAssetsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` // 页码(默认1) + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量(默认20,最大100) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyExhibitedAssetsRequest) Reset() { + *x = GetMyExhibitedAssetsRequest{} + mi := &file_gallery_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyExhibitedAssetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyExhibitedAssetsRequest) ProtoMessage() {} + +func (x *GetMyExhibitedAssetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_gallery_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyExhibitedAssetsRequest.ProtoReflect.Descriptor instead. +func (*GetMyExhibitedAssetsRequest) Descriptor() ([]byte, []int) { + return file_gallery_proto_rawDescGZIP(), []int{16} +} + +func (x *GetMyExhibitedAssetsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *GetMyExhibitedAssetsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// 获取我展出的作品列表响应 +type GetMyExhibitedAssetsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` + Data *ExhibitedAssetsData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyExhibitedAssetsResponse) Reset() { + *x = GetMyExhibitedAssetsResponse{} + mi := &file_gallery_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyExhibitedAssetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyExhibitedAssetsResponse) ProtoMessage() {} + +func (x *GetMyExhibitedAssetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_gallery_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyExhibitedAssetsResponse.ProtoReflect.Descriptor instead. +func (*GetMyExhibitedAssetsResponse) Descriptor() ([]byte, []int) { + return file_gallery_proto_rawDescGZIP(), []int{17} +} + +func (x *GetMyExhibitedAssetsResponse) GetBase() *common.BaseResponse { + if x != nil { + return x.Base + } + return nil +} + +func (x *GetMyExhibitedAssetsResponse) GetData() *ExhibitedAssetsData { + if x != nil { + return x.Data + } + return nil +} + +// 展出作品数据 +type ExhibitedAssetsData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Items []*ExhibitedAssetItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` // 作品列表 + Page int32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"` // 当前页码 + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量 + Total int64 `protobuf:"varint,4,opt,name=total,proto3" json:"total,omitempty"` // 总数量 + HasMore bool `protobuf:"varint,5,opt,name=has_more,json=hasMore,proto3" json:"has_more,omitempty"` // 是否有更多 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExhibitedAssetsData) Reset() { + *x = ExhibitedAssetsData{} + mi := &file_gallery_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExhibitedAssetsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExhibitedAssetsData) ProtoMessage() {} + +func (x *ExhibitedAssetsData) ProtoReflect() protoreflect.Message { + mi := &file_gallery_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExhibitedAssetsData.ProtoReflect.Descriptor instead. +func (*ExhibitedAssetsData) Descriptor() ([]byte, []int) { + return file_gallery_proto_rawDescGZIP(), []int{18} +} + +func (x *ExhibitedAssetsData) GetItems() []*ExhibitedAssetItem { + if x != nil { + return x.Items + } + return nil +} + +func (x *ExhibitedAssetsData) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ExhibitedAssetsData) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ExhibitedAssetsData) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *ExhibitedAssetsData) GetHasMore() bool { + if x != nil { + return x.HasMore + } + return false +} + +// 展出作品项 +type ExhibitedAssetItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + AssetId int64 `protobuf:"varint,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` // 资产ID + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 藏品名称 + CoverUrl string `protobuf:"bytes,3,opt,name=cover_url,json=coverUrl,proto3" json:"cover_url,omitempty"` // 封面图URL + LikeCount int32 `protobuf:"varint,4,opt,name=like_count,json=likeCount,proto3" json:"like_count,omitempty"` // 实时点赞数 + ExhibitedAt int64 `protobuf:"varint,5,opt,name=exhibited_at,json=exhibitedAt,proto3" json:"exhibited_at,omitempty"` // 展出开始时间(毫秒时间戳) + ExpireAt int64 `protobuf:"varint,6,opt,name=expire_at,json=expireAt,proto3" json:"expire_at,omitempty"` // 展出过期时间(毫秒时间戳) + Earnings int64 `protobuf:"varint,7,opt,name=earnings,proto3" json:"earnings,omitempty"` // 当前可领取收益 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExhibitedAssetItem) Reset() { + *x = ExhibitedAssetItem{} + mi := &file_gallery_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExhibitedAssetItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExhibitedAssetItem) ProtoMessage() {} + +func (x *ExhibitedAssetItem) ProtoReflect() protoreflect.Message { + mi := &file_gallery_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExhibitedAssetItem.ProtoReflect.Descriptor instead. +func (*ExhibitedAssetItem) Descriptor() ([]byte, []int) { + return file_gallery_proto_rawDescGZIP(), []int{19} +} + +func (x *ExhibitedAssetItem) GetAssetId() int64 { + if x != nil { + return x.AssetId + } + return 0 +} + +func (x *ExhibitedAssetItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ExhibitedAssetItem) GetCoverUrl() string { + if x != nil { + return x.CoverUrl + } + return "" +} + +func (x *ExhibitedAssetItem) GetLikeCount() int32 { + if x != nil { + return x.LikeCount + } + return 0 +} + +func (x *ExhibitedAssetItem) GetExhibitedAt() int64 { + if x != nil { + return x.ExhibitedAt + } + return 0 +} + +func (x *ExhibitedAssetItem) GetExpireAt() int64 { + if x != nil { + return x.ExpireAt + } + return 0 +} + +func (x *ExhibitedAssetItem) GetEarnings() int64 { + if x != nil { + return x.Earnings + } + return 0 +} + var File_gallery_proto protoreflect.FileDescriptor const file_gallery_proto_rawDesc = "" + "\n" + - "\rgallery.proto\x12\x0ftopfans.gallery\x1a\x1cgoogle/api/annotations.proto\x1a\x12proto/common.proto\"\x15\n" + + "\rgallery.proto\x12\x0ftopfans.gallery\x1a\x12proto/common.proto\x1a\x1cgoogle/api/annotations.proto\"\x15\n" + "\x13GetMyGalleryRequest\"z\n" + "\x14GetMyGalleryResponse\x120\n" + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x120\n" + @@ -1013,7 +1289,28 @@ const file_gallery_proto_rawDesc = "" + "\x15RemoveFromSlotRequest\x12\x17\n" + "\aslot_id\x18\x01 \x01(\x03R\x06slotId\"J\n" + "\x16RemoveFromSlotResponse\x120\n" + - "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base2\x99\x05\n" + + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\"N\n" + + "\x1bGetMyExhibitedAssetsRequest\x12\x12\n" + + "\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\"\x8a\x01\n" + + "\x1cGetMyExhibitedAssetsResponse\x120\n" + + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x128\n" + + "\x04data\x18\x02 \x01(\v2$.topfans.gallery.ExhibitedAssetsDataR\x04data\"\xb2\x01\n" + + "\x13ExhibitedAssetsData\x129\n" + + "\x05items\x18\x01 \x03(\v2#.topfans.gallery.ExhibitedAssetItemR\x05items\x12\x12\n" + + "\x04page\x18\x02 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x14\n" + + "\x05total\x18\x04 \x01(\x03R\x05total\x12\x19\n" + + "\bhas_more\x18\x05 \x01(\bR\ahasMore\"\xdb\x01\n" + + "\x12ExhibitedAssetItem\x12\x19\n" + + "\basset_id\x18\x01 \x01(\x03R\aassetId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1b\n" + + "\tcover_url\x18\x03 \x01(\tR\bcoverUrl\x12\x1d\n" + + "\n" + + "like_count\x18\x04 \x01(\x05R\tlikeCount\x12!\n" + + "\fexhibited_at\x18\x05 \x01(\x03R\vexhibitedAt\x12\x1b\n" + + "\texpire_at\x18\x06 \x01(\x03R\bexpireAt\x12\x1a\n" + + "\bearnings\x18\a \x01(\x03R\bearnings2\xb4\x06\n" + "\x0eGalleryService\x12u\n" + "\fGetMyGallery\x12$.topfans.gallery.GetMyGalleryRequest\x1a%.topfans.gallery.GetMyGalleryResponse\"\x18\x82\xd3\xe4\x93\x02\x12\x12\x10/api/mygalleries\x12\x86\x01\n" + "\x0eGetUserGallery\x12&.topfans.gallery.GetUserGalleryRequest\x1a'.topfans.gallery.GetUserGalleryResponse\"#\x82\xd3\xe4\x93\x02\x1d\x12\x1b/api/galleries/{target_uid}\x12v\n" + @@ -1021,7 +1318,8 @@ const file_gallery_proto_rawDesc = "" + "PlaceAsset\x12\".topfans.gallery.PlaceAssetRequest\x1a#.topfans.gallery.PlaceAssetResponse\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\"\x14/api/galleries/place\x12}\n" + "\n" + "UnlockSlot\x12\".topfans.gallery.UnlockSlotRequest\x1a#.topfans.gallery.UnlockSlotResponse\"&\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/galleries/slots_unlock\x12\x8f\x01\n" + - "\x0eRemoveFromSlot\x12&.topfans.gallery.RemoveFromSlotRequest\x1a'.topfans.gallery.RemoveFromSlotResponse\",\x82\xd3\xe4\x93\x02&*$/api/galleries/slots/{slot_id}/assetB6Z4github.com/topfans/backend/pkg/proto/gallery;galleryb\x06proto3" + "\x0eRemoveFromSlot\x12&.topfans.gallery.RemoveFromSlotRequest\x1a'.topfans.gallery.RemoveFromSlotResponse\",\x82\xd3\xe4\x93\x02&*$/api/galleries/slots/{slot_id}/asset\x12\x98\x01\n" + + "\x14GetMyExhibitedAssets\x12,.topfans.gallery.GetMyExhibitedAssetsRequest\x1a-.topfans.gallery.GetMyExhibitedAssetsResponse\"#\x82\xd3\xe4\x93\x02\x1d\x12\x1b/api/v1/me/exhibited-assetsB6Z4github.com/topfans/backend/pkg/proto/gallery;galleryb\x06proto3" var ( file_gallery_proto_rawDescOnce sync.Once @@ -1035,54 +1333,63 @@ func file_gallery_proto_rawDescGZIP() []byte { return file_gallery_proto_rawDescData } -var file_gallery_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_gallery_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_gallery_proto_goTypes = []any{ - (*GetMyGalleryRequest)(nil), // 0: topfans.gallery.GetMyGalleryRequest - (*GetMyGalleryResponse)(nil), // 1: topfans.gallery.GetMyGalleryResponse - (*GetUserGalleryRequest)(nil), // 2: topfans.gallery.GetUserGalleryRequest - (*GetUserGalleryResponse)(nil), // 3: topfans.gallery.GetUserGalleryResponse - (*PlaceAssetRequest)(nil), // 4: topfans.gallery.PlaceAssetRequest - (*PlaceAssetResponse)(nil), // 5: topfans.gallery.PlaceAssetResponse - (*UnlockSlotRequest)(nil), // 6: topfans.gallery.UnlockSlotRequest - (*UnlockSlotResponse)(nil), // 7: topfans.gallery.UnlockSlotResponse - (*GalleryData)(nil), // 8: topfans.gallery.GalleryData - (*SlotInfo)(nil), // 9: topfans.gallery.SlotInfo - (*AssetInfo)(nil), // 10: topfans.gallery.AssetInfo - (*UnlockCondition)(nil), // 11: topfans.gallery.UnlockCondition - (*PlaceAssetData)(nil), // 12: topfans.gallery.PlaceAssetData - (*UnlockSlotData)(nil), // 13: topfans.gallery.UnlockSlotData - (*RemoveFromSlotRequest)(nil), // 14: topfans.gallery.RemoveFromSlotRequest - (*RemoveFromSlotResponse)(nil), // 15: topfans.gallery.RemoveFromSlotResponse - (*common.BaseResponse)(nil), // 16: topfans.common.BaseResponse + (*GetMyGalleryRequest)(nil), // 0: topfans.gallery.GetMyGalleryRequest + (*GetMyGalleryResponse)(nil), // 1: topfans.gallery.GetMyGalleryResponse + (*GetUserGalleryRequest)(nil), // 2: topfans.gallery.GetUserGalleryRequest + (*GetUserGalleryResponse)(nil), // 3: topfans.gallery.GetUserGalleryResponse + (*PlaceAssetRequest)(nil), // 4: topfans.gallery.PlaceAssetRequest + (*PlaceAssetResponse)(nil), // 5: topfans.gallery.PlaceAssetResponse + (*UnlockSlotRequest)(nil), // 6: topfans.gallery.UnlockSlotRequest + (*UnlockSlotResponse)(nil), // 7: topfans.gallery.UnlockSlotResponse + (*GalleryData)(nil), // 8: topfans.gallery.GalleryData + (*SlotInfo)(nil), // 9: topfans.gallery.SlotInfo + (*AssetInfo)(nil), // 10: topfans.gallery.AssetInfo + (*UnlockCondition)(nil), // 11: topfans.gallery.UnlockCondition + (*PlaceAssetData)(nil), // 12: topfans.gallery.PlaceAssetData + (*UnlockSlotData)(nil), // 13: topfans.gallery.UnlockSlotData + (*RemoveFromSlotRequest)(nil), // 14: topfans.gallery.RemoveFromSlotRequest + (*RemoveFromSlotResponse)(nil), // 15: topfans.gallery.RemoveFromSlotResponse + (*GetMyExhibitedAssetsRequest)(nil), // 16: topfans.gallery.GetMyExhibitedAssetsRequest + (*GetMyExhibitedAssetsResponse)(nil), // 17: topfans.gallery.GetMyExhibitedAssetsResponse + (*ExhibitedAssetsData)(nil), // 18: topfans.gallery.ExhibitedAssetsData + (*ExhibitedAssetItem)(nil), // 19: topfans.gallery.ExhibitedAssetItem + (*common.BaseResponse)(nil), // 20: topfans.common.BaseResponse } var file_gallery_proto_depIdxs = []int32{ - 16, // 0: topfans.gallery.GetMyGalleryResponse.base:type_name -> topfans.common.BaseResponse + 20, // 0: topfans.gallery.GetMyGalleryResponse.base:type_name -> topfans.common.BaseResponse 8, // 1: topfans.gallery.GetMyGalleryResponse.data:type_name -> topfans.gallery.GalleryData - 16, // 2: topfans.gallery.GetUserGalleryResponse.base:type_name -> topfans.common.BaseResponse + 20, // 2: topfans.gallery.GetUserGalleryResponse.base:type_name -> topfans.common.BaseResponse 8, // 3: topfans.gallery.GetUserGalleryResponse.data:type_name -> topfans.gallery.GalleryData - 16, // 4: topfans.gallery.PlaceAssetResponse.base:type_name -> topfans.common.BaseResponse + 20, // 4: topfans.gallery.PlaceAssetResponse.base:type_name -> topfans.common.BaseResponse 12, // 5: topfans.gallery.PlaceAssetResponse.data:type_name -> topfans.gallery.PlaceAssetData - 16, // 6: topfans.gallery.UnlockSlotResponse.base:type_name -> topfans.common.BaseResponse + 20, // 6: topfans.gallery.UnlockSlotResponse.base:type_name -> topfans.common.BaseResponse 13, // 7: topfans.gallery.UnlockSlotResponse.data:type_name -> topfans.gallery.UnlockSlotData 9, // 8: topfans.gallery.GalleryData.slots:type_name -> topfans.gallery.SlotInfo 10, // 9: topfans.gallery.SlotInfo.asset:type_name -> topfans.gallery.AssetInfo 11, // 10: topfans.gallery.SlotInfo.unlock_condition:type_name -> topfans.gallery.UnlockCondition - 16, // 11: topfans.gallery.RemoveFromSlotResponse.base:type_name -> topfans.common.BaseResponse - 0, // 12: topfans.gallery.GalleryService.GetMyGallery:input_type -> topfans.gallery.GetMyGalleryRequest - 2, // 13: topfans.gallery.GalleryService.GetUserGallery:input_type -> topfans.gallery.GetUserGalleryRequest - 4, // 14: topfans.gallery.GalleryService.PlaceAsset:input_type -> topfans.gallery.PlaceAssetRequest - 6, // 15: topfans.gallery.GalleryService.UnlockSlot:input_type -> topfans.gallery.UnlockSlotRequest - 14, // 16: topfans.gallery.GalleryService.RemoveFromSlot:input_type -> topfans.gallery.RemoveFromSlotRequest - 1, // 17: topfans.gallery.GalleryService.GetMyGallery:output_type -> topfans.gallery.GetMyGalleryResponse - 3, // 18: topfans.gallery.GalleryService.GetUserGallery:output_type -> topfans.gallery.GetUserGalleryResponse - 5, // 19: topfans.gallery.GalleryService.PlaceAsset:output_type -> topfans.gallery.PlaceAssetResponse - 7, // 20: topfans.gallery.GalleryService.UnlockSlot:output_type -> topfans.gallery.UnlockSlotResponse - 15, // 21: topfans.gallery.GalleryService.RemoveFromSlot:output_type -> topfans.gallery.RemoveFromSlotResponse - 17, // [17:22] is the sub-list for method output_type - 12, // [12:17] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 20, // 11: topfans.gallery.RemoveFromSlotResponse.base:type_name -> topfans.common.BaseResponse + 20, // 12: topfans.gallery.GetMyExhibitedAssetsResponse.base:type_name -> topfans.common.BaseResponse + 18, // 13: topfans.gallery.GetMyExhibitedAssetsResponse.data:type_name -> topfans.gallery.ExhibitedAssetsData + 19, // 14: topfans.gallery.ExhibitedAssetsData.items:type_name -> topfans.gallery.ExhibitedAssetItem + 0, // 15: topfans.gallery.GalleryService.GetMyGallery:input_type -> topfans.gallery.GetMyGalleryRequest + 2, // 16: topfans.gallery.GalleryService.GetUserGallery:input_type -> topfans.gallery.GetUserGalleryRequest + 4, // 17: topfans.gallery.GalleryService.PlaceAsset:input_type -> topfans.gallery.PlaceAssetRequest + 6, // 18: topfans.gallery.GalleryService.UnlockSlot:input_type -> topfans.gallery.UnlockSlotRequest + 14, // 19: topfans.gallery.GalleryService.RemoveFromSlot:input_type -> topfans.gallery.RemoveFromSlotRequest + 16, // 20: topfans.gallery.GalleryService.GetMyExhibitedAssets:input_type -> topfans.gallery.GetMyExhibitedAssetsRequest + 1, // 21: topfans.gallery.GalleryService.GetMyGallery:output_type -> topfans.gallery.GetMyGalleryResponse + 3, // 22: topfans.gallery.GalleryService.GetUserGallery:output_type -> topfans.gallery.GetUserGalleryResponse + 5, // 23: topfans.gallery.GalleryService.PlaceAsset:output_type -> topfans.gallery.PlaceAssetResponse + 7, // 24: topfans.gallery.GalleryService.UnlockSlot:output_type -> topfans.gallery.UnlockSlotResponse + 15, // 25: topfans.gallery.GalleryService.RemoveFromSlot:output_type -> topfans.gallery.RemoveFromSlotResponse + 17, // 26: topfans.gallery.GalleryService.GetMyExhibitedAssets:output_type -> topfans.gallery.GetMyExhibitedAssetsResponse + 21, // [21:27] is the sub-list for method output_type + 15, // [15:21] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_gallery_proto_init() } @@ -1096,7 +1403,7 @@ func file_gallery_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_gallery_proto_rawDesc), len(file_gallery_proto_rawDesc)), NumEnums: 0, - NumMessages: 16, + NumMessages: 20, NumExtensions: 0, NumServices: 1, }, diff --git a/backend/pkg/proto/gallery/gallery.triple.go b/backend/pkg/proto/gallery/gallery.triple.go index 8b5e0d1..18b0bd9 100644 --- a/backend/pkg/proto/gallery/gallery.triple.go +++ b/backend/pkg/proto/gallery/gallery.triple.go @@ -46,6 +46,8 @@ const ( GalleryServiceUnlockSlotProcedure = "/topfans.gallery.GalleryService/UnlockSlot" // GalleryServiceRemoveFromSlotProcedure is the fully-qualified name of the GalleryService's RemoveFromSlot RPC. GalleryServiceRemoveFromSlotProcedure = "/topfans.gallery.GalleryService/RemoveFromSlot" + // GalleryServiceGetMyExhibitedAssetsProcedure is the fully-qualified name of the GalleryService's GetMyExhibitedAssets RPC. + GalleryServiceGetMyExhibitedAssetsProcedure = "/topfans.gallery.GalleryService/GetMyExhibitedAssets" ) var ( @@ -59,6 +61,7 @@ type GalleryService interface { PlaceAsset(ctx context.Context, req *PlaceAssetRequest, opts ...client.CallOption) (*PlaceAssetResponse, error) UnlockSlot(ctx context.Context, req *UnlockSlotRequest, opts ...client.CallOption) (*UnlockSlotResponse, error) RemoveFromSlot(ctx context.Context, req *RemoveFromSlotRequest, opts ...client.CallOption) (*RemoveFromSlotResponse, error) + GetMyExhibitedAssets(ctx context.Context, req *GetMyExhibitedAssetsRequest, opts ...client.CallOption) (*GetMyExhibitedAssetsResponse, error) } // NewGalleryService constructs a client for the gallery.GalleryService service. @@ -121,9 +124,17 @@ func (c *GalleryServiceImpl) RemoveFromSlot(ctx context.Context, req *RemoveFrom return resp, nil } +func (c *GalleryServiceImpl) GetMyExhibitedAssets(ctx context.Context, req *GetMyExhibitedAssetsRequest, opts ...client.CallOption) (*GetMyExhibitedAssetsResponse, error) { + resp := new(GetMyExhibitedAssetsResponse) + if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyExhibitedAssets", opts...); err != nil { + return nil, err + } + return resp, nil +} + var GalleryService_ClientInfo = client.ClientInfo{ InterfaceName: "topfans.gallery.GalleryService", - MethodNames: []string{"GetMyGallery", "GetUserGallery", "PlaceAsset", "UnlockSlot", "RemoveFromSlot"}, + MethodNames: []string{"GetMyGallery", "GetUserGallery", "PlaceAsset", "UnlockSlot", "RemoveFromSlot", "GetMyExhibitedAssets"}, ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) { dubboCli := dubboCliRaw.(*GalleryServiceImpl) dubboCli.conn = conn @@ -137,6 +148,7 @@ type GalleryServiceHandler interface { PlaceAsset(context.Context, *PlaceAssetRequest) (*PlaceAssetResponse, error) UnlockSlot(context.Context, *UnlockSlotRequest) (*UnlockSlotResponse, error) RemoveFromSlot(context.Context, *RemoveFromSlotRequest) (*RemoveFromSlotResponse, error) + GetMyExhibitedAssets(context.Context, *GetMyExhibitedAssetsRequest) (*GetMyExhibitedAssetsResponse, error) } func RegisterGalleryServiceHandler(srv *server.Server, hdlr GalleryServiceHandler, opts ...server.ServiceOption) error { @@ -226,5 +238,20 @@ var GalleryService_ServiceInfo = server.ServiceInfo{ return triple_protocol.NewResponse(res), nil }, }, + { + Name: "GetMyExhibitedAssets", + Type: constant.CallUnary, + ReqInitFunc: func() interface{} { + return new(GetMyExhibitedAssetsRequest) + }, + MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) { + req := args[0].(*GetMyExhibitedAssetsRequest) + res, err := handler.(GalleryServiceHandler).GetMyExhibitedAssets(ctx, req) + if err != nil { + return nil, err + } + return triple_protocol.NewResponse(res), nil + }, + }, }, } diff --git a/backend/pkg/proto/social/social.pb.go b/backend/pkg/proto/social/social.pb.go index 4cdd8c0..d96f5ff 100644 --- a/backend/pkg/proto/social/social.pb.go +++ b/backend/pkg/proto/social/social.pb.go @@ -2148,6 +2148,486 @@ func (x *CheckAssetLikeResponse) GetIsLiked() bool { return false } +// 获取我点赞的作品列表请求 +type GetMyLikedAssetsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` // 页码(默认1) + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量(默认20,最大100) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyLikedAssetsRequest) Reset() { + *x = GetMyLikedAssetsRequest{} + mi := &file_social_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyLikedAssetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyLikedAssetsRequest) ProtoMessage() {} + +func (x *GetMyLikedAssetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyLikedAssetsRequest.ProtoReflect.Descriptor instead. +func (*GetMyLikedAssetsRequest) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{33} +} + +func (x *GetMyLikedAssetsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *GetMyLikedAssetsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// 获取我点赞的作品列表响应 +type GetMyLikedAssetsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` + Data *LikedAssetsData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyLikedAssetsResponse) Reset() { + *x = GetMyLikedAssetsResponse{} + mi := &file_social_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyLikedAssetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyLikedAssetsResponse) ProtoMessage() {} + +func (x *GetMyLikedAssetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyLikedAssetsResponse.ProtoReflect.Descriptor instead. +func (*GetMyLikedAssetsResponse) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{34} +} + +func (x *GetMyLikedAssetsResponse) GetBase() *common.BaseResponse { + if x != nil { + return x.Base + } + return nil +} + +func (x *GetMyLikedAssetsResponse) GetData() *LikedAssetsData { + if x != nil { + return x.Data + } + return nil +} + +// 点赞作品数据 +type LikedAssetsData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Items []*LikedAssetItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` // 作品列表 + Page int32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"` // 当前页码 + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量 + Total int64 `protobuf:"varint,4,opt,name=total,proto3" json:"total,omitempty"` // 总数量 + HasMore bool `protobuf:"varint,5,opt,name=has_more,json=hasMore,proto3" json:"has_more,omitempty"` // 是否有更多 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LikedAssetsData) Reset() { + *x = LikedAssetsData{} + mi := &file_social_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LikedAssetsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LikedAssetsData) ProtoMessage() {} + +func (x *LikedAssetsData) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LikedAssetsData.ProtoReflect.Descriptor instead. +func (*LikedAssetsData) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{35} +} + +func (x *LikedAssetsData) GetItems() []*LikedAssetItem { + if x != nil { + return x.Items + } + return nil +} + +func (x *LikedAssetsData) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *LikedAssetsData) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *LikedAssetsData) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *LikedAssetsData) GetHasMore() bool { + if x != nil { + return x.HasMore + } + return false +} + +// 点赞作品项 +type LikedAssetItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + AssetId int64 `protobuf:"varint,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` // 资产ID + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 藏品名称 + CoverUrl string `protobuf:"bytes,3,opt,name=cover_url,json=coverUrl,proto3" json:"cover_url,omitempty"` // 封面图URL + LikeCount int32 `protobuf:"varint,4,opt,name=like_count,json=likeCount,proto3" json:"like_count,omitempty"` // 实时点赞数 + LikedAt int64 `protobuf:"varint,5,opt,name=liked_at,json=likedAt,proto3" json:"liked_at,omitempty"` // 点赞时间(毫秒时间戳) + Earnings int64 `protobuf:"varint,6,opt,name=earnings,proto3" json:"earnings,omitempty"` // 当前可领取收益 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LikedAssetItem) Reset() { + *x = LikedAssetItem{} + mi := &file_social_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LikedAssetItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LikedAssetItem) ProtoMessage() {} + +func (x *LikedAssetItem) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LikedAssetItem.ProtoReflect.Descriptor instead. +func (*LikedAssetItem) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{36} +} + +func (x *LikedAssetItem) GetAssetId() int64 { + if x != nil { + return x.AssetId + } + return 0 +} + +func (x *LikedAssetItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *LikedAssetItem) GetCoverUrl() string { + if x != nil { + return x.CoverUrl + } + return "" +} + +func (x *LikedAssetItem) GetLikeCount() int32 { + if x != nil { + return x.LikeCount + } + return 0 +} + +func (x *LikedAssetItem) GetLikedAt() int64 { + if x != nil { + return x.LikedAt + } + return 0 +} + +func (x *LikedAssetItem) GetEarnings() int64 { + if x != nil { + return x.Earnings + } + return 0 +} + +// 获取我今日点赞的作品列表请求(暂不实现) +type GetMyTodayLikedAssetsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` // 页码(默认1) + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量(默认20,最大100) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyTodayLikedAssetsRequest) Reset() { + *x = GetMyTodayLikedAssetsRequest{} + mi := &file_social_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyTodayLikedAssetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyTodayLikedAssetsRequest) ProtoMessage() {} + +func (x *GetMyTodayLikedAssetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyTodayLikedAssetsRequest.ProtoReflect.Descriptor instead. +func (*GetMyTodayLikedAssetsRequest) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{37} +} + +func (x *GetMyTodayLikedAssetsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *GetMyTodayLikedAssetsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// 获取我今日点赞的作品列表响应(暂不实现) +type GetMyTodayLikedAssetsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` + Data *LikedAssetsData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyTodayLikedAssetsResponse) Reset() { + *x = GetMyTodayLikedAssetsResponse{} + mi := &file_social_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyTodayLikedAssetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyTodayLikedAssetsResponse) ProtoMessage() {} + +func (x *GetMyTodayLikedAssetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyTodayLikedAssetsResponse.ProtoReflect.Descriptor instead. +func (*GetMyTodayLikedAssetsResponse) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{38} +} + +func (x *GetMyTodayLikedAssetsResponse) GetBase() *common.BaseResponse { + if x != nil { + return x.Base + } + return nil +} + +func (x *GetMyTodayLikedAssetsResponse) GetData() *LikedAssetsData { + if x != nil { + return x.Data + } + return nil +} + +// 获取我本周点赞的作品列表请求(暂不实现) +type GetMyWeekLikedAssetsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` // 页码(默认1) + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 每页数量(默认20,最大100) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyWeekLikedAssetsRequest) Reset() { + *x = GetMyWeekLikedAssetsRequest{} + mi := &file_social_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyWeekLikedAssetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyWeekLikedAssetsRequest) ProtoMessage() {} + +func (x *GetMyWeekLikedAssetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyWeekLikedAssetsRequest.ProtoReflect.Descriptor instead. +func (*GetMyWeekLikedAssetsRequest) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{39} +} + +func (x *GetMyWeekLikedAssetsRequest) GetPage() int32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *GetMyWeekLikedAssetsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +// 获取我本周点赞的作品列表响应(暂不实现) +type GetMyWeekLikedAssetsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"` + Data *LikedAssetsData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetMyWeekLikedAssetsResponse) Reset() { + *x = GetMyWeekLikedAssetsResponse{} + mi := &file_social_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetMyWeekLikedAssetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMyWeekLikedAssetsResponse) ProtoMessage() {} + +func (x *GetMyWeekLikedAssetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_social_proto_msgTypes[40] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMyWeekLikedAssetsResponse.ProtoReflect.Descriptor instead. +func (*GetMyWeekLikedAssetsResponse) Descriptor() ([]byte, []int) { + return file_social_proto_rawDescGZIP(), []int{40} +} + +func (x *GetMyWeekLikedAssetsResponse) GetBase() *common.BaseResponse { + if x != nil { + return x.Base + } + return nil +} + +func (x *GetMyWeekLikedAssetsResponse) GetData() *LikedAssetsData { + if x != nil { + return x.Data + } + return nil +} + var File_social_proto protoreflect.FileDescriptor const file_social_proto_rawDesc = "" + @@ -2313,7 +2793,39 @@ const file_social_proto_rawDesc = "" + "\basset_id\x18\x01 \x01(\x03R\aassetId\"e\n" + "\x16CheckAssetLikeResponse\x120\n" + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x12\x19\n" + - "\bis_liked\x18\x02 \x01(\bR\aisLiked2\xb7\x0f\n" + + "\bis_liked\x18\x02 \x01(\bR\aisLiked\"J\n" + + "\x17GetMyLikedAssetsRequest\x12\x12\n" + + "\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\"\x81\x01\n" + + "\x18GetMyLikedAssetsResponse\x120\n" + + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x123\n" + + "\x04data\x18\x02 \x01(\v2\x1f.topfans.social.LikedAssetsDataR\x04data\"\xa9\x01\n" + + "\x0fLikedAssetsData\x124\n" + + "\x05items\x18\x01 \x03(\v2\x1e.topfans.social.LikedAssetItemR\x05items\x12\x12\n" + + "\x04page\x18\x02 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x12\x14\n" + + "\x05total\x18\x04 \x01(\x03R\x05total\x12\x19\n" + + "\bhas_more\x18\x05 \x01(\bR\ahasMore\"\xb2\x01\n" + + "\x0eLikedAssetItem\x12\x19\n" + + "\basset_id\x18\x01 \x01(\x03R\aassetId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1b\n" + + "\tcover_url\x18\x03 \x01(\tR\bcoverUrl\x12\x1d\n" + + "\n" + + "like_count\x18\x04 \x01(\x05R\tlikeCount\x12\x19\n" + + "\bliked_at\x18\x05 \x01(\x03R\alikedAt\x12\x1a\n" + + "\bearnings\x18\x06 \x01(\x03R\bearnings\"O\n" + + "\x1cGetMyTodayLikedAssetsRequest\x12\x12\n" + + "\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\"\x86\x01\n" + + "\x1dGetMyTodayLikedAssetsResponse\x120\n" + + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x123\n" + + "\x04data\x18\x02 \x01(\v2\x1f.topfans.social.LikedAssetsDataR\x04data\"N\n" + + "\x1bGetMyWeekLikedAssetsRequest\x12\x12\n" + + "\x04page\x18\x01 \x01(\x05R\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\"\x85\x01\n" + + "\x1cGetMyWeekLikedAssetsResponse\x120\n" + + "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x123\n" + + "\x04data\x18\x02 \x01(\v2\x1f.topfans.social.LikedAssetsDataR\x04data2\xf8\x12\n" + "\rSocialService\x12\x8d\x01\n" + "\x11SendFriendRequest\x12(.topfans.social.SendFriendRequestRequest\x1a).topfans.social.SendFriendRequestResponse\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/v1/friends/requests\x12\x8a\x01\n" + "\x11GetFriendRequests\x12(.topfans.social.GetFriendRequestsRequest\x1a).topfans.social.GetFriendRequestsResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/api/v1/friends/requests\x12\xa7\x01\n" + @@ -2328,7 +2840,10 @@ const file_social_proto_rawDesc = "" + "\rGetUsersPaged\x12$.topfans.social.GetUsersPagedRequest\x1a%.topfans.social.GetUsersPagedResponse\"\x1c\x82\xd3\xe4\x93\x02\x16\x12\x14/api/v1/social/users\x12\x7f\n" + "\tLikeAsset\x12 .topfans.social.LikeAssetRequest\x1a!.topfans.social.LikeAssetResponse\"-\x82\xd3\xe4\x93\x02'\"%/api/v1/social/assets/{asset_id}/like\x12\x85\x01\n" + "\vUnlikeAsset\x12\".topfans.social.UnlikeAssetRequest\x1a#.topfans.social.UnlikeAssetResponse\"-\x82\xd3\xe4\x93\x02'*%/api/v1/social/assets/{asset_id}/like\x12\x8e\x01\n" + - "\x0eCheckAssetLike\x12%.topfans.social.CheckAssetLikeRequest\x1a&.topfans.social.CheckAssetLikeResponse\"-\x82\xd3\xe4\x93\x02'\x12%/api/v1/social/assets/{asset_id}/likeB4Z2github.com/topfans/backend/pkg/proto/social;socialb\x06proto3" + "\x0eCheckAssetLike\x12%.topfans.social.CheckAssetLikeRequest\x1a&.topfans.social.CheckAssetLikeResponse\"-\x82\xd3\xe4\x93\x02'\x12%/api/v1/social/assets/{asset_id}/like\x12\x86\x01\n" + + "\x10GetMyLikedAssets\x12'.topfans.social.GetMyLikedAssetsRequest\x1a(.topfans.social.GetMyLikedAssetsResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\x12\x17/api/v1/me/liked-assets\x12\x9b\x01\n" + + "\x15GetMyTodayLikedAssets\x12,.topfans.social.GetMyTodayLikedAssetsRequest\x1a-.topfans.social.GetMyTodayLikedAssetsResponse\"%\x82\xd3\xe4\x93\x02\x1f\x12\x1d/api/v1/me/today-liked-assets\x12\x97\x01\n" + + "\x14GetMyWeekLikedAssets\x12+.topfans.social.GetMyWeekLikedAssetsRequest\x1a,.topfans.social.GetMyWeekLikedAssetsResponse\"$\x82\xd3\xe4\x93\x02\x1e\x12\x1c/api/v1/me/week-liked-assetsB4Z2github.com/topfans/backend/pkg/proto/social;socialb\x06proto3" var ( file_social_proto_rawDescOnce sync.Once @@ -2342,97 +2857,118 @@ func file_social_proto_rawDescGZIP() []byte { return file_social_proto_rawDescData } -var file_social_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_social_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_social_proto_goTypes = []any{ - (*FriendRequest)(nil), // 0: topfans.social.FriendRequest - (*Friendship)(nil), // 1: topfans.social.Friendship - (*SendFriendRequestRequest)(nil), // 2: topfans.social.SendFriendRequestRequest - (*SendFriendRequestResponse)(nil), // 3: topfans.social.SendFriendRequestResponse - (*GetFriendRequestsRequest)(nil), // 4: topfans.social.GetFriendRequestsRequest - (*GetFriendRequestsResponse)(nil), // 5: topfans.social.GetFriendRequestsResponse - (*HandleFriendRequestRequest)(nil), // 6: topfans.social.HandleFriendRequestRequest - (*HandleFriendRequestResponse)(nil), // 7: topfans.social.HandleFriendRequestResponse - (*GetFriendListRequest)(nil), // 8: topfans.social.GetFriendListRequest - (*GetFriendListResponse)(nil), // 9: topfans.social.GetFriendListResponse - (*DeleteFriendRequest)(nil), // 10: topfans.social.DeleteFriendRequest - (*DeleteFriendResponse)(nil), // 11: topfans.social.DeleteFriendResponse - (*SetFriendRemarkRequest)(nil), // 12: topfans.social.SetFriendRemarkRequest - (*SetFriendRemarkResponse)(nil), // 13: topfans.social.SetFriendRemarkResponse - (*CheckFriendshipRequest)(nil), // 14: topfans.social.CheckFriendshipRequest - (*CheckFriendshipResponse)(nil), // 15: topfans.social.CheckFriendshipResponse - (*GetFriendCountRequest)(nil), // 16: topfans.social.GetFriendCountRequest - (*GetFriendCountResponse)(nil), // 17: topfans.social.GetFriendCountResponse - (*SearchUserForFriendRequest)(nil), // 18: topfans.social.SearchUserForFriendRequest - (*SearchUserForFriendResponse)(nil), // 19: topfans.social.SearchUserForFriendResponse - (*FanProfileSearchResult)(nil), // 20: topfans.social.FanProfileSearchResult - (*RandomUser)(nil), // 21: topfans.social.RandomUser - (*GetRandomUsersRequest)(nil), // 22: topfans.social.GetRandomUsersRequest - (*GetRandomUsersResponse)(nil), // 23: topfans.social.GetRandomUsersResponse - (*PagedUser)(nil), // 24: topfans.social.PagedUser - (*GetUsersPagedRequest)(nil), // 25: topfans.social.GetUsersPagedRequest - (*GetUsersPagedResponse)(nil), // 26: topfans.social.GetUsersPagedResponse - (*LikeAssetRequest)(nil), // 27: topfans.social.LikeAssetRequest - (*LikeAssetResponse)(nil), // 28: topfans.social.LikeAssetResponse - (*UnlikeAssetRequest)(nil), // 29: topfans.social.UnlikeAssetRequest - (*UnlikeAssetResponse)(nil), // 30: topfans.social.UnlikeAssetResponse - (*CheckAssetLikeRequest)(nil), // 31: topfans.social.CheckAssetLikeRequest - (*CheckAssetLikeResponse)(nil), // 32: topfans.social.CheckAssetLikeResponse - (*common.BaseResponse)(nil), // 33: topfans.common.BaseResponse + (*FriendRequest)(nil), // 0: topfans.social.FriendRequest + (*Friendship)(nil), // 1: topfans.social.Friendship + (*SendFriendRequestRequest)(nil), // 2: topfans.social.SendFriendRequestRequest + (*SendFriendRequestResponse)(nil), // 3: topfans.social.SendFriendRequestResponse + (*GetFriendRequestsRequest)(nil), // 4: topfans.social.GetFriendRequestsRequest + (*GetFriendRequestsResponse)(nil), // 5: topfans.social.GetFriendRequestsResponse + (*HandleFriendRequestRequest)(nil), // 6: topfans.social.HandleFriendRequestRequest + (*HandleFriendRequestResponse)(nil), // 7: topfans.social.HandleFriendRequestResponse + (*GetFriendListRequest)(nil), // 8: topfans.social.GetFriendListRequest + (*GetFriendListResponse)(nil), // 9: topfans.social.GetFriendListResponse + (*DeleteFriendRequest)(nil), // 10: topfans.social.DeleteFriendRequest + (*DeleteFriendResponse)(nil), // 11: topfans.social.DeleteFriendResponse + (*SetFriendRemarkRequest)(nil), // 12: topfans.social.SetFriendRemarkRequest + (*SetFriendRemarkResponse)(nil), // 13: topfans.social.SetFriendRemarkResponse + (*CheckFriendshipRequest)(nil), // 14: topfans.social.CheckFriendshipRequest + (*CheckFriendshipResponse)(nil), // 15: topfans.social.CheckFriendshipResponse + (*GetFriendCountRequest)(nil), // 16: topfans.social.GetFriendCountRequest + (*GetFriendCountResponse)(nil), // 17: topfans.social.GetFriendCountResponse + (*SearchUserForFriendRequest)(nil), // 18: topfans.social.SearchUserForFriendRequest + (*SearchUserForFriendResponse)(nil), // 19: topfans.social.SearchUserForFriendResponse + (*FanProfileSearchResult)(nil), // 20: topfans.social.FanProfileSearchResult + (*RandomUser)(nil), // 21: topfans.social.RandomUser + (*GetRandomUsersRequest)(nil), // 22: topfans.social.GetRandomUsersRequest + (*GetRandomUsersResponse)(nil), // 23: topfans.social.GetRandomUsersResponse + (*PagedUser)(nil), // 24: topfans.social.PagedUser + (*GetUsersPagedRequest)(nil), // 25: topfans.social.GetUsersPagedRequest + (*GetUsersPagedResponse)(nil), // 26: topfans.social.GetUsersPagedResponse + (*LikeAssetRequest)(nil), // 27: topfans.social.LikeAssetRequest + (*LikeAssetResponse)(nil), // 28: topfans.social.LikeAssetResponse + (*UnlikeAssetRequest)(nil), // 29: topfans.social.UnlikeAssetRequest + (*UnlikeAssetResponse)(nil), // 30: topfans.social.UnlikeAssetResponse + (*CheckAssetLikeRequest)(nil), // 31: topfans.social.CheckAssetLikeRequest + (*CheckAssetLikeResponse)(nil), // 32: topfans.social.CheckAssetLikeResponse + (*GetMyLikedAssetsRequest)(nil), // 33: topfans.social.GetMyLikedAssetsRequest + (*GetMyLikedAssetsResponse)(nil), // 34: topfans.social.GetMyLikedAssetsResponse + (*LikedAssetsData)(nil), // 35: topfans.social.LikedAssetsData + (*LikedAssetItem)(nil), // 36: topfans.social.LikedAssetItem + (*GetMyTodayLikedAssetsRequest)(nil), // 37: topfans.social.GetMyTodayLikedAssetsRequest + (*GetMyTodayLikedAssetsResponse)(nil), // 38: topfans.social.GetMyTodayLikedAssetsResponse + (*GetMyWeekLikedAssetsRequest)(nil), // 39: topfans.social.GetMyWeekLikedAssetsRequest + (*GetMyWeekLikedAssetsResponse)(nil), // 40: topfans.social.GetMyWeekLikedAssetsResponse + (*common.BaseResponse)(nil), // 41: topfans.common.BaseResponse } var file_social_proto_depIdxs = []int32{ - 33, // 0: topfans.social.SendFriendRequestResponse.base:type_name -> topfans.common.BaseResponse + 41, // 0: topfans.social.SendFriendRequestResponse.base:type_name -> topfans.common.BaseResponse 20, // 1: topfans.social.SendFriendRequestResponse.matched_users:type_name -> topfans.social.FanProfileSearchResult - 33, // 2: topfans.social.GetFriendRequestsResponse.base:type_name -> topfans.common.BaseResponse + 41, // 2: topfans.social.GetFriendRequestsResponse.base:type_name -> topfans.common.BaseResponse 0, // 3: topfans.social.GetFriendRequestsResponse.items:type_name -> topfans.social.FriendRequest - 33, // 4: topfans.social.HandleFriendRequestResponse.base:type_name -> topfans.common.BaseResponse - 33, // 5: topfans.social.GetFriendListResponse.base:type_name -> topfans.common.BaseResponse + 41, // 4: topfans.social.HandleFriendRequestResponse.base:type_name -> topfans.common.BaseResponse + 41, // 5: topfans.social.GetFriendListResponse.base:type_name -> topfans.common.BaseResponse 1, // 6: topfans.social.GetFriendListResponse.items:type_name -> topfans.social.Friendship - 33, // 7: topfans.social.DeleteFriendResponse.base:type_name -> topfans.common.BaseResponse - 33, // 8: topfans.social.SetFriendRemarkResponse.base:type_name -> topfans.common.BaseResponse - 33, // 9: topfans.social.CheckFriendshipResponse.base:type_name -> topfans.common.BaseResponse - 33, // 10: topfans.social.GetFriendCountResponse.base:type_name -> topfans.common.BaseResponse - 33, // 11: topfans.social.SearchUserForFriendResponse.base:type_name -> topfans.common.BaseResponse + 41, // 7: topfans.social.DeleteFriendResponse.base:type_name -> topfans.common.BaseResponse + 41, // 8: topfans.social.SetFriendRemarkResponse.base:type_name -> topfans.common.BaseResponse + 41, // 9: topfans.social.CheckFriendshipResponse.base:type_name -> topfans.common.BaseResponse + 41, // 10: topfans.social.GetFriendCountResponse.base:type_name -> topfans.common.BaseResponse + 41, // 11: topfans.social.SearchUserForFriendResponse.base:type_name -> topfans.common.BaseResponse 20, // 12: topfans.social.SearchUserForFriendResponse.user:type_name -> topfans.social.FanProfileSearchResult - 33, // 13: topfans.social.GetRandomUsersResponse.base:type_name -> topfans.common.BaseResponse + 41, // 13: topfans.social.GetRandomUsersResponse.base:type_name -> topfans.common.BaseResponse 21, // 14: topfans.social.GetRandomUsersResponse.users:type_name -> topfans.social.RandomUser - 33, // 15: topfans.social.GetUsersPagedResponse.base:type_name -> topfans.common.BaseResponse + 41, // 15: topfans.social.GetUsersPagedResponse.base:type_name -> topfans.common.BaseResponse 24, // 16: topfans.social.GetUsersPagedResponse.users:type_name -> topfans.social.PagedUser - 33, // 17: topfans.social.LikeAssetResponse.base:type_name -> topfans.common.BaseResponse - 33, // 18: topfans.social.UnlikeAssetResponse.base:type_name -> topfans.common.BaseResponse - 33, // 19: topfans.social.CheckAssetLikeResponse.base:type_name -> topfans.common.BaseResponse - 2, // 20: topfans.social.SocialService.SendFriendRequest:input_type -> topfans.social.SendFriendRequestRequest - 4, // 21: topfans.social.SocialService.GetFriendRequests:input_type -> topfans.social.GetFriendRequestsRequest - 6, // 22: topfans.social.SocialService.HandleFriendRequest:input_type -> topfans.social.HandleFriendRequestRequest - 8, // 23: topfans.social.SocialService.GetFriendList:input_type -> topfans.social.GetFriendListRequest - 10, // 24: topfans.social.SocialService.DeleteFriend:input_type -> topfans.social.DeleteFriendRequest - 12, // 25: topfans.social.SocialService.SetFriendRemark:input_type -> topfans.social.SetFriendRemarkRequest - 14, // 26: topfans.social.SocialService.CheckFriendship:input_type -> topfans.social.CheckFriendshipRequest - 16, // 27: topfans.social.SocialService.GetFriendCount:input_type -> topfans.social.GetFriendCountRequest - 18, // 28: topfans.social.SocialService.SearchUserForFriend:input_type -> topfans.social.SearchUserForFriendRequest - 22, // 29: topfans.social.SocialService.GetRandomUsers:input_type -> topfans.social.GetRandomUsersRequest - 25, // 30: topfans.social.SocialService.GetUsersPaged:input_type -> topfans.social.GetUsersPagedRequest - 27, // 31: topfans.social.SocialService.LikeAsset:input_type -> topfans.social.LikeAssetRequest - 29, // 32: topfans.social.SocialService.UnlikeAsset:input_type -> topfans.social.UnlikeAssetRequest - 31, // 33: topfans.social.SocialService.CheckAssetLike:input_type -> topfans.social.CheckAssetLikeRequest - 3, // 34: topfans.social.SocialService.SendFriendRequest:output_type -> topfans.social.SendFriendRequestResponse - 5, // 35: topfans.social.SocialService.GetFriendRequests:output_type -> topfans.social.GetFriendRequestsResponse - 7, // 36: topfans.social.SocialService.HandleFriendRequest:output_type -> topfans.social.HandleFriendRequestResponse - 9, // 37: topfans.social.SocialService.GetFriendList:output_type -> topfans.social.GetFriendListResponse - 11, // 38: topfans.social.SocialService.DeleteFriend:output_type -> topfans.social.DeleteFriendResponse - 13, // 39: topfans.social.SocialService.SetFriendRemark:output_type -> topfans.social.SetFriendRemarkResponse - 15, // 40: topfans.social.SocialService.CheckFriendship:output_type -> topfans.social.CheckFriendshipResponse - 17, // 41: topfans.social.SocialService.GetFriendCount:output_type -> topfans.social.GetFriendCountResponse - 19, // 42: topfans.social.SocialService.SearchUserForFriend:output_type -> topfans.social.SearchUserForFriendResponse - 23, // 43: topfans.social.SocialService.GetRandomUsers:output_type -> topfans.social.GetRandomUsersResponse - 26, // 44: topfans.social.SocialService.GetUsersPaged:output_type -> topfans.social.GetUsersPagedResponse - 28, // 45: topfans.social.SocialService.LikeAsset:output_type -> topfans.social.LikeAssetResponse - 30, // 46: topfans.social.SocialService.UnlikeAsset:output_type -> topfans.social.UnlikeAssetResponse - 32, // 47: topfans.social.SocialService.CheckAssetLike:output_type -> topfans.social.CheckAssetLikeResponse - 34, // [34:48] is the sub-list for method output_type - 20, // [20:34] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 41, // 17: topfans.social.LikeAssetResponse.base:type_name -> topfans.common.BaseResponse + 41, // 18: topfans.social.UnlikeAssetResponse.base:type_name -> topfans.common.BaseResponse + 41, // 19: topfans.social.CheckAssetLikeResponse.base:type_name -> topfans.common.BaseResponse + 41, // 20: topfans.social.GetMyLikedAssetsResponse.base:type_name -> topfans.common.BaseResponse + 35, // 21: topfans.social.GetMyLikedAssetsResponse.data:type_name -> topfans.social.LikedAssetsData + 36, // 22: topfans.social.LikedAssetsData.items:type_name -> topfans.social.LikedAssetItem + 41, // 23: topfans.social.GetMyTodayLikedAssetsResponse.base:type_name -> topfans.common.BaseResponse + 35, // 24: topfans.social.GetMyTodayLikedAssetsResponse.data:type_name -> topfans.social.LikedAssetsData + 41, // 25: topfans.social.GetMyWeekLikedAssetsResponse.base:type_name -> topfans.common.BaseResponse + 35, // 26: topfans.social.GetMyWeekLikedAssetsResponse.data:type_name -> topfans.social.LikedAssetsData + 2, // 27: topfans.social.SocialService.SendFriendRequest:input_type -> topfans.social.SendFriendRequestRequest + 4, // 28: topfans.social.SocialService.GetFriendRequests:input_type -> topfans.social.GetFriendRequestsRequest + 6, // 29: topfans.social.SocialService.HandleFriendRequest:input_type -> topfans.social.HandleFriendRequestRequest + 8, // 30: topfans.social.SocialService.GetFriendList:input_type -> topfans.social.GetFriendListRequest + 10, // 31: topfans.social.SocialService.DeleteFriend:input_type -> topfans.social.DeleteFriendRequest + 12, // 32: topfans.social.SocialService.SetFriendRemark:input_type -> topfans.social.SetFriendRemarkRequest + 14, // 33: topfans.social.SocialService.CheckFriendship:input_type -> topfans.social.CheckFriendshipRequest + 16, // 34: topfans.social.SocialService.GetFriendCount:input_type -> topfans.social.GetFriendCountRequest + 18, // 35: topfans.social.SocialService.SearchUserForFriend:input_type -> topfans.social.SearchUserForFriendRequest + 22, // 36: topfans.social.SocialService.GetRandomUsers:input_type -> topfans.social.GetRandomUsersRequest + 25, // 37: topfans.social.SocialService.GetUsersPaged:input_type -> topfans.social.GetUsersPagedRequest + 27, // 38: topfans.social.SocialService.LikeAsset:input_type -> topfans.social.LikeAssetRequest + 29, // 39: topfans.social.SocialService.UnlikeAsset:input_type -> topfans.social.UnlikeAssetRequest + 31, // 40: topfans.social.SocialService.CheckAssetLike:input_type -> topfans.social.CheckAssetLikeRequest + 33, // 41: topfans.social.SocialService.GetMyLikedAssets:input_type -> topfans.social.GetMyLikedAssetsRequest + 37, // 42: topfans.social.SocialService.GetMyTodayLikedAssets:input_type -> topfans.social.GetMyTodayLikedAssetsRequest + 39, // 43: topfans.social.SocialService.GetMyWeekLikedAssets:input_type -> topfans.social.GetMyWeekLikedAssetsRequest + 3, // 44: topfans.social.SocialService.SendFriendRequest:output_type -> topfans.social.SendFriendRequestResponse + 5, // 45: topfans.social.SocialService.GetFriendRequests:output_type -> topfans.social.GetFriendRequestsResponse + 7, // 46: topfans.social.SocialService.HandleFriendRequest:output_type -> topfans.social.HandleFriendRequestResponse + 9, // 47: topfans.social.SocialService.GetFriendList:output_type -> topfans.social.GetFriendListResponse + 11, // 48: topfans.social.SocialService.DeleteFriend:output_type -> topfans.social.DeleteFriendResponse + 13, // 49: topfans.social.SocialService.SetFriendRemark:output_type -> topfans.social.SetFriendRemarkResponse + 15, // 50: topfans.social.SocialService.CheckFriendship:output_type -> topfans.social.CheckFriendshipResponse + 17, // 51: topfans.social.SocialService.GetFriendCount:output_type -> topfans.social.GetFriendCountResponse + 19, // 52: topfans.social.SocialService.SearchUserForFriend:output_type -> topfans.social.SearchUserForFriendResponse + 23, // 53: topfans.social.SocialService.GetRandomUsers:output_type -> topfans.social.GetRandomUsersResponse + 26, // 54: topfans.social.SocialService.GetUsersPaged:output_type -> topfans.social.GetUsersPagedResponse + 28, // 55: topfans.social.SocialService.LikeAsset:output_type -> topfans.social.LikeAssetResponse + 30, // 56: topfans.social.SocialService.UnlikeAsset:output_type -> topfans.social.UnlikeAssetResponse + 32, // 57: topfans.social.SocialService.CheckAssetLike:output_type -> topfans.social.CheckAssetLikeResponse + 34, // 58: topfans.social.SocialService.GetMyLikedAssets:output_type -> topfans.social.GetMyLikedAssetsResponse + 38, // 59: topfans.social.SocialService.GetMyTodayLikedAssets:output_type -> topfans.social.GetMyTodayLikedAssetsResponse + 40, // 60: topfans.social.SocialService.GetMyWeekLikedAssets:output_type -> topfans.social.GetMyWeekLikedAssetsResponse + 44, // [44:61] is the sub-list for method output_type + 27, // [27:44] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name } func init() { file_social_proto_init() } @@ -2446,7 +2982,7 @@ func file_social_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_social_proto_rawDesc), len(file_social_proto_rawDesc)), NumEnums: 0, - NumMessages: 33, + NumMessages: 41, NumExtensions: 0, NumServices: 1, }, diff --git a/backend/pkg/proto/social/social.triple.go b/backend/pkg/proto/social/social.triple.go index fe868e2..bcb87dc 100644 --- a/backend/pkg/proto/social/social.triple.go +++ b/backend/pkg/proto/social/social.triple.go @@ -64,6 +64,8 @@ const ( SocialServiceUnlikeAssetProcedure = "/topfans.social.SocialService/UnlikeAsset" // SocialServiceCheckAssetLikeProcedure is the fully-qualified name of the SocialService's CheckAssetLike RPC. SocialServiceCheckAssetLikeProcedure = "/topfans.social.SocialService/CheckAssetLike" + // SocialServiceGetMyLikedAssetsProcedure is the fully-qualified name of the SocialService's GetMyLikedAssets RPC. + SocialServiceGetMyLikedAssetsProcedure = "/topfans.social.SocialService/GetMyLikedAssets" ) var ( @@ -86,6 +88,7 @@ type SocialService interface { LikeAsset(ctx context.Context, req *LikeAssetRequest, opts ...client.CallOption) (*LikeAssetResponse, error) UnlikeAsset(ctx context.Context, req *UnlikeAssetRequest, opts ...client.CallOption) (*UnlikeAssetResponse, error) CheckAssetLike(ctx context.Context, req *CheckAssetLikeRequest, opts ...client.CallOption) (*CheckAssetLikeResponse, error) + GetMyLikedAssets(ctx context.Context, req *GetMyLikedAssetsRequest, opts ...client.CallOption) (*GetMyLikedAssetsResponse, error) } // NewSocialService constructs a client for the social.SocialService service. @@ -220,9 +223,17 @@ func (c *SocialServiceImpl) CheckAssetLike(ctx context.Context, req *CheckAssetL return resp, nil } +func (c *SocialServiceImpl) GetMyLikedAssets(ctx context.Context, req *GetMyLikedAssetsRequest, opts ...client.CallOption) (*GetMyLikedAssetsResponse, error) { + resp := new(GetMyLikedAssetsResponse) + if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyLikedAssets", opts...); err != nil { + return nil, err + } + return resp, nil +} + var SocialService_ClientInfo = client.ClientInfo{ InterfaceName: "topfans.social.SocialService", - MethodNames: []string{"SendFriendRequest", "GetFriendRequests", "HandleFriendRequest", "GetFriendList", "DeleteFriend", "SetFriendRemark", "CheckFriendship", "GetFriendCount", "SearchUserForFriend", "GetRandomUsers", "GetUsersPaged", "LikeAsset", "UnlikeAsset", "CheckAssetLike"}, + MethodNames: []string{"SendFriendRequest", "GetFriendRequests", "HandleFriendRequest", "GetFriendList", "DeleteFriend", "SetFriendRemark", "CheckFriendship", "GetFriendCount", "SearchUserForFriend", "GetRandomUsers", "GetUsersPaged", "LikeAsset", "UnlikeAsset", "CheckAssetLike", "GetMyLikedAssets"}, ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) { dubboCli := dubboCliRaw.(*SocialServiceImpl) dubboCli.conn = conn @@ -245,6 +256,7 @@ type SocialServiceHandler interface { LikeAsset(context.Context, *LikeAssetRequest) (*LikeAssetResponse, error) UnlikeAsset(context.Context, *UnlikeAssetRequest) (*UnlikeAssetResponse, error) CheckAssetLike(context.Context, *CheckAssetLikeRequest) (*CheckAssetLikeResponse, error) + GetMyLikedAssets(context.Context, *GetMyLikedAssetsRequest) (*GetMyLikedAssetsResponse, error) } func RegisterSocialServiceHandler(srv *server.Server, hdlr SocialServiceHandler, opts ...server.ServiceOption) error { @@ -469,5 +481,20 @@ var SocialService_ServiceInfo = server.ServiceInfo{ return triple_protocol.NewResponse(res), nil }, }, + { + Name: "GetMyLikedAssets", + Type: constant.CallUnary, + ReqInitFunc: func() interface{} { + return new(GetMyLikedAssetsRequest) + }, + MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) { + req := args[0].(*GetMyLikedAssetsRequest) + res, err := handler.(SocialServiceHandler).GetMyLikedAssets(ctx, req) + if err != nil { + return nil, err + } + return triple_protocol.NewResponse(res), nil + }, + }, }, } diff --git a/backend/proto/gallery.proto b/backend/proto/gallery.proto index fae36ec..e93626a 100644 --- a/backend/proto/gallery.proto +++ b/backend/proto/gallery.proto @@ -2,8 +2,8 @@ syntax = "proto3"; package topfans.gallery; -import "google/api/annotations.proto"; import "proto/common.proto"; +import "google/api/annotations.proto"; option go_package = "github.com/topfans/backend/pkg/proto/gallery;gallery"; @@ -45,6 +45,15 @@ service GalleryService { delete: "/api/galleries/slots/{slot_id}/asset" }; } + + // ========== 我的作品相关 ========== + + // 获取我展出的作品列表 + rpc GetMyExhibitedAssets(GetMyExhibitedAssetsRequest) returns (GetMyExhibitedAssetsResponse) { + option (google.api.http) = { + get: "/api/v1/me/exhibited-assets" + }; + } } // 请求和响应消息定义 @@ -138,3 +147,37 @@ message RemoveFromSlotRequest { message RemoveFromSlotResponse { topfans.common.BaseResponse base = 1; } + +// ==================== 我的作品相关消息 ==================== + +// 获取我展出的作品列表请求 +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; // 当前可领取收益 +} diff --git a/backend/proto/social.proto b/backend/proto/social.proto index 7120ef0..3946343 100644 --- a/backend/proto/social.proto +++ b/backend/proto/social.proto @@ -260,6 +260,63 @@ message CheckAssetLikeResponse { bool is_liked = 2; // 是否已点赞 } +// ==================== 我的作品相关消息 ==================== + +// 获取我点赞的作品列表请求 +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; // 当前可领取收益 +} + +// 获取我今日点赞的作品列表请求(暂不实现) +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; +} + // ==================== 社交服务(包含好友等功能)==================== service SocialService { @@ -371,5 +428,28 @@ service SocialService { get: "/api/v1/social/assets/{asset_id}/like" }; } + + // ========== 我的作品相关 ========== + + // 获取我点赞的作品列表 + 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" + }; + } } diff --git a/backend/services/galleryService/provider/gallery_provider.go b/backend/services/galleryService/provider/gallery_provider.go index 3c97ea5..762c647 100644 --- a/backend/services/galleryService/provider/gallery_provider.go +++ b/backend/services/galleryService/provider/gallery_provider.go @@ -315,6 +315,29 @@ func (p *GalleryProvider) UnlockSlot(ctx context.Context, req *pb.UnlockSlotRequ }, nil } +// GetMyExhibitedAssets 获取我展出的作品列表 +func (p *GalleryProvider) GetMyExhibitedAssets(ctx context.Context, req *pb.GetMyExhibitedAssetsRequest) (*pb.GetMyExhibitedAssetsResponse, error) { + logger.Logger.Info("Received GetMyExhibitedAssets request") + + // 从 Dubbo attachments 获取用户信息(网关已验证并传递) + userID, starID, err := extractUserInfoFromDubboAttachments(ctx) + if err != nil { + logger.Logger.Error("Failed to extract user info from attachments", + zap.Error(err), + ) + return &pb.GetMyExhibitedAssetsResponse{ + Base: &pbCommon.BaseResponse{ + Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED, + Message: "user authentication required", + Timestamp: 0, + }, + }, err + } + + // 调用Service层 + return p.exhibitionService.GetMyExhibitedAssets(ctx, userID, starID, req) +} + // ==================== 辅助函数 ==================== // extractUserInfoFromDubboAttachments 从Dubbo attachments提取用户信息 diff --git a/backend/services/galleryService/repository/gallery_repository.go b/backend/services/galleryService/repository/gallery_repository.go index 72dd41b..b618929 100644 --- a/backend/services/galleryService/repository/gallery_repository.go +++ b/backend/services/galleryService/repository/gallery_repository.go @@ -31,6 +31,27 @@ type GalleryRepository interface { // 资产注册表相关 UpdateAssetRegistryDisplayStatus(assetID int64, displayStatus int32) error + + // ========== 我的作品相关 ========== + + // GetMyExhibitedAssets 获取我展出的作品列表(只返回展出中且未过期的,含收益) + // userID: 用户ID + // starID: 明星ID + // page: 页码(从1开始) + // pageSize: 每页数量 + // 返回: 作品列表、总数量 + GetMyExhibitedAssets(userID, starID int64, page, pageSize int) ([]*ExhibitedAssetInfo, int64, error) +} + +// ExhibitedAssetInfo 我展出的作品信息 +type ExhibitedAssetInfo struct { + AssetID int64 + Name string + CoverURL string + LikeCount int32 + ExhibitedAt int64 + ExpireAt int64 + Earnings int64 } // galleryRepository Repository实现 @@ -214,6 +235,46 @@ func (r *galleryRepository) UpdateAssetRegistryDisplayStatus(assetID int64, disp Update("display_status", displayStatus).Error } +// ========== 我的作品相关实现 ========== + +// GetMyExhibitedAssets 获取我展出的作品列表(只返回展出中且未过期的,含收益) +func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pageSize int) ([]*ExhibitedAssetInfo, int64, error) { + var items []*ExhibitedAssetInfo + var total int64 + + now := time.Now().UnixMilli() + + // 计数查询 + err := r.db.Model(&models.Exhibition{}). + Where("occupier_uid = ? AND occupier_star_id = ? AND deleted_at IS NULL AND expire_at > ?", userID, starID, now). + Count(&total).Error + if err != nil { + return nil, 0, err + } + + // 数据查询 + offset := (page - 1) * pageSize + err = r.db.Model(&models.Exhibition{}). + Select(`exhibitions.asset_id, a.name, a.cover_url, a.like_count, + exhibitions.start_time as exhibited_at, exhibitions.expire_at, + COALESCE(SUM(err.crystal_amount), 0) as earnings`). + Joins("JOIN assets a ON a.id = exhibitions.asset_id"). + Joins("LEFT JOIN exhibition_revenue_records err ON err.asset_id = a.id AND err.status = 'claimable'"). + Where("exhibitions.occupier_uid = ? AND exhibitions.occupier_star_id = ?", userID, starID). + Where("exhibitions.deleted_at IS NULL AND exhibitions.expire_at > ?", now). + Group("exhibitions.asset_id, a.name, a.cover_url, a.like_count, exhibitions.start_time, exhibitions.expire_at"). + Order("exhibitions.start_time DESC"). + Limit(pageSize). + Offset(offset). + Scan(&items).Error + + if err != nil { + return nil, 0, err + } + + return items, total, nil +} + // ==================== 辅助函数 ==================== // generateHostProfileID 生成 host_profile_id diff --git a/backend/services/socialService/main.go b/backend/services/socialService/main.go index c66d675..2d93f5e 100644 --- a/backend/services/socialService/main.go +++ b/backend/services/socialService/main.go @@ -181,7 +181,7 @@ func initDubboService() error { // 创建Service实例 friendService := service.NewFriendService(socialRepo, userServiceClient, db) - assetLikeService := service.NewAssetLikeService(assetClient) + assetLikeService := service.NewAssetLikeService(assetClient, socialRepo) // 创建Provider实例 socialProvider := provider.NewSocialProvider(friendService, assetLikeService) diff --git a/backend/services/socialService/provider/social_provider.go b/backend/services/socialService/provider/social_provider.go index 23b6f6b..0565fd9 100644 --- a/backend/services/socialService/provider/social_provider.go +++ b/backend/services/socialService/provider/social_provider.go @@ -373,6 +373,33 @@ func (p *SocialProvider) CheckAssetLike(ctx context.Context, req *pb.CheckAssetL }, nil } +// ========== 我的作品相关 ========== + +// GetMyLikedAssets 获取我点赞的作品列表 +func (p *SocialProvider) GetMyLikedAssets(ctx context.Context, req *pb.GetMyLikedAssetsRequest) (*pb.GetMyLikedAssetsResponse, error) { + // 从上下文获取用户信息 + userID, starID, err := extractUserInfo(ctx) + if err != nil { + logger.Logger.Warn("Failed to extract user info from context", zap.Error(err)) + return &pb.GetMyLikedAssetsResponse{ + Base: &common.BaseResponse{ + Code: common.StatusCode_STATUS_UNAUTHORIZED, + Message: "Unauthorized: " + err.Error(), + Timestamp: time.Now().UnixMilli(), + }, + }, nil + } + + logger.Logger.Debug("GetMyLikedAssets called", + zap.Int64("user_id", userID), + zap.Int64("star_id", starID), + zap.Int32("page", req.Page), + zap.Int32("page_size", req.PageSize), + ) + + return p.assetLikeService.GetMyLikedAssets(ctx, req) +} + // extractUserInfo 从 Dubbo attachments 中提取用户信息 // 网关调用:网关已验证 Token 并将 user_id 和 star_id 通过 attachments 传递 func extractUserInfo(ctx context.Context) (int64, int64, error) { diff --git a/backend/services/socialService/repository/social_repository.go b/backend/services/socialService/repository/social_repository.go index c200c18..ce8cfba 100644 --- a/backend/services/socialService/repository/social_repository.go +++ b/backend/services/socialService/repository/social_repository.go @@ -101,6 +101,26 @@ type SocialRepository interface { // nickname: 昵称关键词 // limit: 返回数量限制 GetFanProfilesByNickname(starID int64, nickname string, limit int) ([]*models.FanProfile, error) + + // ========== 我的作品相关 ========== + + // GetMyLikedAssets 获取我点赞的作品列表(只返回展出中且未过期的,含收益) + // userID: 用户ID + // starID: 明星ID + // page: 页码(从1开始) + // pageSize: 每页数量 + // 返回: 作品列表、总数量 + GetMyLikedAssets(userID, starID int64, page, pageSize int) ([]*LikedAssetInfo, int64, error) +} + +// LikedAssetInfo 我点赞的作品信息 +type LikedAssetInfo struct { + AssetID int64 + Name string + CoverURL string + LikeCount int32 + LikedAt int64 + Earnings int64 } // RandomUserInfo 随机用户信息 @@ -526,3 +546,50 @@ func (r *socialRepositoryImpl) GetFanProfilesByNickname(starID int64, nickname s return profiles, nil } + +// ========== 我的作品相关实现 ========== + +// GetMyLikedAssets 获取我点赞的作品列表(只返回展出中且未过期的,含收益) +func (r *socialRepositoryImpl) GetMyLikedAssets(userID, starID int64, page, pageSize int) ([]*LikedAssetInfo, int64, error) { + var items []*LikedAssetInfo + var total int64 + + // 子查询:查找当前时间未过期的展出记录 + now := time.Now().UnixMilli() + + // 计数查询(使用 DISTINCT 因为一个资产可能在多个展位展出) + countQuery := r.db.Model(&models.AssetLike{}). + Joins("JOIN assets a ON a.id = asset_likes.asset_id"). + Joins("JOIN exhibitions e ON e.asset_id = a.id"). + Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID). + Where("a.deleted_at IS NULL AND a.is_active = ?", true). + Where("e.deleted_at IS NULL AND e.expire_at > ?", now) + + if err := countQuery.Distinct("asset_likes.asset_id").Count(&total).Error; err != nil { + return nil, 0, err + } + + // 数据查询 + offset := (page - 1) * pageSize + err := r.db.Model(&models.AssetLike{}). + Select(`asset_likes.asset_id, a.name, a.cover_url, a.like_count, + asset_likes.created_at as liked_at, + COALESCE(SUM(err.crystal_amount), 0) as earnings`). + Joins("JOIN assets a ON a.id = asset_likes.asset_id"). + Joins("JOIN exhibitions e ON e.asset_id = a.id"). + Joins("LEFT JOIN exhibition_revenue_records err ON err.asset_id = a.id AND err.status = 'claimable'"). + Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID). + Where("a.deleted_at IS NULL AND a.is_active = ?", true). + Where("e.deleted_at IS NULL AND e.expire_at > ?", now). + Group("asset_likes.asset_id, a.name, a.cover_url, a.like_count, asset_likes.created_at"). + Order("asset_likes.created_at DESC"). + Limit(pageSize). + Offset(offset). + Scan(&items).Error + + if err != nil { + return nil, 0, err + } + + return items, total, nil +} diff --git a/docs/superpowers/specs/2026-04-27-my-assets-design.md b/docs/superpowers/specs/2026-04-27-my-assets-design.md index 578cbb8..043bd92 100644 --- a/docs/superpowers/specs/2026-04-27-my-assets-design.md +++ b/docs/superpowers/specs/2026-04-27-my-assets-design.md @@ -19,19 +19,26 @@ **主表:** asset_likes(点赞记录表) -**关联表:** assets(资产表)- 用于获取藏品信息 +**关联表:** +- 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(资产表)- 用于获取藏品信息 +**关联表:** +- assets(资产表)- 用于获取藏品信息 +- exhibition_revenue_records(收益记录表)- 用于获取当前可领取收益 **筛选条件:** - `occupier_uid = ?` (当前用户) @@ -88,6 +95,7 @@ GET /api/v1/me/liked-assets | cover_url | string | 封面图URL | | like_count | int32 | 实时点赞数(来自 assets 表) | | liked_at | int64 | 用户点赞该作品的时间(毫秒时间戳) | +| earnings | int64 | 当前可领取收益(status='claimable' 的 crystal_amount 汇总) | --- @@ -106,6 +114,224 @@ GET /api/v1/me/exhibited-assets **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, @@ -140,9 +366,11 @@ GET /api/v1/me/exhibited-assets | exhibited_at | int64 | 展出开始时间(毫秒时间戳) | | expire_at | int64 | 展出过期时间(毫秒时间戳) | +> **状态:暂不实现** + --- -### 3.3 错误码 +### 3.7 错误码 | code | 说明 | |------|------| @@ -185,6 +413,7 @@ message LikedAssetItem { string cover_url = 3; // 封面图URL int32 like_count = 4; // 实时点赞数 int64 liked_at = 5; // 点赞时间(毫秒时间戳) + int64 earnings = 6; // 当前可领取收益 } ``` @@ -222,12 +451,79 @@ message ExhibitedAssetItem { int32 like_count = 4; // 实时点赞数 int64 exhibited_at = 5; // 展出开始时间(毫秒时间戳) int64 expire_at = 6; // 展出过期时间(毫秒时间戳) + int64 earnings = 7; // 当前可领取收益 } ``` --- -### 4.3 Service 方法 +### 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 中新增方法: @@ -242,6 +538,27 @@ service SocialService { 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" + }; + } } ``` @@ -258,6 +575,13 @@ service GalleryService { get: "/api/v1/me/exhibited-assets" }; } + + // 获取他人展出的作品列表(暂不实现) + rpc GetUserExhibitedAssets(GetUserExhibitedAssetsRequest) returns (GetUserExhibitedAssetsResponse) { + option (google.api.http) = { + get: "/api/v1/users/{user_id}/exhibited-assets" + }; + } } ``` @@ -265,7 +589,7 @@ service GalleryService { ## 五、核心逻辑 -### 5.1 查询我点赞的作品 +### 5.1 查询我点赞的作品(只返回展出中且未过期的) ```sql SELECT @@ -273,29 +597,39 @@ SELECT a.name, a.cover_url, a.like_count, - al.created_at as liked_at + 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(*) +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 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` @@ -310,13 +644,16 @@ SELECT a.cover_url, a.like_count, e.start_time as exhibited_at, - e.expire_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 ?; @@ -437,4 +774,8 @@ backend/ 1. **只显示展出中的作品** — 通过 `expire_at > now` 过滤 2. **排序方式** — 按展出时间倒序(start_time DESC) -3. **分页大小** — 默认 20,最大 100 \ No newline at end of file +3. **分页大小** — 默认 20,最大 100 +4. **点赞作品也只显示展出中且未过期的** — 通过 JOIN exhibitions 并过滤 `expire_at > now` +5. **今日/本周点赞暂不实现** — API 和 Proto 已定义,但代码实现待后续 +6. **每个藏品返回当前可领取收益** — 关联 exhibition_revenue_records 表,汇总 `status='claimable'` 的 `crystal_amount` +7. **他人点赞/展出的作品列表暂不实现** — API 和 Proto 已定义,但代码实现待后续 \ No newline at end of file diff --git a/frontend/utils/api.js b/frontend/utils/api.js index ec5af73..d559a05 100644 --- a/frontend/utils/api.js +++ b/frontend/utils/api.js @@ -566,4 +566,26 @@ export function getStarbookItemsApi(type, category, grade = null, page = 1, page url: url, method: 'GET' }) +} + +// ==================== 他人作品统计接口(暂不实现) ==================== + +// 获取他人点赞的作品列表(暂不实现) +export function getUserLikedAssetsApi(userId, page = 1, pageSize = 20) { + return Promise.reject(new Error('接口暂未开放')) + // 正式实现时启用: + // return request({ + // url: `/api/v1/users/${userId}/liked-assets?page=${page}&page_size=${pageSize}`, + // method: 'GET' + // }) +} + +// 获取他人展出的作品列表(暂不实现) +export function getUserExhibitedAssetsApi(userId, page = 1, pageSize = 20) { + return Promise.reject(new Error('接口暂未开放')) + // 正式实现时启用: + // return request({ + // url: `/api/v1/users/${userId}/exhibited-assets?page=${page}&page_size=${pageSize}`, + // method: 'GET' + // }) } \ No newline at end of file