diff --git a/backend/gateway/controller/gallery_controller.go b/backend/gateway/controller/gallery_controller.go
index c8cb49f..d619354 100644
--- a/backend/gateway/controller/gallery_controller.go
+++ b/backend/gateway/controller/gallery_controller.go
@@ -633,4 +633,87 @@ result := &dto.GetMyExhibitedAssetsResponseDTO{
)
response.Success(c, result)
+}
+
+// GetInspirationFlow 获取灵感瀑布藏品列表
+// @Summary 获取灵感瀑布藏品列表
+// @Description 获取灵感瀑布藏品列表,支持随机展示和双向滚动
+// @Tags galleries
+// @Accept json
+// @Produce json
+// @Security BearerAuth
+// @Param cursor query string false "游标"
+// @Param direction query string false "滚动方向:right(加载新数据)/ left(加载历史)" default(right)
+// @Param limit query int false "每页数量" default(10)
+// @Param type query string false "过滤类型:badge/poster/original/all" default(all)
+// @Param session_id query string false "会话ID"
+// @Success 200 {object} response.Response{data=dto.GetInspirationFlowResponseDTO}
+// @Router /api/v1/inspiration-flow [get]
+func (ctrl *GalleryController) GetInspirationFlow(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
+ }
+
+ // 解析请求参数
+ cursor := c.Query("cursor")
+ direction := c.DefaultQuery("direction", "right")
+ limitStr := c.DefaultQuery("limit", "10")
+ limit, _ := strconv.Atoi(limitStr)
+ materialType := c.DefaultQuery("type", "all")
+ sessionID := c.Query("session_id")
+
+ // 创建带有附加信息的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.GetInspirationFlow(ctx, &pbGallery.GetInspirationFlowRequest{
+ Cursor: cursor,
+ Direction: direction,
+ Limit: int32(limit),
+ Type: materialType,
+ SessionId: sessionID,
+ })
+ if err != nil {
+ logger.Logger.Error("GetInspirationFlow 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
+ flowDTO := dto.ConvertInspirationFlowData(resp.Data)
+
+ logger.Logger.Info("GetInspirationFlow success",
+ zap.Any("user_id", userID),
+ zap.Any("star_id", starID),
+ zap.Int("count", len(flowDTO.Items)),
+ )
+
+ response.Success(c, flowDTO)
}
\ No newline at end of file
diff --git a/backend/gateway/dto/gallery_converter.go b/backend/gateway/dto/gallery_converter.go
index 37b9e4b..08c109d 100644
--- a/backend/gateway/dto/gallery_converter.go
+++ b/backend/gateway/dto/gallery_converter.go
@@ -150,3 +150,29 @@ func ConvertPlaceAssetRequest(dto *PlaceAssetRequestDTO) *pbGallery.PlaceAssetRe
SlotId: dto.SlotID,
}
}
+
+// ConvertInspirationFlowData 转换灵感瀑布数据
+func ConvertInspirationFlowData(pbData *pbGallery.InspirationFlowData) *GetInspirationFlowResponseDTO {
+ if pbData == nil {
+ return nil
+ }
+
+ dto := &GetInspirationFlowResponseDTO{
+ Cursor: pbData.Cursor,
+ HasMore: pbData.HasMore,
+ SessionID: pbData.SessionId,
+ Items: make([]*InspirationFlowItemDTO, 0, len(pbData.Items)),
+ }
+
+ for _, item := range pbData.Items {
+ dto.Items = append(dto.Items, &InspirationFlowItemDTO{
+ AssetID: item.AssetId,
+ Name: item.Name,
+ CoverURL: item.CoverUrl,
+ LikeCount: item.LikeCount,
+ OwnerNickname: item.OwnerNickname,
+ })
+ }
+
+ return dto
+}
diff --git a/backend/gateway/dto/gallery_dto.go b/backend/gateway/dto/gallery_dto.go
index 18f729d..040df3c 100644
--- a/backend/gateway/dto/gallery_dto.go
+++ b/backend/gateway/dto/gallery_dto.go
@@ -90,3 +90,22 @@ type GetMyExhibitedAssetsResponseDTO struct {
Total int64 `json:"total"` // 总数量
HasMore bool `json:"has_more"` // 是否有更多
}
+
+// ========== 灵感瀑布相关 ==========
+
+// InspirationFlowItemDTO 灵感瀑布藏品项
+type InspirationFlowItemDTO struct {
+ AssetID int64 `json:"asset_id"` // 资产ID
+ Name string `json:"name"` // 藏品名称
+ CoverURL string `json:"cover_url"` // 封面图URL
+ LikeCount int32 `json:"like_count"` // 点赞数
+ OwnerNickname string `json:"owner_nickname"` // 展出者昵称
+}
+
+// GetInspirationFlowResponseDTO 获取灵感瀑布藏品列表响应
+type GetInspirationFlowResponseDTO struct {
+ Items []*InspirationFlowItemDTO `json:"items"` // 藏品列表
+ Cursor string `json:"cursor"` // 下次请求的游标
+ HasMore bool `json:"has_more"` // 是否有更多
+ SessionID string `json:"session_id"` // 会话ID
+}
diff --git a/backend/gateway/router/router.go b/backend/gateway/router/router.go
index c81de4d..d1d5401 100644
--- a/backend/gateway/router/router.go
+++ b/backend/gateway/router/router.go
@@ -203,6 +203,13 @@ func SetupRouter(userClient *client.Client, socialClient *client.Client, assetCl
galleries.POST("/slots_unlock", galleryCtrl.UnlockSlot) // 解锁/购买新展位
}
+ // 灵感瀑布相关路由(需要认证)
+ inspirationFlow := v1.Group("/inspiration-flow")
+ inspirationFlow.Use(middleware.AuthMiddleware())
+ {
+ inspirationFlow.GET("", galleryCtrl.GetInspirationFlow) // 获取灵感瀑布藏品列表
+ }
+
// 我的展馆路由(需要认证)
mygalleries := v1.Group("/mygalleries")
mygalleries.Use(middleware.AuthMiddleware())
diff --git a/backend/github.com/topfans/backend/pkg/proto/gallery/gallery.triple.go b/backend/github.com/topfans/backend/pkg/proto/gallery/gallery.triple.go
new file mode 100644
index 0000000..d3d77de
--- /dev/null
+++ b/backend/github.com/topfans/backend/pkg/proto/gallery/gallery.triple.go
@@ -0,0 +1,284 @@
+// Code generated by protoc-gen-triple. DO NOT EDIT.
+//
+// Source: gallery.proto
+package gallery
+
+import (
+ "context"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+// This is a compile-time assertion to ensure that this generated file and the Triple package
+// are compatible. If you get a compiler error that this constant is not defined, this code was
+// generated with a version of Triple newer than the one compiled into your binary. You can fix the
+// problem by either regenerating this code with an older version of Triple or updating the Triple
+// version compiled into your binary.
+const _ = triple_protocol.IsAtLeastVersion0_1_0
+
+const (
+ // GalleryServiceName is the fully-qualified name of the GalleryService service.
+ GalleryServiceName = "topfans.gallery.GalleryService"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this package. They're
+// exposed at runtime as procedure and as the final two segments of the HTTP route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
+// period.
+const (
+ // GalleryServiceGetMyGalleryProcedure is the fully-qualified name of the GalleryService's GetMyGallery RPC.
+ GalleryServiceGetMyGalleryProcedure = "/topfans.gallery.GalleryService/GetMyGallery"
+ // GalleryServiceGetUserGalleryProcedure is the fully-qualified name of the GalleryService's GetUserGallery RPC.
+ GalleryServiceGetUserGalleryProcedure = "/topfans.gallery.GalleryService/GetUserGallery"
+ // GalleryServicePlaceAssetProcedure is the fully-qualified name of the GalleryService's PlaceAsset RPC.
+ GalleryServicePlaceAssetProcedure = "/topfans.gallery.GalleryService/PlaceAsset"
+ // GalleryServiceUnlockSlotProcedure is the fully-qualified name of the GalleryService's UnlockSlot RPC.
+ 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"
+ // GalleryServiceGetInspirationFlowProcedure is the fully-qualified name of the GalleryService's GetInspirationFlow RPC.
+ GalleryServiceGetInspirationFlowProcedure = "/topfans.gallery.GalleryService/GetInspirationFlow"
+)
+
+var (
+ _ GalleryService = (*GalleryServiceImpl)(nil)
+)
+
+// GalleryService is a client for the topfans.gallery.GalleryService service.
+type GalleryService interface {
+ GetMyGallery(ctx context.Context, req *GetMyGalleryRequest, opts ...client.CallOption) (*GetMyGalleryResponse, error)
+ GetUserGallery(ctx context.Context, req *GetUserGalleryRequest, opts ...client.CallOption) (*GetUserGalleryResponse, error)
+ 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)
+ GetInspirationFlow(ctx context.Context, req *GetInspirationFlowRequest, opts ...client.CallOption) (*GetInspirationFlowResponse, error)
+}
+
+// NewGalleryService constructs a client for the gallery.GalleryService service.
+func NewGalleryService(cli *client.Client, opts ...client.ReferenceOption) (GalleryService, error) {
+ conn, err := cli.DialWithInfo("topfans.gallery.GalleryService", &GalleryService_ClientInfo, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &GalleryServiceImpl{
+ conn: conn,
+ }, nil
+}
+
+func SetConsumerGalleryService(srv common.RPCService) {
+ dubbo.SetConsumerServiceWithInfo(srv, &GalleryService_ClientInfo)
+}
+
+// GalleryServiceImpl implements GalleryService.
+type GalleryServiceImpl struct {
+ conn *client.Connection
+}
+
+func (c *GalleryServiceImpl) GetMyGallery(ctx context.Context, req *GetMyGalleryRequest, opts ...client.CallOption) (*GetMyGalleryResponse, error) {
+ resp := new(GetMyGalleryResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyGallery", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *GalleryServiceImpl) GetUserGallery(ctx context.Context, req *GetUserGalleryRequest, opts ...client.CallOption) (*GetUserGalleryResponse, error) {
+ resp := new(GetUserGalleryResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetUserGallery", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *GalleryServiceImpl) PlaceAsset(ctx context.Context, req *PlaceAssetRequest, opts ...client.CallOption) (*PlaceAssetResponse, error) {
+ resp := new(PlaceAssetResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "PlaceAsset", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *GalleryServiceImpl) UnlockSlot(ctx context.Context, req *UnlockSlotRequest, opts ...client.CallOption) (*UnlockSlotResponse, error) {
+ resp := new(UnlockSlotResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "UnlockSlot", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *GalleryServiceImpl) RemoveFromSlot(ctx context.Context, req *RemoveFromSlotRequest, opts ...client.CallOption) (*RemoveFromSlotResponse, error) {
+ resp := new(RemoveFromSlotResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "RemoveFromSlot", opts...); err != nil {
+ return nil, err
+ }
+ 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
+}
+
+func (c *GalleryServiceImpl) GetInspirationFlow(ctx context.Context, req *GetInspirationFlowRequest, opts ...client.CallOption) (*GetInspirationFlowResponse, error) {
+ resp := new(GetInspirationFlowResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetInspirationFlow", 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", "GetMyExhibitedAssets", "GetInspirationFlow"},
+ ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) {
+ dubboCli := dubboCliRaw.(*GalleryServiceImpl)
+ dubboCli.conn = conn
+ },
+}
+
+// GalleryServiceHandler is an implementation of the topfans.gallery.GalleryService service.
+type GalleryServiceHandler interface {
+ GetMyGallery(context.Context, *GetMyGalleryRequest) (*GetMyGalleryResponse, error)
+ GetUserGallery(context.Context, *GetUserGalleryRequest) (*GetUserGalleryResponse, error)
+ PlaceAsset(context.Context, *PlaceAssetRequest) (*PlaceAssetResponse, error)
+ UnlockSlot(context.Context, *UnlockSlotRequest) (*UnlockSlotResponse, error)
+ RemoveFromSlot(context.Context, *RemoveFromSlotRequest) (*RemoveFromSlotResponse, error)
+ GetMyExhibitedAssets(context.Context, *GetMyExhibitedAssetsRequest) (*GetMyExhibitedAssetsResponse, error)
+ GetInspirationFlow(context.Context, *GetInspirationFlowRequest) (*GetInspirationFlowResponse, error)
+}
+
+func RegisterGalleryServiceHandler(srv *server.Server, hdlr GalleryServiceHandler, opts ...server.ServiceOption) error {
+ return srv.Register(hdlr, &GalleryService_ServiceInfo, opts...)
+}
+
+func SetProviderGalleryService(srv common.RPCService) {
+ dubbo.SetProviderServiceWithInfo(srv, &GalleryService_ServiceInfo)
+}
+
+var GalleryService_ServiceInfo = server.ServiceInfo{
+ InterfaceName: "topfans.gallery.GalleryService",
+ ServiceType: (*GalleryServiceHandler)(nil),
+ Methods: []server.MethodInfo{
+ {
+ Name: "GetMyGallery",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetMyGalleryRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetMyGalleryRequest)
+ res, err := handler.(GalleryServiceHandler).GetMyGallery(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetUserGallery",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetUserGalleryRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetUserGalleryRequest)
+ res, err := handler.(GalleryServiceHandler).GetUserGallery(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "PlaceAsset",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(PlaceAssetRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*PlaceAssetRequest)
+ res, err := handler.(GalleryServiceHandler).PlaceAsset(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "UnlockSlot",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(UnlockSlotRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*UnlockSlotRequest)
+ res, err := handler.(GalleryServiceHandler).UnlockSlot(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "RemoveFromSlot",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(RemoveFromSlotRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*RemoveFromSlotRequest)
+ res, err := handler.(GalleryServiceHandler).RemoveFromSlot(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ 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
+ },
+ },
+ {
+ Name: "GetInspirationFlow",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetInspirationFlowRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetInspirationFlowRequest)
+ res, err := handler.(GalleryServiceHandler).GetInspirationFlow(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ },
+}
diff --git a/backend/github.com/topfans/backend/pkg/proto/social/social.triple.go b/backend/github.com/topfans/backend/pkg/proto/social/social.triple.go
new file mode 100644
index 0000000..3bbe0e5
--- /dev/null
+++ b/backend/github.com/topfans/backend/pkg/proto/social/social.triple.go
@@ -0,0 +1,554 @@
+// Code generated by protoc-gen-triple. DO NOT EDIT.
+//
+// Source: social.proto
+package social
+
+import (
+ "context"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+// This is a compile-time assertion to ensure that this generated file and the Triple package
+// are compatible. If you get a compiler error that this constant is not defined, this code was
+// generated with a version of Triple newer than the one compiled into your binary. You can fix the
+// problem by either regenerating this code with an older version of Triple or updating the Triple
+// version compiled into your binary.
+const _ = triple_protocol.IsAtLeastVersion0_1_0
+
+const (
+ // SocialServiceName is the fully-qualified name of the SocialService service.
+ SocialServiceName = "topfans.social.SocialService"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this package. They're
+// exposed at runtime as procedure and as the final two segments of the HTTP route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
+// period.
+const (
+ // SocialServiceSendFriendRequestProcedure is the fully-qualified name of the SocialService's SendFriendRequest RPC.
+ SocialServiceSendFriendRequestProcedure = "/topfans.social.SocialService/SendFriendRequest"
+ // SocialServiceGetFriendRequestsProcedure is the fully-qualified name of the SocialService's GetFriendRequests RPC.
+ SocialServiceGetFriendRequestsProcedure = "/topfans.social.SocialService/GetFriendRequests"
+ // SocialServiceHandleFriendRequestProcedure is the fully-qualified name of the SocialService's HandleFriendRequest RPC.
+ SocialServiceHandleFriendRequestProcedure = "/topfans.social.SocialService/HandleFriendRequest"
+ // SocialServiceGetFriendListProcedure is the fully-qualified name of the SocialService's GetFriendList RPC.
+ SocialServiceGetFriendListProcedure = "/topfans.social.SocialService/GetFriendList"
+ // SocialServiceDeleteFriendProcedure is the fully-qualified name of the SocialService's DeleteFriend RPC.
+ SocialServiceDeleteFriendProcedure = "/topfans.social.SocialService/DeleteFriend"
+ // SocialServiceSetFriendRemarkProcedure is the fully-qualified name of the SocialService's SetFriendRemark RPC.
+ SocialServiceSetFriendRemarkProcedure = "/topfans.social.SocialService/SetFriendRemark"
+ // SocialServiceCheckFriendshipProcedure is the fully-qualified name of the SocialService's CheckFriendship RPC.
+ SocialServiceCheckFriendshipProcedure = "/topfans.social.SocialService/CheckFriendship"
+ // SocialServiceGetFriendCountProcedure is the fully-qualified name of the SocialService's GetFriendCount RPC.
+ SocialServiceGetFriendCountProcedure = "/topfans.social.SocialService/GetFriendCount"
+ // SocialServiceSearchUserForFriendProcedure is the fully-qualified name of the SocialService's SearchUserForFriend RPC.
+ SocialServiceSearchUserForFriendProcedure = "/topfans.social.SocialService/SearchUserForFriend"
+ // SocialServiceGetRandomUsersProcedure is the fully-qualified name of the SocialService's GetRandomUsers RPC.
+ SocialServiceGetRandomUsersProcedure = "/topfans.social.SocialService/GetRandomUsers"
+ // SocialServiceGetUsersPagedProcedure is the fully-qualified name of the SocialService's GetUsersPaged RPC.
+ SocialServiceGetUsersPagedProcedure = "/topfans.social.SocialService/GetUsersPaged"
+ // SocialServiceLikeAssetProcedure is the fully-qualified name of the SocialService's LikeAsset RPC.
+ SocialServiceLikeAssetProcedure = "/topfans.social.SocialService/LikeAsset"
+ // SocialServiceUnlikeAssetProcedure is the fully-qualified name of the SocialService's UnlikeAsset RPC.
+ 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"
+ // SocialServiceGetMyTodayLikedAssetsProcedure is the fully-qualified name of the SocialService's GetMyTodayLikedAssets RPC.
+ SocialServiceGetMyTodayLikedAssetsProcedure = "/topfans.social.SocialService/GetMyTodayLikedAssets"
+ // SocialServiceGetMyWeekLikedAssetsProcedure is the fully-qualified name of the SocialService's GetMyWeekLikedAssets RPC.
+ SocialServiceGetMyWeekLikedAssetsProcedure = "/topfans.social.SocialService/GetMyWeekLikedAssets"
+)
+
+var (
+ _ SocialService = (*SocialServiceImpl)(nil)
+)
+
+// SocialService is a client for the topfans.social.SocialService service.
+type SocialService interface {
+ SendFriendRequest(ctx context.Context, req *SendFriendRequestRequest, opts ...client.CallOption) (*SendFriendRequestResponse, error)
+ GetFriendRequests(ctx context.Context, req *GetFriendRequestsRequest, opts ...client.CallOption) (*GetFriendRequestsResponse, error)
+ HandleFriendRequest(ctx context.Context, req *HandleFriendRequestRequest, opts ...client.CallOption) (*HandleFriendRequestResponse, error)
+ GetFriendList(ctx context.Context, req *GetFriendListRequest, opts ...client.CallOption) (*GetFriendListResponse, error)
+ DeleteFriend(ctx context.Context, req *DeleteFriendRequest, opts ...client.CallOption) (*DeleteFriendResponse, error)
+ SetFriendRemark(ctx context.Context, req *SetFriendRemarkRequest, opts ...client.CallOption) (*SetFriendRemarkResponse, error)
+ CheckFriendship(ctx context.Context, req *CheckFriendshipRequest, opts ...client.CallOption) (*CheckFriendshipResponse, error)
+ GetFriendCount(ctx context.Context, req *GetFriendCountRequest, opts ...client.CallOption) (*GetFriendCountResponse, error)
+ SearchUserForFriend(ctx context.Context, req *SearchUserForFriendRequest, opts ...client.CallOption) (*SearchUserForFriendResponse, error)
+ GetRandomUsers(ctx context.Context, req *GetRandomUsersRequest, opts ...client.CallOption) (*GetRandomUsersResponse, error)
+ GetUsersPaged(ctx context.Context, req *GetUsersPagedRequest, opts ...client.CallOption) (*GetUsersPagedResponse, error)
+ 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)
+ GetMyTodayLikedAssets(ctx context.Context, req *GetMyTodayLikedAssetsRequest, opts ...client.CallOption) (*GetMyTodayLikedAssetsResponse, error)
+ GetMyWeekLikedAssets(ctx context.Context, req *GetMyWeekLikedAssetsRequest, opts ...client.CallOption) (*GetMyWeekLikedAssetsResponse, error)
+}
+
+// NewSocialService constructs a client for the social.SocialService service.
+func NewSocialService(cli *client.Client, opts ...client.ReferenceOption) (SocialService, error) {
+ conn, err := cli.DialWithInfo("topfans.social.SocialService", &SocialService_ClientInfo, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &SocialServiceImpl{
+ conn: conn,
+ }, nil
+}
+
+func SetConsumerSocialService(srv common.RPCService) {
+ dubbo.SetConsumerServiceWithInfo(srv, &SocialService_ClientInfo)
+}
+
+// SocialServiceImpl implements SocialService.
+type SocialServiceImpl struct {
+ conn *client.Connection
+}
+
+func (c *SocialServiceImpl) SendFriendRequest(ctx context.Context, req *SendFriendRequestRequest, opts ...client.CallOption) (*SendFriendRequestResponse, error) {
+ resp := new(SendFriendRequestResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "SendFriendRequest", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetFriendRequests(ctx context.Context, req *GetFriendRequestsRequest, opts ...client.CallOption) (*GetFriendRequestsResponse, error) {
+ resp := new(GetFriendRequestsResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetFriendRequests", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) HandleFriendRequest(ctx context.Context, req *HandleFriendRequestRequest, opts ...client.CallOption) (*HandleFriendRequestResponse, error) {
+ resp := new(HandleFriendRequestResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "HandleFriendRequest", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetFriendList(ctx context.Context, req *GetFriendListRequest, opts ...client.CallOption) (*GetFriendListResponse, error) {
+ resp := new(GetFriendListResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetFriendList", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) DeleteFriend(ctx context.Context, req *DeleteFriendRequest, opts ...client.CallOption) (*DeleteFriendResponse, error) {
+ resp := new(DeleteFriendResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "DeleteFriend", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) SetFriendRemark(ctx context.Context, req *SetFriendRemarkRequest, opts ...client.CallOption) (*SetFriendRemarkResponse, error) {
+ resp := new(SetFriendRemarkResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "SetFriendRemark", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) CheckFriendship(ctx context.Context, req *CheckFriendshipRequest, opts ...client.CallOption) (*CheckFriendshipResponse, error) {
+ resp := new(CheckFriendshipResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "CheckFriendship", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetFriendCount(ctx context.Context, req *GetFriendCountRequest, opts ...client.CallOption) (*GetFriendCountResponse, error) {
+ resp := new(GetFriendCountResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetFriendCount", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) SearchUserForFriend(ctx context.Context, req *SearchUserForFriendRequest, opts ...client.CallOption) (*SearchUserForFriendResponse, error) {
+ resp := new(SearchUserForFriendResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "SearchUserForFriend", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetRandomUsers(ctx context.Context, req *GetRandomUsersRequest, opts ...client.CallOption) (*GetRandomUsersResponse, error) {
+ resp := new(GetRandomUsersResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetRandomUsers", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetUsersPaged(ctx context.Context, req *GetUsersPagedRequest, opts ...client.CallOption) (*GetUsersPagedResponse, error) {
+ resp := new(GetUsersPagedResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetUsersPaged", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) LikeAsset(ctx context.Context, req *LikeAssetRequest, opts ...client.CallOption) (*LikeAssetResponse, error) {
+ resp := new(LikeAssetResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "LikeAsset", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) UnlikeAsset(ctx context.Context, req *UnlikeAssetRequest, opts ...client.CallOption) (*UnlikeAssetResponse, error) {
+ resp := new(UnlikeAssetResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "UnlikeAsset", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) CheckAssetLike(ctx context.Context, req *CheckAssetLikeRequest, opts ...client.CallOption) (*CheckAssetLikeResponse, error) {
+ resp := new(CheckAssetLikeResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "CheckAssetLike", opts...); err != nil {
+ return nil, err
+ }
+ 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
+}
+
+func (c *SocialServiceImpl) GetMyTodayLikedAssets(ctx context.Context, req *GetMyTodayLikedAssetsRequest, opts ...client.CallOption) (*GetMyTodayLikedAssetsResponse, error) {
+ resp := new(GetMyTodayLikedAssetsResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyTodayLikedAssets", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *SocialServiceImpl) GetMyWeekLikedAssets(ctx context.Context, req *GetMyWeekLikedAssetsRequest, opts ...client.CallOption) (*GetMyWeekLikedAssetsResponse, error) {
+ resp := new(GetMyWeekLikedAssetsResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetMyWeekLikedAssets", 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", "GetMyLikedAssets", "GetMyTodayLikedAssets", "GetMyWeekLikedAssets"},
+ ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) {
+ dubboCli := dubboCliRaw.(*SocialServiceImpl)
+ dubboCli.conn = conn
+ },
+}
+
+// SocialServiceHandler is an implementation of the topfans.social.SocialService service.
+type SocialServiceHandler interface {
+ SendFriendRequest(context.Context, *SendFriendRequestRequest) (*SendFriendRequestResponse, error)
+ GetFriendRequests(context.Context, *GetFriendRequestsRequest) (*GetFriendRequestsResponse, error)
+ HandleFriendRequest(context.Context, *HandleFriendRequestRequest) (*HandleFriendRequestResponse, error)
+ GetFriendList(context.Context, *GetFriendListRequest) (*GetFriendListResponse, error)
+ DeleteFriend(context.Context, *DeleteFriendRequest) (*DeleteFriendResponse, error)
+ SetFriendRemark(context.Context, *SetFriendRemarkRequest) (*SetFriendRemarkResponse, error)
+ CheckFriendship(context.Context, *CheckFriendshipRequest) (*CheckFriendshipResponse, error)
+ GetFriendCount(context.Context, *GetFriendCountRequest) (*GetFriendCountResponse, error)
+ SearchUserForFriend(context.Context, *SearchUserForFriendRequest) (*SearchUserForFriendResponse, error)
+ GetRandomUsers(context.Context, *GetRandomUsersRequest) (*GetRandomUsersResponse, error)
+ GetUsersPaged(context.Context, *GetUsersPagedRequest) (*GetUsersPagedResponse, error)
+ LikeAsset(context.Context, *LikeAssetRequest) (*LikeAssetResponse, error)
+ UnlikeAsset(context.Context, *UnlikeAssetRequest) (*UnlikeAssetResponse, error)
+ CheckAssetLike(context.Context, *CheckAssetLikeRequest) (*CheckAssetLikeResponse, error)
+ GetMyLikedAssets(context.Context, *GetMyLikedAssetsRequest) (*GetMyLikedAssetsResponse, error)
+ GetMyTodayLikedAssets(context.Context, *GetMyTodayLikedAssetsRequest) (*GetMyTodayLikedAssetsResponse, error)
+ GetMyWeekLikedAssets(context.Context, *GetMyWeekLikedAssetsRequest) (*GetMyWeekLikedAssetsResponse, error)
+}
+
+func RegisterSocialServiceHandler(srv *server.Server, hdlr SocialServiceHandler, opts ...server.ServiceOption) error {
+ return srv.Register(hdlr, &SocialService_ServiceInfo, opts...)
+}
+
+func SetProviderSocialService(srv common.RPCService) {
+ dubbo.SetProviderServiceWithInfo(srv, &SocialService_ServiceInfo)
+}
+
+var SocialService_ServiceInfo = server.ServiceInfo{
+ InterfaceName: "topfans.social.SocialService",
+ ServiceType: (*SocialServiceHandler)(nil),
+ Methods: []server.MethodInfo{
+ {
+ Name: "SendFriendRequest",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(SendFriendRequestRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*SendFriendRequestRequest)
+ res, err := handler.(SocialServiceHandler).SendFriendRequest(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetFriendRequests",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetFriendRequestsRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetFriendRequestsRequest)
+ res, err := handler.(SocialServiceHandler).GetFriendRequests(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "HandleFriendRequest",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(HandleFriendRequestRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*HandleFriendRequestRequest)
+ res, err := handler.(SocialServiceHandler).HandleFriendRequest(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetFriendList",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetFriendListRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetFriendListRequest)
+ res, err := handler.(SocialServiceHandler).GetFriendList(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "DeleteFriend",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(DeleteFriendRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*DeleteFriendRequest)
+ res, err := handler.(SocialServiceHandler).DeleteFriend(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "SetFriendRemark",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(SetFriendRemarkRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*SetFriendRemarkRequest)
+ res, err := handler.(SocialServiceHandler).SetFriendRemark(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "CheckFriendship",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(CheckFriendshipRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*CheckFriendshipRequest)
+ res, err := handler.(SocialServiceHandler).CheckFriendship(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetFriendCount",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetFriendCountRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetFriendCountRequest)
+ res, err := handler.(SocialServiceHandler).GetFriendCount(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "SearchUserForFriend",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(SearchUserForFriendRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*SearchUserForFriendRequest)
+ res, err := handler.(SocialServiceHandler).SearchUserForFriend(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetRandomUsers",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetRandomUsersRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetRandomUsersRequest)
+ res, err := handler.(SocialServiceHandler).GetRandomUsers(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetUsersPaged",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetUsersPagedRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetUsersPagedRequest)
+ res, err := handler.(SocialServiceHandler).GetUsersPaged(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "LikeAsset",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(LikeAssetRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*LikeAssetRequest)
+ res, err := handler.(SocialServiceHandler).LikeAsset(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "UnlikeAsset",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(UnlikeAssetRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*UnlikeAssetRequest)
+ res, err := handler.(SocialServiceHandler).UnlikeAsset(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "CheckAssetLike",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(CheckAssetLikeRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*CheckAssetLikeRequest)
+ res, err := handler.(SocialServiceHandler).CheckAssetLike(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ 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
+ },
+ },
+ {
+ Name: "GetMyTodayLikedAssets",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetMyTodayLikedAssetsRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetMyTodayLikedAssetsRequest)
+ res, err := handler.(SocialServiceHandler).GetMyTodayLikedAssets(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ {
+ Name: "GetMyWeekLikedAssets",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetMyWeekLikedAssetsRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetMyWeekLikedAssetsRequest)
+ res, err := handler.(SocialServiceHandler).GetMyWeekLikedAssets(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
+ },
+}
diff --git a/backend/pkg/proto/gallery/gallery.pb.go b/backend/pkg/proto/gallery/gallery.pb.go
index 27a730e..28ae39f 100644
--- a/backend/pkg/proto/gallery/gallery.pb.go
+++ b/backend/pkg/proto/gallery/gallery.pb.go
@@ -1215,6 +1215,282 @@ func (x *ExhibitedAssetItem) GetEarnings() int64 {
return 0
}
+// 获取灵感瀑布藏品列表请求
+type GetInspirationFlowRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Cursor string `protobuf:"bytes,1,opt,name=cursor,proto3" json:"cursor,omitempty"` // 游标(首次请求为空)
+ Direction string `protobuf:"bytes,2,opt,name=direction,proto3" json:"direction,omitempty"` // 滚动方向:right(加载新数据)/ left(加载历史)
+ Limit int32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` // 每页数量(默认10,最大20)
+ Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` // 过滤类型:badge/poster/original/all(默认all)
+ SessionId string `protobuf:"bytes,5,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` // 会话ID(首次请求时为空,后端返回新的session_id)
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetInspirationFlowRequest) Reset() {
+ *x = GetInspirationFlowRequest{}
+ mi := &file_gallery_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetInspirationFlowRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetInspirationFlowRequest) ProtoMessage() {}
+
+func (x *GetInspirationFlowRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_gallery_proto_msgTypes[20]
+ 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 GetInspirationFlowRequest.ProtoReflect.Descriptor instead.
+func (*GetInspirationFlowRequest) Descriptor() ([]byte, []int) {
+ return file_gallery_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *GetInspirationFlowRequest) GetCursor() string {
+ if x != nil {
+ return x.Cursor
+ }
+ return ""
+}
+
+func (x *GetInspirationFlowRequest) GetDirection() string {
+ if x != nil {
+ return x.Direction
+ }
+ return ""
+}
+
+func (x *GetInspirationFlowRequest) GetLimit() int32 {
+ if x != nil {
+ return x.Limit
+ }
+ return 0
+}
+
+func (x *GetInspirationFlowRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *GetInspirationFlowRequest) GetSessionId() string {
+ if x != nil {
+ return x.SessionId
+ }
+ return ""
+}
+
+// 获取灵感瀑布藏品列表响应
+type GetInspirationFlowResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
+ Data *InspirationFlowData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetInspirationFlowResponse) Reset() {
+ *x = GetInspirationFlowResponse{}
+ mi := &file_gallery_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetInspirationFlowResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetInspirationFlowResponse) ProtoMessage() {}
+
+func (x *GetInspirationFlowResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_gallery_proto_msgTypes[21]
+ 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 GetInspirationFlowResponse.ProtoReflect.Descriptor instead.
+func (*GetInspirationFlowResponse) Descriptor() ([]byte, []int) {
+ return file_gallery_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *GetInspirationFlowResponse) GetBase() *common.BaseResponse {
+ if x != nil {
+ return x.Base
+ }
+ return nil
+}
+
+func (x *GetInspirationFlowResponse) GetData() *InspirationFlowData {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// 灵感瀑布数据
+type InspirationFlowData struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Items []*InspirationFlowItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` // 藏品列表
+ Cursor string `protobuf:"bytes,2,opt,name=cursor,proto3" json:"cursor,omitempty"` // 下次请求的游标
+ HasMore bool `protobuf:"varint,3,opt,name=has_more,json=hasMore,proto3" json:"has_more,omitempty"` // 是否有更多
+ SessionId string `protobuf:"bytes,4,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` // 会话ID(首次请求时返回)
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *InspirationFlowData) Reset() {
+ *x = InspirationFlowData{}
+ mi := &file_gallery_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *InspirationFlowData) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InspirationFlowData) ProtoMessage() {}
+
+func (x *InspirationFlowData) ProtoReflect() protoreflect.Message {
+ mi := &file_gallery_proto_msgTypes[22]
+ 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 InspirationFlowData.ProtoReflect.Descriptor instead.
+func (*InspirationFlowData) Descriptor() ([]byte, []int) {
+ return file_gallery_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *InspirationFlowData) GetItems() []*InspirationFlowItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+func (x *InspirationFlowData) GetCursor() string {
+ if x != nil {
+ return x.Cursor
+ }
+ return ""
+}
+
+func (x *InspirationFlowData) GetHasMore() bool {
+ if x != nil {
+ return x.HasMore
+ }
+ return false
+}
+
+func (x *InspirationFlowData) GetSessionId() string {
+ if x != nil {
+ return x.SessionId
+ }
+ return ""
+}
+
+// 灵感瀑布藏品项
+type InspirationFlowItem 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"` // 点赞数
+ OwnerNickname string `protobuf:"bytes,5,opt,name=owner_nickname,json=ownerNickname,proto3" json:"owner_nickname,omitempty"` // 展出者昵称
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *InspirationFlowItem) Reset() {
+ *x = InspirationFlowItem{}
+ mi := &file_gallery_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *InspirationFlowItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InspirationFlowItem) ProtoMessage() {}
+
+func (x *InspirationFlowItem) ProtoReflect() protoreflect.Message {
+ mi := &file_gallery_proto_msgTypes[23]
+ 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 InspirationFlowItem.ProtoReflect.Descriptor instead.
+func (*InspirationFlowItem) Descriptor() ([]byte, []int) {
+ return file_gallery_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *InspirationFlowItem) GetAssetId() int64 {
+ if x != nil {
+ return x.AssetId
+ }
+ return 0
+}
+
+func (x *InspirationFlowItem) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *InspirationFlowItem) GetCoverUrl() string {
+ if x != nil {
+ return x.CoverUrl
+ }
+ return ""
+}
+
+func (x *InspirationFlowItem) GetLikeCount() int32 {
+ if x != nil {
+ return x.LikeCount
+ }
+ return 0
+}
+
+func (x *InspirationFlowItem) GetOwnerNickname() string {
+ if x != nil {
+ return x.OwnerNickname
+ }
+ return ""
+}
+
var File_gallery_proto protoreflect.FileDescriptor
const file_gallery_proto_rawDesc = "" +
@@ -1310,7 +1586,30 @@ const file_gallery_proto_rawDesc = "" +
"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" +
+ "\bearnings\x18\a \x01(\x03R\bearnings\"\x9a\x01\n" +
+ "\x19GetInspirationFlowRequest\x12\x16\n" +
+ "\x06cursor\x18\x01 \x01(\tR\x06cursor\x12\x1c\n" +
+ "\tdirection\x18\x02 \x01(\tR\tdirection\x12\x14\n" +
+ "\x05limit\x18\x03 \x01(\x05R\x05limit\x12\x12\n" +
+ "\x04type\x18\x04 \x01(\tR\x04type\x12\x1d\n" +
+ "\n" +
+ "session_id\x18\x05 \x01(\tR\tsessionId\"\x88\x01\n" +
+ "\x1aGetInspirationFlowResponse\x120\n" +
+ "\x04base\x18\x01 \x01(\v2\x1c.topfans.common.BaseResponseR\x04base\x128\n" +
+ "\x04data\x18\x02 \x01(\v2$.topfans.gallery.InspirationFlowDataR\x04data\"\xa3\x01\n" +
+ "\x13InspirationFlowData\x12:\n" +
+ "\x05items\x18\x01 \x03(\v2$.topfans.gallery.InspirationFlowItemR\x05items\x12\x16\n" +
+ "\x06cursor\x18\x02 \x01(\tR\x06cursor\x12\x19\n" +
+ "\bhas_more\x18\x03 \x01(\bR\ahasMore\x12\x1d\n" +
+ "\n" +
+ "session_id\x18\x04 \x01(\tR\tsessionId\"\xa7\x01\n" +
+ "\x13InspirationFlowItem\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" +
+ "\x0eowner_nickname\x18\x05 \x01(\tR\rownerNickname2\xc6\a\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" +
@@ -1319,7 +1618,8 @@ const file_gallery_proto_rawDesc = "" +
"\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}/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"
+ "\x14GetMyExhibitedAssets\x12,.topfans.gallery.GetMyExhibitedAssetsRequest\x1a-.topfans.gallery.GetMyExhibitedAssetsResponse\"#\x82\xd3\xe4\x93\x02\x1d\x12\x1b/api/v1/me/exhibited-assets\x12\x8f\x01\n" +
+ "\x12GetInspirationFlow\x12*.topfans.gallery.GetInspirationFlowRequest\x1a+.topfans.gallery.GetInspirationFlowResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/api/v1/inspiration-flowB6Z4github.com/topfans/backend/pkg/proto/gallery;galleryb\x06proto3"
var (
file_gallery_proto_rawDescOnce sync.Once
@@ -1333,7 +1633,7 @@ func file_gallery_proto_rawDescGZIP() []byte {
return file_gallery_proto_rawDescData
}
-var file_gallery_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
+var file_gallery_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
var file_gallery_proto_goTypes = []any{
(*GetMyGalleryRequest)(nil), // 0: topfans.gallery.GetMyGalleryRequest
(*GetMyGalleryResponse)(nil), // 1: topfans.gallery.GetMyGalleryResponse
@@ -1355,41 +1655,50 @@ var file_gallery_proto_goTypes = []any{
(*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
+ (*GetInspirationFlowRequest)(nil), // 20: topfans.gallery.GetInspirationFlowRequest
+ (*GetInspirationFlowResponse)(nil), // 21: topfans.gallery.GetInspirationFlowResponse
+ (*InspirationFlowData)(nil), // 22: topfans.gallery.InspirationFlowData
+ (*InspirationFlowItem)(nil), // 23: topfans.gallery.InspirationFlowItem
+ (*common.BaseResponse)(nil), // 24: topfans.common.BaseResponse
}
var file_gallery_proto_depIdxs = []int32{
- 20, // 0: topfans.gallery.GetMyGalleryResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 0: topfans.gallery.GetMyGalleryResponse.base:type_name -> topfans.common.BaseResponse
8, // 1: topfans.gallery.GetMyGalleryResponse.data:type_name -> topfans.gallery.GalleryData
- 20, // 2: topfans.gallery.GetUserGalleryResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 2: topfans.gallery.GetUserGalleryResponse.base:type_name -> topfans.common.BaseResponse
8, // 3: topfans.gallery.GetUserGalleryResponse.data:type_name -> topfans.gallery.GalleryData
- 20, // 4: topfans.gallery.PlaceAssetResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 4: topfans.gallery.PlaceAssetResponse.base:type_name -> topfans.common.BaseResponse
12, // 5: topfans.gallery.PlaceAssetResponse.data:type_name -> topfans.gallery.PlaceAssetData
- 20, // 6: topfans.gallery.UnlockSlotResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 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
- 20, // 11: topfans.gallery.RemoveFromSlotResponse.base:type_name -> topfans.common.BaseResponse
- 20, // 12: topfans.gallery.GetMyExhibitedAssetsResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 11: topfans.gallery.RemoveFromSlotResponse.base:type_name -> topfans.common.BaseResponse
+ 24, // 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
+ 24, // 15: topfans.gallery.GetInspirationFlowResponse.base:type_name -> topfans.common.BaseResponse
+ 22, // 16: topfans.gallery.GetInspirationFlowResponse.data:type_name -> topfans.gallery.InspirationFlowData
+ 23, // 17: topfans.gallery.InspirationFlowData.items:type_name -> topfans.gallery.InspirationFlowItem
+ 0, // 18: topfans.gallery.GalleryService.GetMyGallery:input_type -> topfans.gallery.GetMyGalleryRequest
+ 2, // 19: topfans.gallery.GalleryService.GetUserGallery:input_type -> topfans.gallery.GetUserGalleryRequest
+ 4, // 20: topfans.gallery.GalleryService.PlaceAsset:input_type -> topfans.gallery.PlaceAssetRequest
+ 6, // 21: topfans.gallery.GalleryService.UnlockSlot:input_type -> topfans.gallery.UnlockSlotRequest
+ 14, // 22: topfans.gallery.GalleryService.RemoveFromSlot:input_type -> topfans.gallery.RemoveFromSlotRequest
+ 16, // 23: topfans.gallery.GalleryService.GetMyExhibitedAssets:input_type -> topfans.gallery.GetMyExhibitedAssetsRequest
+ 20, // 24: topfans.gallery.GalleryService.GetInspirationFlow:input_type -> topfans.gallery.GetInspirationFlowRequest
+ 1, // 25: topfans.gallery.GalleryService.GetMyGallery:output_type -> topfans.gallery.GetMyGalleryResponse
+ 3, // 26: topfans.gallery.GalleryService.GetUserGallery:output_type -> topfans.gallery.GetUserGalleryResponse
+ 5, // 27: topfans.gallery.GalleryService.PlaceAsset:output_type -> topfans.gallery.PlaceAssetResponse
+ 7, // 28: topfans.gallery.GalleryService.UnlockSlot:output_type -> topfans.gallery.UnlockSlotResponse
+ 15, // 29: topfans.gallery.GalleryService.RemoveFromSlot:output_type -> topfans.gallery.RemoveFromSlotResponse
+ 17, // 30: topfans.gallery.GalleryService.GetMyExhibitedAssets:output_type -> topfans.gallery.GetMyExhibitedAssetsResponse
+ 21, // 31: topfans.gallery.GalleryService.GetInspirationFlow:output_type -> topfans.gallery.GetInspirationFlowResponse
+ 25, // [25:32] is the sub-list for method output_type
+ 18, // [18:25] is the sub-list for method input_type
+ 18, // [18:18] is the sub-list for extension type_name
+ 18, // [18:18] is the sub-list for extension extendee
+ 0, // [0:18] is the sub-list for field type_name
}
func init() { file_gallery_proto_init() }
@@ -1403,7 +1712,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: 20,
+ NumMessages: 24,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/backend/pkg/proto/gallery/gallery.triple.go b/backend/pkg/proto/gallery/gallery.triple.go
index 18b0bd9..4a991a4 100644
--- a/backend/pkg/proto/gallery/gallery.triple.go
+++ b/backend/pkg/proto/gallery/gallery.triple.go
@@ -48,6 +48,8 @@ const (
GalleryServiceRemoveFromSlotProcedure = "/topfans.gallery.GalleryService/RemoveFromSlot"
// GalleryServiceGetMyExhibitedAssetsProcedure is the fully-qualified name of the GalleryService's GetMyExhibitedAssets RPC.
GalleryServiceGetMyExhibitedAssetsProcedure = "/topfans.gallery.GalleryService/GetMyExhibitedAssets"
+ // GalleryServiceGetInspirationFlowProcedure is the fully-qualified name of the GalleryService's GetInspirationFlow RPC.
+ GalleryServiceGetInspirationFlowProcedure = "/topfans.gallery.GalleryService/GetInspirationFlow"
)
var (
@@ -62,6 +64,7 @@ type GalleryService interface {
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)
+ GetInspirationFlow(ctx context.Context, req *GetInspirationFlowRequest, opts ...client.CallOption) (*GetInspirationFlowResponse, error)
}
// NewGalleryService constructs a client for the gallery.GalleryService service.
@@ -132,9 +135,17 @@ func (c *GalleryServiceImpl) GetMyExhibitedAssets(ctx context.Context, req *GetM
return resp, nil
}
+func (c *GalleryServiceImpl) GetInspirationFlow(ctx context.Context, req *GetInspirationFlowRequest, opts ...client.CallOption) (*GetInspirationFlowResponse, error) {
+ resp := new(GetInspirationFlowResponse)
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp, "GetInspirationFlow", 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", "GetMyExhibitedAssets"},
+ MethodNames: []string{"GetMyGallery", "GetUserGallery", "PlaceAsset", "UnlockSlot", "RemoveFromSlot", "GetMyExhibitedAssets", "GetInspirationFlow"},
ConnectionInjectFunc: func(dubboCliRaw interface{}, conn *client.Connection) {
dubboCli := dubboCliRaw.(*GalleryServiceImpl)
dubboCli.conn = conn
@@ -149,6 +160,7 @@ type GalleryServiceHandler interface {
UnlockSlot(context.Context, *UnlockSlotRequest) (*UnlockSlotResponse, error)
RemoveFromSlot(context.Context, *RemoveFromSlotRequest) (*RemoveFromSlotResponse, error)
GetMyExhibitedAssets(context.Context, *GetMyExhibitedAssetsRequest) (*GetMyExhibitedAssetsResponse, error)
+ GetInspirationFlow(context.Context, *GetInspirationFlowRequest) (*GetInspirationFlowResponse, error)
}
func RegisterGalleryServiceHandler(srv *server.Server, hdlr GalleryServiceHandler, opts ...server.ServiceOption) error {
@@ -253,5 +265,20 @@ var GalleryService_ServiceInfo = server.ServiceInfo{
return triple_protocol.NewResponse(res), nil
},
},
+ {
+ Name: "GetInspirationFlow",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new(GetInspirationFlowRequest)
+ },
+ MethodFunc: func(ctx context.Context, args []interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*GetInspirationFlowRequest)
+ res, err := handler.(GalleryServiceHandler).GetInspirationFlow(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },
},
}
diff --git a/backend/pkg/proto/task/task.pb.go b/backend/pkg/proto/task/task.pb.go
index ed997ca..77ff955 100644
--- a/backend/pkg/proto/task/task.pb.go
+++ b/backend/pkg/proto/task/task.pb.go
@@ -605,6 +605,7 @@ type OnboardingStage struct {
Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` // pending/completed/in_progress
IsCurrent bool `protobuf:"varint,7,opt,name=is_current,json=isCurrent,proto3" json:"is_current,omitempty"`
AllTasksCompleted bool `protobuf:"varint,8,opt,name=all_tasks_completed,json=allTasksCompleted,proto3" json:"all_tasks_completed,omitempty"` // 该阶段所有任务是否完成
+ IsRewardClaimed bool `protobuf:"varint,9,opt,name=is_reward_claimed,json=isRewardClaimed,proto3" json:"is_reward_claimed,omitempty"` // 该阶段奖励是否已领取
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -695,6 +696,13 @@ func (x *OnboardingStage) GetAllTasksCompleted() bool {
return false
}
+func (x *OnboardingStage) GetIsRewardClaimed() bool {
+ if x != nil {
+ return x.IsRewardClaimed
+ }
+ return false
+}
+
type CompleteGuideRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
TaskKey string `protobuf:"bytes,1,opt,name=task_key,json=taskKey,proto3" json:"task_key,omitempty"`
@@ -1942,7 +1950,7 @@ const file_task_proto_rawDesc = "" +
"\n" +
"experience\x18\x04 \x01(\x03R\n" +
"experience\x12*\n" +
- "\x11claimed_task_keys\x18\x05 \x03(\tR\x0fclaimedTaskKeys\"\x96\x02\n" +
+ "\x11claimed_task_keys\x18\x05 \x03(\tR\x0fclaimedTaskKeys\"\xc2\x02\n" +
"\x0fOnboardingStage\x12\x14\n" +
"\x05stage\x18\x01 \x01(\x05R\x05stage\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12,\n" +
@@ -1953,7 +1961,8 @@ const file_task_proto_rawDesc = "" +
"\x06status\x18\x06 \x01(\tR\x06status\x12\x1d\n" +
"\n" +
"is_current\x18\a \x01(\bR\tisCurrent\x12.\n" +
- "\x13all_tasks_completed\x18\b \x01(\bR\x11allTasksCompleted\"h\n" +
+ "\x13all_tasks_completed\x18\b \x01(\bR\x11allTasksCompleted\x12*\n" +
+ "\x11is_reward_claimed\x18\t \x01(\bR\x0fisRewardClaimed\"h\n" +
"\x14CompleteGuideRequest\x12\x19\n" +
"\btask_key\x18\x01 \x01(\tR\ataskKey\x125\n" +
"\x06stages\x18\x02 \x03(\v2\x1d.topfans.task.OnboardingStageR\x06stages\"\xd6\x01\n" +
diff --git a/backend/proto/gallery.proto b/backend/proto/gallery.proto
index e93626a..d948278 100644
--- a/backend/proto/gallery.proto
+++ b/backend/proto/gallery.proto
@@ -54,6 +54,13 @@ service GalleryService {
get: "/api/v1/me/exhibited-assets"
};
}
+
+ // 获取灵感瀑布藏品列表
+ rpc GetInspirationFlow(GetInspirationFlowRequest) returns (GetInspirationFlowResponse) {
+ option (google.api.http) = {
+ get: "/api/v1/inspiration-flow"
+ };
+ }
}
// 请求和响应消息定义
@@ -181,3 +188,37 @@ message ExhibitedAssetItem {
int64 expire_at = 6; // 展出过期时间(毫秒时间戳)
int64 earnings = 7; // 当前可领取收益
}
+
+// ==================== 灵感瀑布相关消息 ====================
+
+// 获取灵感瀑布藏品列表请求
+message GetInspirationFlowRequest {
+ string cursor = 1; // 游标(首次请求为空)
+ string direction = 2; // 滚动方向:right(加载新数据)/ left(加载历史)
+ int32 limit = 3; // 每页数量(默认10,最大20)
+ string type = 4; // 过滤类型:badge/poster/original/all(默认all)
+ string session_id = 5; // 会话ID(首次请求时为空,后端返回新的session_id)
+}
+
+// 获取灵感瀑布藏品列表响应
+message GetInspirationFlowResponse {
+ topfans.common.BaseResponse base = 1;
+ InspirationFlowData data = 2;
+}
+
+// 灵感瀑布数据
+message InspirationFlowData {
+ repeated InspirationFlowItem items = 1; // 藏品列表
+ string cursor = 2; // 下次请求的游标
+ bool has_more = 3; // 是否有更多
+ string session_id = 4; // 会话ID(首次请求时返回)
+}
+
+// 灵感瀑布藏品项
+message InspirationFlowItem {
+ int64 asset_id = 1; // 资产ID
+ string name = 2; // 藏品名称
+ string cover_url = 3; // 封面图URL
+ int32 like_count = 4; // 点赞数
+ string owner_nickname = 5; // 展出者昵称
+}
diff --git a/backend/services/galleryService/provider/gallery_provider.go b/backend/services/galleryService/provider/gallery_provider.go
index 762c647..14bbe98 100644
--- a/backend/services/galleryService/provider/gallery_provider.go
+++ b/backend/services/galleryService/provider/gallery_provider.go
@@ -338,6 +338,64 @@ func (p *GalleryProvider) GetMyExhibitedAssets(ctx context.Context, req *pb.GetM
return p.exhibitionService.GetMyExhibitedAssets(ctx, userID, starID, req)
}
+// GetInspirationFlow 获取灵感瀑布藏品列表
+func (p *GalleryProvider) GetInspirationFlow(ctx context.Context, req *pb.GetInspirationFlowRequest) (*pb.GetInspirationFlowResponse, error) {
+ logger.Logger.Info("Received GetInspirationFlow request",
+ zap.String("cursor", req.Cursor),
+ zap.String("direction", req.Direction),
+ zap.Int32("limit", req.Limit),
+ zap.String("type", req.Type),
+ )
+
+ // 从 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.GetInspirationFlowResponse{
+ Base: &pbCommon.BaseResponse{
+ Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED,
+ Message: "user authentication required",
+ Timestamp: 0,
+ },
+ }, err
+ }
+
+ // 调用Service层
+ data, _, err := p.galleryService.GetInspirationFlow(userID, starID, req.Cursor, req.Direction, req.Limit, req.Type, req.SessionId)
+ if err != nil {
+ logger.Logger.Error("GetInspirationFlow failed",
+ zap.Int64("user_id", userID),
+ zap.Int64("star_id", starID),
+ zap.String("direction", req.Direction),
+ zap.Error(err),
+ )
+ return &pb.GetInspirationFlowResponse{
+ Base: &pbCommon.BaseResponse{
+ Code: appErrors.ToStatusCode(err),
+ Message: err.Error(),
+ Timestamp: 0,
+ },
+ }, err
+ }
+
+ logger.Logger.Info("GetInspirationFlow successful",
+ zap.Int64("user_id", userID),
+ zap.Int64("star_id", starID),
+ zap.Int("item_count", len(data.Items)),
+ )
+
+ return &pb.GetInspirationFlowResponse{
+ Base: &pbCommon.BaseResponse{
+ Code: pbCommon.StatusCode_STATUS_OK,
+ Message: "success",
+ Timestamp: 0,
+ },
+ Data: data,
+ }, nil
+}
+
// ==================== 辅助函数 ====================
// extractUserInfoFromDubboAttachments 从Dubbo attachments提取用户信息
diff --git a/backend/services/galleryService/repository/gallery_repository.go b/backend/services/galleryService/repository/gallery_repository.go
index b618929..210bc96 100644
--- a/backend/services/galleryService/repository/gallery_repository.go
+++ b/backend/services/galleryService/repository/gallery_repository.go
@@ -41,6 +41,30 @@ type GalleryRepository interface {
// pageSize: 每页数量
// 返回: 作品列表、总数量
GetMyExhibitedAssets(userID, starID int64, page, pageSize int) ([]*ExhibitedAssetInfo, int64, error)
+
+ // ========== 灵感瀑布相关 ==========
+
+ // CountValidExhibitions 统计有效展品数量
+ // starID: 明星ID
+ // materialType: 素材类型过滤(空字符串表示不过滤)
+ CountValidExhibitions(starID int64, materialType string) (int64, error)
+
+ // GetRandomExhibitions 获取随机展品列表
+ // starID: 明星ID
+ // materialType: 素材类型过滤(空字符串表示不过滤)
+ // excludeIDs: 排除的展品ID列表(用于去重)
+ // limit: 返回数量
+ // offset: 偏移量(随机生成)
+ GetRandomExhibitions(starID int64, materialType string, excludeIDs []int64, limit, offset int) ([]*InspirationFlowItem, error)
+}
+
+// InspirationFlowItem 灵感瀑布展品项
+type InspirationFlowItem struct {
+ AssetID int64
+ Name string
+ CoverURL string
+ LikeCount int32
+ OwnerNickname string
}
// ExhibitedAssetInfo 我展出的作品信息
@@ -255,18 +279,19 @@ func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pag
// 数据查询
offset := (page - 1) * pageSize
err = r.db.Model(&models.Exhibition{}).
- Select(`exhibitions.asset_id, a.name, a.cover_url, a.like_count,
+ Raw(`
+ 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
+ COALESCE(CAST(SUM(err.crystal_amount) / 10 AS bigint), 0) as earnings
+ FROM exhibitions
+ JOIN assets a ON a.id = exhibitions.asset_id
+ 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 = ?
+ AND exhibitions.deleted_at IS NULL AND exhibitions.expire_at > ?
+ GROUP BY exhibitions.asset_id, a.name, a.cover_url, a.like_count, exhibitions.start_time, exhibitions.expire_at
+ ORDER BY exhibitions.start_time DESC
+ LIMIT ? OFFSET ?
+ `, userID, starID, now, pageSize, offset).Scan(&items).Error
if err != nil {
return nil, 0, err
@@ -275,6 +300,62 @@ func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pag
return items, total, nil
}
+// ========== 灵感瀑布相关实现 ==========
+
+// CountValidExhibitions 统计有效展品数量
+func (r *galleryRepository) CountValidExhibitions(starID int64, materialType string) (int64, error) {
+ var count int64
+ now := time.Now().UnixMilli()
+
+ query := r.db.Model(&models.Exhibition{}).
+ Where("occupier_star_id = ? AND expire_at > ? AND deleted_at IS NULL", starID, now)
+
+ if materialType != "" && materialType != "all" {
+ query = query.Joins("JOIN assets a ON a.id = exhibitions.asset_id").
+ Where("a.material_type = ?", materialType)
+ }
+
+ err := query.Count(&count).Error
+ return count, err
+}
+
+// GetRandomExhibitions 获取随机展品列表
+func (r *galleryRepository) GetRandomExhibitions(starID int64, materialType string, excludeIDs []int64, limit, offset int) ([]*InspirationFlowItem, error) {
+ var items []*InspirationFlowItem
+ now := time.Now().UnixMilli()
+
+ // 构建基础查询
+ baseQuery := r.db.Model(&models.Exhibition{}).
+ Where("exhibitions.occupier_star_id = ? AND exhibitions.expire_at > ? AND exhibitions.deleted_at IS NULL", starID, now)
+
+ if materialType != "" && materialType != "all" {
+ baseQuery = baseQuery.Joins("JOIN assets a ON a.id = exhibitions.asset_id").
+ Where("a.material_type = ?", materialType)
+ }
+
+ // 排除已展示的ID
+ if len(excludeIDs) > 0 {
+ baseQuery = baseQuery.Where("exhibitions.id NOT IN ?", excludeIDs)
+ }
+
+ // 执行随机排序查询
+ err := baseQuery.
+ Select(`exhibitions.asset_id, a.name, a.cover_url, a.like_count, fp.nickname as owner_nickname`).
+ Joins("JOIN assets a ON a.id = exhibitions.asset_id").
+ Joins("JOIN fan_profiles fp ON exhibitions.occupier_uid = fp.user_id AND exhibitions.occupier_star_id = fp.star_id").
+ Where("a.status = 1 AND a.is_active = true").
+ Order("RANDOM()").
+ Limit(limit).
+ Offset(offset).
+ Scan(&items).Error
+
+ if err != nil {
+ return nil, err
+ }
+
+ return items, nil
+}
+
// ==================== 辅助函数 ====================
// generateHostProfileID 生成 host_profile_id
diff --git a/docs/superpowers/specs/2026-04-27-inspiration-flow-design.md b/docs/superpowers/specs/2026-04-27-inspiration-flow-design.md
index 247ca45..77e4649 100644
--- a/docs/superpowers/specs/2026-04-27-inspiration-flow-design.md
+++ b/docs/superpowers/specs/2026-04-27-inspiration-flow-design.md
@@ -695,3 +695,104 @@ onDataLoaded() {
| 2026-04-29 | 改用随机 offset 方案(方案 B),每次请求都是独立随机,数据变化无影响 |
| 2026-04-29 | 新增双向滚动支持:向右加载新数据,向左加载历史数据,后端维护会话级缓存 |
| 2026-04-29 | 修复:修正重复的 10.4 章节、RangeSamplingStrategy 签名、游标结构说明 |
+| 2026-04-29 | 新增 Redis 会话级缓存实现方案:支持双向滚动去重 |
+
+---
+
+## 十三、Redis 会话级缓存实现
+
+### 13.1 技术选型
+
+- **客户端**: `github.com/redis/go-redis/v9`
+- **连接信息**: `localhost:6379`,无密码
+- **TTL**: 30分钟(无操作自动清理)
+
+### 13.2 缓存结构
+
+```
+Key: inspiration_flow:{star_id}:{session_id}
+Type: Hash
+Fields:
+ - displayed_ids: ["id1", "id2", ...] # 已展示ID列表(用于去重)
+ - history: {"id1": json_data1, "id2": json_data2, ...} # 历史数据详情
+TTL: 1800秒(30分钟)
+```
+
+### 13.3 环境变量配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| REDIS_HOST | Redis 主机地址 | 127.0.0.1 |
+| REDIS_PORT | Redis 端口 | 6379 |
+| REDIS_PASSWORD | Redis 密码 | (空) |
+| REDIS_DB | Redis 数据库编号 | 0 |
+
+### 13.4 核心逻辑
+
+| 方向 | 行为 |
+|------|------|
+| `direction=right` | 随机查询新数据(排除已展示ID),返回并更新缓存 |
+| `direction=left` | 从缓存的历史数据中分页返回 |
+
+### 13.5 实现文件
+
+| 文件 | 说明 |
+|------|------|
+| `backend/pkg/database/redis.go`(新建) | Redis 客户端初始化 |
+| `backend/services/socialService/repository/social_repository.go` | 新增 `GetRandomUsersExcludeIDs` |
+| `backend/services/socialService/service/friend_service.go` | 修改 `GetRandomUsers` 支持 direction + 缓存 |
+| `backend/services/socialService/provider/social_provider.go` | 透传 direction 参数 |
+| `backend/gateway/dto/social_converter.go` | 转换 exclude_ids |
+| `backend/gateway/config/config.go` | 新增 Redis 配置 |
+
+### 13.6 session_id 生成
+
+- 由后端生成(UUID)
+- 首次请求时返回给前端,前端后续请求携带
+
+### 13.7 向左滚动实现
+
+向左滚动时,后端从 Redis 缓存的 `history` 字段读取已展示数据,按 offset 分页返回。前端在左侧插入展示。
+
+### 13.8 预签名 URL 批量获取优化
+
+**问题**:前端逐个获取预签名 URL,N 个卡片产生 N 次请求。
+
+**解决方案**:新增批量接口,前端一次性获取所有 URL。
+
+**接口设计**:
+```
+POST /api/v1/assets/oss/batch-presigned-urls
+Content-Type: application/json
+
+Request:
+{
+ "files": ["path/to/img1.png", "path/to/img2.png", ...],
+ "expires": 3600,
+ "type": "asset"
+}
+
+Response:
+{
+ "code": 200,
+ "data": {
+ "urls": {
+ "path/to/img1.png": "https://xxx?signature=...",
+ "path/to/img2.png": "https://xxx?signature=..."
+ }
+ }
+}
+```
+
+**前端逻辑**:
+1. 加载用户数据后,收集所有 `cover_url`
+2. 批量调用接口获取全部预签名 URL
+3. 存入 Map 缓存,后续直接使用
+
+**实现文件**:
+| 文件 | 说明 |
+|------|------|
+| `backend/gateway/controller/asset_controller.go` | 新增 batch presigned urls 路由 |
+| `backend/gateway/dto/asset_dto.go` | 新增 BatchPresignedUrlsRequest/Response |
+| `frontend/utils/api.js` | 新增 `getBatchOssPresignedUrlsApi` |
+| `frontend/pages/square/components/WaterfallGrid.vue` | 使用批量接口替代逐个调用 |
diff --git a/frontend/pages/components/Header.vue b/frontend/pages/components/Header.vue
index aed5133..f1898b4 100644
--- a/frontend/pages/components/Header.vue
+++ b/frontend/pages/components/Header.vue
@@ -22,18 +22,18 @@
-
-
+
+ 2. 下层:文字背景块
新手引导
-
+ -->
@@ -388,13 +388,13 @@ const handleAvatarClick = () => {
if (pages.length > 0) {
const currentPage = pages[pages.length - 1];
// 检查当前页面是否是个人信息页面
- if (currentPage.route === 'pages/profile/profile') {
+ if (currentPage.route === 'pages/profile/myWorks') {
// 已经在个人信息页面,不执行跳转
return;
}
}
uni.navigateTo({
- url: '/pages/profile/profile'
+ url: '/pages/profile/myWorks'
});
};
@@ -570,7 +570,7 @@ defineExpose({
}
.balance-number {
- font-size: 22rpx;
+ font-size: 24rpx;
font-weight: bold;
color: #FFB800;
font-family: 'ZaoZiGongFangJianHei-1', sans-serif;
diff --git a/frontend/pages/profile/myWorks.vue b/frontend/pages/profile/myWorks.vue
index bba47fd..d2148bc 100644
--- a/frontend/pages/profile/myWorks.vue
+++ b/frontend/pages/profile/myWorks.vue
@@ -10,6 +10,9 @@
+
+ 个人设置
+
@@ -22,15 +25,13 @@
-
-
-
+ @tap="handleExhibitionCardTap(item, index)">
+
+
+
@@ -39,10 +40,11 @@
-
+
- {{ item.earnings || 0 }}
+ {{ item.earnings || 0 }}/时
@@ -50,9 +52,11 @@
-
+
-
+
+
@@ -60,7 +64,8 @@
-
+
+
@@ -69,34 +74,27 @@
-
+
- 今日点赞作品
+ 点赞作品
-
+
-
+
-
-
+
+
@@ -104,13 +102,15 @@
{{ item.status_text }}
{{ formatScore(item.score) }}
-
+
+
-
+
+
+{{ item.reward }}
@@ -118,7 +118,7 @@
- 今日暂无点赞作品
+ 当前暂无点赞作品
@@ -127,12 +127,8 @@
-
+
@@ -144,7 +140,24 @@ import { onShow } from '@dcloudio/uni-app';
import { doubleTapLike } from '@/utils/likeHelper.js';
const goBack = () => {
- uni.navigateBack();
+ // 获取页面栈
+ const pages = getCurrentPages();
+ if (pages.length > 1) {
+ // 有上一页,执行返回
+ uni.navigateBack();
+ } else {
+ // 没有上一页,跳转到square页面
+ uni.reLaunch({
+ url: '/pages/square/square'
+ });
+ }
+};
+
+const goToSettings = () => {
+
+ uni.navigateTo({
+ url: '/pages/profile/profile'
+ });
};
const goToCastlove = () => {
@@ -237,7 +250,7 @@ const handleExhibitionCardTap = (item, index) => {
if (success) {
// 更新在展作品的点赞数
exhibitionWorks.value[index].like_count = (exhibitionWorks.value[index].like_count || 0) + 1;
- // 将作品添加到今日点赞列表
+ // 将作品添加到当前点赞列表
const likedItem = {
id: item.id,
cover_url: item.cover_url,
@@ -275,7 +288,7 @@ const formatScore = (score) => {
// 在展作品列表
const exhibitionWorks = ref([]);
-// 今日点赞作品列表
+// 当前点赞作品列表
const likedWorks = ref([]);
// 加载我的展出作品
@@ -383,6 +396,28 @@ onShow(() => {
width: 64rpx;
}
+.nav-settings {
+ height: 64rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(to bottom right,
+ #F0E4B1 0%,
+ #F08399 50%,
+ #B94E73 100%);
+ border-radius: 24rpx;
+ padding: 8rpx 20rpx 8rpx 20rpx;
+ box-shadow:
+ 0 4rpx 12rpx rgba(255, 143, 158, 0.2),
+ inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
+}
+
+.nav-settings-text {
+ font-size: 24rpx;
+ color: #fff;
+ font-weight: 400;
+}
+
/* 内容区域 */
.scroll-content {
position: relative;
@@ -492,7 +527,7 @@ onShow(() => {
.card-user-text {
font-size: 20rpx;
color: #fff;
- background: rgba(0,0,0,0.45);
+ background: rgba(0, 0, 0, 0.45);
padding: 4rpx 14rpx;
border-radius: 20rpx;
}
@@ -532,11 +567,11 @@ onShow(() => {
}
.card-income-text-wrap {
+ width: 64rpx;
background: linear-gradient(to bottom right,
- #F0E4B1 0%,
- #F08399 50%,
- #B94E73 100%
- );
+ #F0E4B1 0%,
+ #F08399 50%,
+ #B94E73 100%);
border-radius: 999rpx;
padding: 8rpx 20rpx 8rpx 40rpx;
box-shadow:
@@ -553,7 +588,7 @@ onShow(() => {
font-weight: 700;
text-align: center;
}
-
+
.heart-icon {
width: 28rpx;
@@ -562,15 +597,15 @@ onShow(() => {
.card-rate-text-wrap {
background: linear-gradient(to bottom right,
- #F0E4B1 0%,
- #F08399 50%,
- #B94E73 100%
- );
+ #F0E4B1 0%,
+ #F08399 50%,
+ #B94E73 100%);
border-radius: 999rpx;
- padding: 2rpx 12rpx;
+ padding: 2rpx 16rpx;
box-shadow:
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
+ display: flex;
}
.card-rate-text {
@@ -643,7 +678,7 @@ onShow(() => {
color: #b09cc0;
}
-/* 今日点赞列表 */
+/* 当前点赞列表 */
.liked-list {
max-height: 732rpx;
}
@@ -686,7 +721,7 @@ onShow(() => {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
- background: rgba(180,140,220,0.3);
+ background: rgba(180, 140, 220, 0.3);
display: flex;
align-items: center;
justify-content: center;
@@ -720,8 +755,8 @@ onShow(() => {
transform: rotate(-22deg);
transform-origin: center center;
position: relative;
- z-index: 3;
- padding: 0.25rem;
+ z-index: 3;
+ padding: 0.25rem;
}
.liked-cover-frame {
diff --git a/frontend/pages/square/components/CabinItem.vue b/frontend/pages/square/components/CabinItem.vue
deleted file mode 100644
index 292b5f5..0000000
--- a/frontend/pages/square/components/CabinItem.vue
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
- {{ cabin.nickname === currentUserNickname ? '我的小屋' : cabin.nickname }}
-
- 小屋暂无人居住
-
-
-
- 剩余 {{ cabin.sharedBoothSlotsRemaining }} 个展位
-
-
-
-
-
-
-
-
diff --git a/frontend/pages/square/components/ContentTabs.vue b/frontend/pages/square/components/ContentTabs.vue
index 276a0ef..e52dfac 100644
--- a/frontend/pages/square/components/ContentTabs.vue
+++ b/frontend/pages/square/components/ContentTabs.vue
@@ -39,11 +39,10 @@ defineProps({
defineEmits(['update:modelValue'])
const tabs = [
- { key: 'hot', label: '热门作品', emoji: null, icon: '/static/square/rementubiao.png', iconWidth: 104, iconHeight: 104 },
- { key: 'xingka', label: '星卡', emoji: null, icon: '/static/square/xingka.png', iconWidth: 80, iconHeight: 80 },
- { key: 'baji', label: '把爱', emoji: null, icon: '/static/square/baji.png', iconWidth: 80, iconHeight: 80 },
- { key: 'haibao', label: '海报', emoji: null, icon: '/static/square/haibao.png', iconWidth: 96, iconHeight: 96 },
-]
+ { key: 'hot', label: '人气王者', emoji: null, icon: '/static/square/rementubiao.png', iconWidth: 104, iconHeight: 104 },
+ { key: 'xingka', label: '潜力之星', emoji: null, icon: '/static/square/xingka.png', iconWidth: 80, iconHeight: 80 },
+ { key: 'baji', label: '新鲜上架', emoji: null, icon: '/static/square/baji.png', iconWidth: 80, iconHeight: 80 },
+ { key: 'haibao', label: '随机寻宝', emoji: null, icon: '/static/square/haibao.png', iconWidth: 96, iconHeight: 96 },]
diff --git a/frontend/pages/square/square.vue b/frontend/pages/square/square.vue
index 8cbfc76..fa15d89 100644
--- a/frontend/pages/square/square.vue
+++ b/frontend/pages/square/square.vue
@@ -8,6 +8,8 @@
:screenWidth="screenWidth"
:screenHeight="screenHeight"
:bannerBottom="bannerBottomPx"
+ :useMockData="USE_MOCK_DATA"
+ :category="activeContentTab"
@cardClick="handleCardClick"
class="fall-bg"
/>
@@ -68,6 +70,7 @@ import WaterfallGrid from './components/WaterfallGrid.vue'
import ContentTabs from './components/ContentTabs.vue'
import { clearSubStepProgress, shouldShowGuideStartModal } from '@/utils/guideConfig.js'
import { useBanner } from './composables/useBanner.js'
+import { USE_MOCK_DATA } from './config/mockData.js'
// ========== Store & User Info ==========
const store = useStore()
@@ -78,7 +81,6 @@ const currentStarId = ref(uni.getStorageSync('star_id') || null)
const activeContentTab = ref('hot')
const navExpanded = ref(false)
const showRankingModal = ref(false)
-const isDev = ref(false) // 开发模式,显示调试按钮
// ========== Screen Info ==========
const screenWidth = ref(375)
@@ -143,12 +145,6 @@ const handleTabChange = (newTab) => {
}
}
-const openDebugGrid = () => {
- uni.navigateTo({
- url: '/pages/square/debug-grid'
- })
-}
-
// ========== Tile Change Callback ==========
const handleTileChange = () => {}
@@ -282,25 +278,4 @@ onUnmounted(() => {
opacity: 1;
}
}
-
-.debug-btn {
- position: fixed;
- bottom: 200rpx;
- right: 20rpx;
- width: 100rpx;
- height: 100rpx;
- background: rgba(255, 0, 0, 0.8);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 999;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.3);
-}
-
-.debug-text {
- font-size: 24rpx;
- color: #ffffff;
- font-weight: bold;
-}
diff --git a/frontend/utils/api.js b/frontend/utils/api.js
index 37608d5..5863606 100644
--- a/frontend/utils/api.js
+++ b/frontend/utils/api.js
@@ -1,6 +1,6 @@
// API 基础配置
-const baseURL = 'http://101.132.250.62:8080'
-// const baseURL = 'http://192.168.110.60:8080'
+// const baseURL = 'http://101.132.250.62:8080'
+const baseURL = 'http://192.168.110.60:8080'
// const baseURL = 'http://localhost:8080'
// 是否使用模拟数据(开发调试时设为 true,后端API准备好后改为 false)
@@ -606,4 +606,23 @@ export function getMyLikedAssetsApi(page = 1, pageSize = 20) {
url: `/api/v1/me/liked-assets?page=${page}&page_size=${pageSize}`,
method: 'GET'
})
+}
+
+// ==================== 灵感瀑布相关接口 ====================
+
+// 获取灵感瀑布藏品列表
+export function getInspirationFlowApi(params) {
+ return request({
+ url: '/api/v1/inspiration-flow',
+ method: 'GET',
+ data: params
+ })
+}
+
+// 批量获取OSS预签名URL(用于读取目录下的图片)
+export function getBatchOssPresignedUrlsApi(files, expires = 3600, type = 'asset') {
+ return request({
+ url: `/api/v1/assets/oss/batch-presigned-urls?files=${encodeURIComponent(JSON.stringify(files))}&expires=${expires}&type=${type}`,
+ method: 'GET'
+ })
}
\ No newline at end of file