719 lines
21 KiB
Go
719 lines
21 KiB
Go
package controller
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"strconv"
|
||
"time"
|
||
|
||
"dubbo.apache.org/dubbo-go/v3/client"
|
||
"dubbo.apache.org/dubbo-go/v3/common/constant"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/topfans/backend/gateway/dto"
|
||
"github.com/topfans/backend/gateway/pkg/response"
|
||
"github.com/topfans/backend/pkg/logger"
|
||
pbCommon "github.com/topfans/backend/pkg/proto/common"
|
||
pbGallery "github.com/topfans/backend/pkg/proto/gallery"
|
||
pbSocial "github.com/topfans/backend/pkg/proto/social"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// GalleryController 展馆相关控制器
|
||
type GalleryController struct {
|
||
galleryService pbGallery.GalleryService
|
||
socialService pbSocial.SocialService
|
||
}
|
||
|
||
// NewGalleryController 创建展馆控制器
|
||
func NewGalleryController(galleryClient *client.Client, socialClient *client.Client) (*GalleryController, error) {
|
||
galleryService, err := pbGallery.NewGalleryService(galleryClient)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
socialService, err := pbSocial.NewSocialService(socialClient)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &GalleryController{
|
||
galleryService: galleryService,
|
||
socialService: socialService,
|
||
}, nil
|
||
}
|
||
|
||
// GetMyGallery 获取我的展馆
|
||
// @Summary 获取我的展馆
|
||
// @Description 获取当前用户的展馆信息
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Success 200 {object} response.Response{data=dto.GetMyGalleryResponseDTO}
|
||
// @Router /api/v1/galleries/me [get]
|
||
func (ctrl *GalleryController) GetMyGallery(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
|
||
}
|
||
|
||
// 创建带有附加信息的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.GetMyGallery(ctx, &pbGallery.GetMyGalleryRequest{})
|
||
if err != nil {
|
||
logger.Logger.Error("GetMyGallery RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Error(err),
|
||
)
|
||
// 解析 RPC 错误消息
|
||
_, msg := parseRPCError(err)
|
||
errorMsg := "获取展馆信息失败"
|
||
if msg != "" {
|
||
errorMsg += "," + msg
|
||
} else if resp != nil && resp.Base != nil && resp.Base.Message != "" {
|
||
errorMsg += "," + resp.Base.Message
|
||
} else {
|
||
errorMsg += ": " + err.Error()
|
||
}
|
||
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
|
||
galleryDTO := dto.ConvertGalleryData(resp.Data)
|
||
|
||
logger.Logger.Info("GetMyGallery success",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int32("slot_total", galleryDTO.SlotTotal),
|
||
)
|
||
|
||
response.Success(c, galleryDTO)
|
||
}
|
||
|
||
// GetUserGallery 获取他人展馆
|
||
// @Summary 获取他人展馆
|
||
// @Description 获取指定用户的展馆信息
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param target_uid path int true "用户ID"
|
||
// @Success 200 {object} response.Response{data=dto.GetUserGalleryResponseDTO}
|
||
// @Router /api/v1/galleries/{target_uid} [get]
|
||
func (ctrl *GalleryController) GetUserGallery(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
|
||
}
|
||
|
||
// 获取目标用户ID
|
||
targetUIDStr := c.Param("target_uid")
|
||
targetUID, err := strconv.ParseInt(targetUIDStr, 10, 64)
|
||
if err != nil {
|
||
response.Error(c, http.StatusBadRequest, "无效的用户ID")
|
||
return
|
||
}
|
||
|
||
// 创建带有附加信息的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.GetUserGallery(ctx, &pbGallery.GetUserGalleryRequest{
|
||
TargetUid: targetUID,
|
||
})
|
||
if err != nil {
|
||
logger.Logger.Error("GetUserGallery RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("target_uid", targetUID),
|
||
zap.Error(err),
|
||
)
|
||
// 解析 RPC 错误消息
|
||
_, msg := parseRPCError(err)
|
||
errorMsg := "获取展馆信息失败"
|
||
if msg != "" {
|
||
errorMsg += "," + msg
|
||
} else if resp != nil && resp.Base != nil && resp.Base.Message != "" {
|
||
errorMsg += "," + resp.Base.Message
|
||
} else {
|
||
errorMsg += ": " + err.Error()
|
||
}
|
||
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
|
||
galleryDTO := dto.ConvertGalleryDataToUser(resp.Data)
|
||
|
||
logger.Logger.Info("GetUserGallery success",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("target_uid", targetUID),
|
||
zap.Int32("slot_total", galleryDTO.SlotTotal),
|
||
)
|
||
|
||
response.Success(c, galleryDTO)
|
||
}
|
||
|
||
// PlaceAsset 在展位展示藏品
|
||
// @Summary 放置藏品
|
||
// @Description 在指定展位放置数字藏品进行展示
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param request body dto.PlaceAssetRequestDTO true "展位ID和资产ID"
|
||
// @Success 200 {object} response.Response
|
||
// @Router /api/v1/galleries/place [post]
|
||
func (ctrl *GalleryController) PlaceAsset(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
|
||
}
|
||
|
||
// 解析请求参数
|
||
var req dto.PlaceAssetRequestDTO
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
response.Error(c, http.StatusBadRequest, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 创建带有附加信息的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),
|
||
})
|
||
|
||
// 转换为Proto请求
|
||
pbReq := dto.ConvertPlaceAssetRequest(&req)
|
||
|
||
// 调用RPC服务
|
||
resp, err := ctrl.galleryService.PlaceAsset(ctx, pbReq)
|
||
if err != nil {
|
||
logger.Logger.Error("PlaceAsset RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("asset_id", req.AssetID),
|
||
zap.Int64("slot_id", req.SlotID),
|
||
zap.Error(err),
|
||
)
|
||
// 优先使用响应中的错误消息,如果没有则解析 RPC 错误
|
||
errorMsg := "放置资产失败"
|
||
if resp != nil && resp.Base != nil && resp.Base.Message != "" {
|
||
errorMsg += "," + resp.Base.Message
|
||
} else {
|
||
// 解析 RPC 错误消息(去掉 code_XX: 前缀)
|
||
_, msg := parseRPCError(err)
|
||
if msg != "" {
|
||
errorMsg += "," + msg
|
||
} else {
|
||
errorMsg += ": " + err.Error()
|
||
}
|
||
}
|
||
response.Error(c, http.StatusInternalServerError, errorMsg)
|
||
return
|
||
}
|
||
|
||
// 检查业务错误
|
||
if resp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
errorMsg := resp.Base.Message
|
||
if errorMsg == "" {
|
||
errorMsg = "未知错误"
|
||
}
|
||
response.Error(c, http.StatusBadRequest, errorMsg)
|
||
return
|
||
}
|
||
|
||
// 转换为DTO
|
||
placeDTO := dto.ConvertPlaceAssetData(resp.Data)
|
||
|
||
logger.Logger.Info("PlaceAsset success",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("asset_id", req.AssetID),
|
||
zap.Int64("slot_id", req.SlotID),
|
||
)
|
||
|
||
response.Success(c, placeDTO)
|
||
}
|
||
|
||
// UnlockSlot 解锁/购买新展位
|
||
// @Summary 解锁展位
|
||
// @Description 解锁或购买新的展位
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Success 200 {object} response.Response
|
||
// @Router /api/v1/galleries/slots_unlock [post]
|
||
func (ctrl *GalleryController) UnlockSlot(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
|
||
}
|
||
|
||
// 创建带有附加信息的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.UnlockSlot(ctx, &pbGallery.UnlockSlotRequest{})
|
||
if err != nil {
|
||
logger.Logger.Error("UnlockSlot RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Error(err),
|
||
)
|
||
// 解析 RPC 错误消息
|
||
_, msg := parseRPCError(err)
|
||
errorMsg := "解锁展位失败"
|
||
if msg != "" {
|
||
errorMsg += "," + msg
|
||
} else if resp != nil && resp.Base != nil && resp.Base.Message != "" {
|
||
errorMsg += "," + resp.Base.Message
|
||
} else {
|
||
errorMsg += ": " + err.Error()
|
||
}
|
||
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
|
||
unlockDTO := dto.ConvertUnlockSlotData(resp.Data)
|
||
|
||
logger.Logger.Info("UnlockSlot success",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int32("slot_total", unlockDTO.SlotTotal),
|
||
zap.Int64("crystal_balance", unlockDTO.CrystalBalance),
|
||
)
|
||
|
||
response.Success(c, unlockDTO)
|
||
}
|
||
|
||
// RemoveFromSlot 从展位移除资产(统一接口)
|
||
// @Summary 移除藏品
|
||
// @Description 从指定展位移除展示的藏品
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Param slot_id path int true "展位ID"
|
||
// @Success 200 {object} response.Response
|
||
// @Router /api/v1/galleries/slots/{slot_id}/asset [delete]
|
||
func (ctrl *GalleryController) RemoveFromSlot(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
|
||
}
|
||
|
||
// 获取展位ID
|
||
slotIDStr := c.Param("slot_id")
|
||
slotID, err := strconv.ParseInt(slotIDStr, 10, 64)
|
||
if err != nil {
|
||
response.Error(c, http.StatusBadRequest, "无效的展位ID")
|
||
return
|
||
}
|
||
|
||
// 创建带有附加信息的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.RemoveFromSlot(ctx, &pbGallery.RemoveFromSlotRequest{
|
||
SlotId: slotID,
|
||
})
|
||
if err != nil {
|
||
logger.Logger.Error("RemoveFromSlot RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("slot_id", slotID),
|
||
zap.Error(err),
|
||
)
|
||
// 优先使用响应中的错误消息,如果没有则解析 RPC 错误
|
||
errorMsg := "移除资产失败"
|
||
if resp != nil && resp.Base != nil && resp.Base.Message != "" {
|
||
errorMsg += "," + resp.Base.Message
|
||
} else {
|
||
// 解析 RPC 错误消息(去掉 code_XX: 前缀)
|
||
_, msg := parseRPCError(err)
|
||
if msg != "" {
|
||
errorMsg += "," + msg
|
||
} else {
|
||
errorMsg += ": " + err.Error()
|
||
}
|
||
}
|
||
response.Error(c, http.StatusInternalServerError, errorMsg)
|
||
return
|
||
}
|
||
|
||
// 检查业务错误
|
||
if resp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
errorMsg := resp.Base.Message
|
||
if errorMsg == "" {
|
||
errorMsg = "未知错误"
|
||
}
|
||
response.Error(c, http.StatusBadRequest, errorMsg)
|
||
return
|
||
}
|
||
|
||
logger.Logger.Info("RemoveFromSlot success",
|
||
zap.Any("user_id", userID),
|
||
zap.Any("star_id", starID),
|
||
zap.Int64("slot_id", slotID),
|
||
)
|
||
|
||
// 返回空对象表示成功
|
||
response.Success(c, gin.H{"message": "移除成功"})
|
||
}
|
||
|
||
// GetRandomGallery 获取随机玩家的展馆
|
||
// @Summary 获取随机展馆
|
||
// @Description 随机返回一个玩家的展馆信息,格式与 GET /api/v1/galleries/:target_uid 一致
|
||
// @Tags galleries
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security BearerAuth
|
||
// @Success 200 {object} response.Response{data=dto.GetUserGalleryResponseDTO}
|
||
// @Router /api/v1/galleries/random [get]
|
||
func (ctrl *GalleryController) GetRandomGallery(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
|
||
}
|
||
|
||
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),
|
||
})
|
||
|
||
// 1. 通过 SocialService 获取一个随机用户
|
||
randomResp, err := ctrl.socialService.GetRandomUsers(ctx, &pbSocial.GetRandomUsersRequest{Count: 1})
|
||
if err != nil {
|
||
logger.Logger.Error("GetRandomGallery: GetRandomUsers RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Error(err),
|
||
)
|
||
_, msg := parseRPCError(err)
|
||
errMsg := "获取随机用户失败"
|
||
if msg != "" {
|
||
errMsg += "," + msg
|
||
}
|
||
response.Error(c, http.StatusInternalServerError, errMsg)
|
||
return
|
||
}
|
||
|
||
if randomResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
response.Error(c, http.StatusBadRequest, randomResp.Base.Message)
|
||
return
|
||
}
|
||
|
||
if len(randomResp.Users) == 0 {
|
||
response.Error(c, http.StatusNotFound, "暂无其他用户")
|
||
return
|
||
}
|
||
|
||
targetUID := randomResp.Users[0].UserId
|
||
|
||
// 2. 用随机用户的 ID 获取其展馆信息
|
||
galleryResp, err := ctrl.galleryService.GetUserGallery(ctx, &pbGallery.GetUserGalleryRequest{
|
||
TargetUid: targetUID,
|
||
})
|
||
if err != nil {
|
||
logger.Logger.Error("GetRandomGallery: GetUserGallery RPC failed",
|
||
zap.Any("user_id", userID),
|
||
zap.Int64("target_uid", targetUID),
|
||
zap.Error(err),
|
||
)
|
||
_, msg := parseRPCError(err)
|
||
errMsg := "获取展馆信息失败"
|
||
if msg != "" {
|
||
errMsg += "," + msg
|
||
} else {
|
||
errMsg += ": " + err.Error()
|
||
}
|
||
response.Error(c, http.StatusInternalServerError, errMsg)
|
||
return
|
||
}
|
||
|
||
if galleryResp.Base.Code != pbCommon.StatusCode_STATUS_OK {
|
||
response.Error(c, http.StatusBadRequest, galleryResp.Base.Message)
|
||
return
|
||
}
|
||
|
||
galleryDTO := dto.ConvertGalleryDataToUser(galleryResp.Data)
|
||
|
||
logger.Logger.Info("GetRandomGallery success",
|
||
zap.Any("user_id", userID),
|
||
zap.Int64("target_uid", targetUID),
|
||
zap.Int32("slot_total", galleryDTO.SlotTotal),
|
||
)
|
||
|
||
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)
|
||
}
|
||
|
||
// 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)
|
||
} |