diff --git a/backend/proto/starbook.proto b/backend/proto/starbook.proto deleted file mode 100644 index 5954299..0000000 --- a/backend/proto/starbook.proto +++ /dev/null @@ -1,100 +0,0 @@ -syntax = "proto3"; - -package topfans.starbook; - -option go_package = "github.com/topfans/backend/pkg/proto/starbook;starbook"; - -import "proto/common.proto"; -import "google/api/annotations.proto"; - -// 星册服务 - 典藏/活动藏品体系重构 -service StarbookService { - // 星册首页 - rpc GetStarbookHome(GetStarbookHomeRequest) returns (GetStarbookHomeResponse) { - option (google.api.http) = { - get: "/api/v1/starbook/home" - }; - } - - // 藏品列表(分页) - rpc GetStarbookItems(GetStarbookItemsRequest) returns (GetStarbookItemsResponse) { - option (google.api.http) = { - get: "/api/v1/starbook/items" - }; - } -} - -// ==================== 星册首页 ==================== - -// 星册首页请求 -message GetStarbookHomeRequest { -} - -// 星册首页响应 -message GetStarbookHomeResponse { - topfans.common.BaseResponse base = 1; - StarbookHomeData data = 2; -} - -// 星册首页数据 -message StarbookHomeData { - repeated AssetGroup groups = 1; -} - -// 资产分组 -message AssetGroup { - string type = 1; // 'regular' / 'collection' / 'activity' - string category = 2; // 'castlove'(regular) / collection_category / activity_type - string category_name = 3; - // regular 使用 grades 分组;collection/activity 使用 flat items 列表 - repeated GradeSection grades = 4; // 仅 regular 时有效 - repeated AssetItem items = 5; // collection / activity 时有效 - int32 total_count = 6; - bool has_more = 7; -} - -// 等级分组(仅 regular 类型使用) -message GradeSection { - int32 grade = 1; // 等级:1/2/3/4/5... - repeated AssetItem items = 2; - int32 total_count = 3; - bool has_more = 4; -} - -// 资产项 -message AssetItem { - int64 asset_id = 1; - string name = 2; - string cover_url_signed = 3; // 预签名封面URL - int32 like_count = 4; - int64 created_at = 5; - string category = 6; // regular: 'castlove' / collection: category / activity: activity_type - int32 grade = 7; // 仅 regular 时有效(1/2/3...),其他类型为 0 - int32 display_status = 8; // 展示状态:0=待展示, 1=已展示 -} - -// ==================== 藏品列表(分页) ==================== - -// 藏品列表请求 -message GetStarbookItemsRequest { - string type = 1; // 'regular' / 'collection' / 'activity' - string category = 2; // regular 时固定传 'castlove' - int32 grade = 3; // 仅 regular 时有效(1/2/3...) - int32 page = 4; // 默认 1 - int32 page_size = 5; // 默认 20 -} - -// 藏品列表响应 -message GetStarbookItemsResponse { - topfans.common.BaseResponse base = 1; - AssetListData data = 2; -} - -// 藏品列表数据 -message AssetListData { - repeated AssetItem items = 1; - int64 total = 2; - int32 page = 3; - int32 page_size = 4; - bool has_more = 5; -} diff --git a/backend/services/starbookService/main.go b/backend/services/starbookService/main.go deleted file mode 100644 index edffda0..0000000 --- a/backend/services/starbookService/main.go +++ /dev/null @@ -1,203 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "os/signal" - "strconv" - "syscall" - - _ "dubbo.apache.org/dubbo-go/v3/imports" - "dubbo.apache.org/dubbo-go/v3/protocol" - "dubbo.apache.org/dubbo-go/v3/server" - - "github.com/topfans/backend/pkg/database" - "github.com/topfans/backend/pkg/health" - "github.com/topfans/backend/pkg/logger" - "github.com/topfans/backend/pkg/models" - pb "github.com/topfans/backend/pkg/proto/starbook" - assetRepo "github.com/topfans/backend/services/assetService/repository" - "github.com/topfans/backend/services/starbookService/provider" - "github.com/topfans/backend/services/starbookService/repository" - "github.com/topfans/backend/services/starbookService/service" -) - -var ( - port = flag.Int("port", getEnvInt("PORT", 20005), "Dubbo service port") - dbHost = flag.String("db-host", getEnv("DB_HOST", "localhost"), "Database host") - dbPort = flag.Int("db-port", getEnvInt("DB_PORT", 5432), "Database port") - dbUser = flag.String("db-user", getEnv("DB_USER", "postgres"), "Database user") - dbPassword = flag.String("db-password", getEnv("DB_PASSWORD", ""), "Database password") - dbName = flag.String("db-name", getEnv("DB_NAME", "top-fans"), "Database name") - healthHandler *health.Handler -) - -func getEnv(key, fallback string) string { - if v := os.Getenv(key); v != "" { - return v - } - return fallback -} - -func getEnvInt(key string, fallback int) int { - if v := os.Getenv(key); v != "" { - if n, err := strconv.Atoi(v); err == nil { - return n - } - } - return fallback -} - -func main() { - flag.Parse() - - // 初始化日志(必须在最前面) - env := os.Getenv("ENV") - if env == "" { - env = "development" - } - - if err := logger.Init(logger.Config{ - ServiceName: "starbook-service", - Environment: env, - LogLevel: os.Getenv("LOG_LEVEL"), - }); err != nil { - panic(fmt.Sprintf("Failed to initialize logger: %v", err)) - } - defer logger.Sync() - - logger.Sugar.Info("Starting Starbook Service...") - - // 初始化数据库 - if err := initDatabase(); err != nil { - logger.Sugar.Fatalf("Failed to initialize database: %v", err) - } - - // 自动迁移数据库表 - if err := autoMigrate(); err != nil { - logger.Sugar.Fatalf("Failed to migrate database: %v", err) - } - - // 初始化 Repository - registryRepo := repository.NewAssetRegistryRepository(database.GetDB()) - collectionRepo := repository.NewCollectionRepository(database.GetDB()) - activityRepo := repository.NewActivityAssetRepository(database.GetDB()) - assetRepository := assetRepo.NewAssetRepository(database.GetDB()) - - // 初始化 Service - starbookService := service.NewStarbookService( - database.GetDB(), - registryRepo, - assetRepository, - collectionRepo, - activityRepo, - ) - - // 初始化 Provider - starbookProvider := provider.NewStarbookProvider(starbookService) - - // 初始化 Dubbo-go 服务器 - if err := initDubboService(starbookProvider); err != nil { - logger.Sugar.Fatalf("Failed to initialize Dubbo service: %v", err) - } - - // 等待信号(优雅关闭) - logger.Sugar.Info("Starbook service started successfully. Press Ctrl+C to exit.") - gracefulShutdown() -} - -// initDatabase 初始化数据库连接 -func initDatabase() error { - config := database.Config{ - Host: *dbHost, - Port: *dbPort, - User: *dbUser, - Password: *dbPassword, - DBName: *dbName, - SSLMode: "disable", - TimeZone: "Asia/Shanghai", - } - - return database.Init(config) -} - -// autoMigrate 自动迁移数据库表 -func autoMigrate() error { - db := database.GetDB() - if db == nil { - return fmt.Errorf("database is not initialized") - } - - // 迁移星册相关的表 - tables := []interface{}{ - &models.CollectionAsset{}, - &models.ActivityAsset{}, - &models.AssetRegistry{}, - } - - for _, table := range tables { - if err := db.AutoMigrate(table); err != nil { - return fmt.Errorf("failed to migrate table: %w", err) - } - } - - logger.Sugar.Info("Database migration completed successfully") - return nil -} - -// initDubboService 初始化 Dubbo 服务 -func initDubboService(starbookProvider *provider.StarbookProvider) error { - // 启动健康检查 HTTP 服务器 - healthPort := *port + 1000 // e.g., 20005 -> 21005 - healthHandler = health.NewHandler("starbook-service", healthPort) - healthHandler.Start() - - // 创建 Dubbo Server - srv, err := server.NewServer( - server.WithServerProtocol( - protocol.WithPort(*port), - protocol.WithTriple(), - ), - ) - if err != nil { - return fmt.Errorf("failed to create Dubbo server: %w", err) - } - - // 注册服务 - if err := pb.RegisterStarbookServiceHandler(srv, starbookProvider); err != nil { - return fmt.Errorf("failed to register StarbookService handler: %w", err) - } - - logger.Sugar.Infof("Dubbo-go provider registered successfully, service: topfans.starbook.StarbookService, port: %d", *port) - - // 在后台启动 Dubbo 服务器 - go func() { - if err := srv.Serve(); err != nil { - logger.Sugar.Fatalf("Failed to serve Dubbo: %v", err) - } - }() - - return nil -} - -// gracefulShutdown 优雅关闭 -func gracefulShutdown() { - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - - logger.Sugar.Info("Shutting down Starbook Service...") - - // 关闭健康检查服务器 - if healthHandler != nil { - healthHandler.Stop() - } - - // 关闭数据库连接 - if err := database.Close(); err != nil { - logger.Sugar.Errorf("Error closing database: %v", err) - } - - logger.Sugar.Info("Starbook Service stopped") -} diff --git a/backend/services/starbookService/provider/starbook_provider.go b/backend/services/starbookService/provider/starbook_provider.go deleted file mode 100644 index 74c17aa..0000000 --- a/backend/services/starbookService/provider/starbook_provider.go +++ /dev/null @@ -1,220 +0,0 @@ -package provider - -import ( - "context" - "fmt" - "strconv" - "time" - - "dubbo.apache.org/dubbo-go/v3/common/constant" - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/logger" - pb "github.com/topfans/backend/pkg/proto/starbook" - pbCommon "github.com/topfans/backend/pkg/proto/common" - "github.com/topfans/backend/services/starbookService/service" - "go.uber.org/zap" - "google.golang.org/grpc/codes" -) - -// StarbookProvider 星册服务Provider实现 -// 实现 Triple 协议生成的 StarbookServiceHandler 接口 -type StarbookProvider struct { - starbookService service.StarbookService -} - -// 确保 StarbookProvider 实现了 StarbookServiceHandler 接口 -var _ pb.StarbookServiceHandler = (*StarbookProvider)(nil) - -// NewStarbookProvider 创建星册服务Provider实例 -func NewStarbookProvider(starbookService service.StarbookService) *StarbookProvider { - return &StarbookProvider{ - starbookService: starbookService, - } -} - -// GetStarbookHome 获取星册首页 -func (p *StarbookProvider) GetStarbookHome(ctx context.Context, req *pb.GetStarbookHomeRequest) (*pb.GetStarbookHomeResponse, error) { - userID, starID, err := extractUserInfoFromDubboAttachments(ctx) - if err != nil { - return &pb.GetStarbookHomeResponse{ - Base: &pbCommon.BaseResponse{ - Code: uint32(codes.Unauthenticated), - Message: "user authentication required", - Timestamp: 0, - }, - }, err - } - - resp, err := p.starbookService.GetStarbookHome(userID, starID) - if err != nil { - logger.Logger.Error("GetStarbookHome failed", - zap.Error(err), - ) - return &pb.GetStarbookHomeResponse{ - Base: &pbCommon.BaseResponse{ - Code: uint32(toStatusCode(err)), - Message: err.Error(), - Timestamp: time.Now().UnixMilli(), - }, - }, err - } - - return resp, nil -} - -// GetStarbookItems 获取星册藏品列表 -func (p *StarbookProvider) GetStarbookItems(ctx context.Context, req *pb.GetStarbookItemsRequest) (*pb.GetStarbookItemsResponse, error) { - userID, starID, err := extractUserInfoFromDubboAttachments(ctx) - if err != nil { - return &pb.GetStarbookItemsResponse{ - Base: &pbCommon.BaseResponse{ - Code: uint32(codes.Unauthenticated), - Message: "user authentication required", - Timestamp: 0, - }, - }, err - } - - resp, err := p.starbookService.GetStarbookItems(req, userID, starID) - if err != nil { - logger.Logger.Error("GetStarbookItems failed", - zap.Error(err), - ) - return &pb.GetStarbookItemsResponse{ - Base: &pbCommon.BaseResponse{ - Code: uint32(toStatusCode(err)), - Message: err.Error(), - Timestamp: time.Now().UnixMilli(), - }, - }, err - } - - return resp, nil -} - -// extractUserInfoFromDubboAttachments 从 Dubbo attachments 中提取用户信息 -// 网关调用:网关已验证 Token 并将 user_id 和 star_id 通过 attachments 传递 -func extractUserInfoFromDubboAttachments(ctx context.Context) (int64, int64, error) { - logger.Logger.Info("=== extractUserInfoFromDubboAttachments called ===") - - // 使用 constant.AttachmentKey 获取 Dubbo attachments - attachments := ctx.Value(constant.AttachmentKey) - logger.Logger.Info("ctx.Value(constant.AttachmentKey) result", - zap.Any("attachments", attachments), - zap.String("type", fmt.Sprintf("%T", attachments)), - ) - - if attachments != nil { - logger.Logger.Info("Attachments found in context") - - if attMap, ok := attachments.(map[string]interface{}); ok { - logger.Logger.Info("Attachments is map[string]interface{}", - zap.Int("map_size", len(attMap))) - userID, starID := extractUserInfoFromMap(attMap) - if userID > 0 && starID > 0 { - logger.Logger.Info("Successfully extracted user info", - zap.Int64("user_id", userID), - zap.Int64("star_id", starID), - ) - return userID, starID, nil - } - logger.Logger.Warn("Extracted zero user_id or star_id", - zap.Int64("user_id", userID), - zap.Int64("star_id", starID), - ) - } else { - logger.Logger.Warn("Attachments is not map[string]interface{}", - zap.String("actual_type", fmt.Sprintf("%T", attachments)), - zap.Any("value", attachments), - ) - } - } else { - logger.Logger.Warn("No attachments found in context") - // 尝试打印所有 context 的值 - logger.Logger.Warn("Context type", zap.String("type", fmt.Sprintf("%T", ctx))) - } - - return 0, 0, fmt.Errorf("user info not found in Dubbo attachments (expected user_id and star_id from gateway)") -} - -// getContextKeys 获取 context 中所有的 key -func getContextKeys(ctx context.Context) []string { - keys := make([]string, 0) - // 直接打印 ctx 类型 - logger.Logger.Debug("Context type", zap.String("type", fmt.Sprintf("%T", ctx))) - return keys -} - -// getContextValues 遍历 context 中的一些已知值 -func getContextValues(ctx context.Context) map[string]interface{} { - result := make(map[string]interface{}) - // 检查 constant.AttachmentKey - if v := ctx.Value(constant.AttachmentKey); v != nil { - result["AttachmentKey"] = v - } - return result -} - -// extractUserInfoFromMap 从 map 中提取 user_id 和 star_id -// 支持多种类型:int64, float64, string -func extractUserInfoFromMap(attMap map[string]interface{}) (int64, int64) { - var userID, starID int64 - - // 打印所有 key 和 value - for k, v := range attMap { - logger.Logger.Debug("Attachment map entry", - zap.String("key", k), - zap.Any("value", v), - zap.String("type", fmt.Sprintf("%T", v)), - ) - } - - // 提取 user_id - if v, ok := attMap["user_id"]; ok { - userID = parseIntValue(v) - } - - // 提取 star_id - if v, ok := attMap["star_id"]; ok { - starID = parseIntValue(v) - } - - return userID, starID -} - -// parseIntValue 解析不同类型的整数值 -func parseIntValue(v interface{}) int64 { - switch val := v.(type) { - case int64: - return val - case int: - return int64(val) - case float64: - return int64(val) - case string: - if i, err := strconv.ParseInt(val, 10, 64); err == nil { - return i - } - case []string: - if len(val) > 0 { - if i, err := strconv.ParseInt(val[0], 10, 64); err == nil { - return i - } - } - case []interface{}: - if len(val) > 0 { - if s, ok := val[0].(string); ok { - if i, err := strconv.ParseInt(s, 10, 64); err == nil { - return i - } - } - } - } - return 0 -} - -// toStatusCode 将错误转换为 google.rpc.Code -// 包装 appErrors.ToGRPCCode 以便该 provider 内调用更简洁 -func toStatusCode(err error) codes.Code { - return appErrors.ToGRPCCode(err) -} diff --git a/backend/services/starbookService/repository/activity_asset_repository.go b/backend/services/starbookService/repository/activity_asset_repository.go deleted file mode 100644 index d0cc3cf..0000000 --- a/backend/services/starbookService/repository/activity_asset_repository.go +++ /dev/null @@ -1,247 +0,0 @@ -package repository - -import ( - "errors" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - "gorm.io/gorm" -) - -// ActivityAssetRepository 活动藏品Repository接口 -type ActivityAssetRepository interface { - // Create 创建活动藏品 - Create(asset *models.ActivityAsset) error - - // GetByID 根据ID查询 - GetByID(id int64) (*models.ActivityAsset, error) - - // GetByAssetID 根据asset_id查询 - GetByAssetID(assetID int64) (*models.ActivityAsset, error) - - // GetByAssetIDs 批量查询 - GetByAssetIDs(assetIDs []int64) ([]*models.ActivityAsset, error) - - // GetByOwner 查询用户的活动藏品列表 - GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.ActivityAsset, error) - - // GetByOwnerAndActivityType 查询用户指定活动类型的活动藏品 - GetByOwnerAndActivityType(ownerUID, starID int64, activityType string, limit, offset int) ([]*models.ActivityAsset, error) - - // GetByOwnerAndActivityID 查询用户指定活动的活动藏品 - GetByOwnerAndActivityID(ownerUID, starID int64, activityID int64, limit, offset int) ([]*models.ActivityAsset, error) - - // CountByOwner 统计用户的活动藏品数量 - CountByOwner(ownerUID, starID int64) (int64, error) - - // CountByOwnerAndActivityType 统计用户指定活动类型的活动藏品数量 - CountByOwnerAndActivityType(ownerUID, starID int64, activityType string) (int64, error) - - // UpdateLikeCount 更新点赞数 - UpdateLikeCount(id int64, likeCount int32) error - - // IncrementLikeCount 增加点赞数 - IncrementLikeCount(id int64) error - - // DecrementLikeCount 减少点赞数 - DecrementLikeCount(id int64) error -} - -// activityAssetRepository 活动藏品Repository实现 -type activityAssetRepository struct { - db *gorm.DB -} - -// NewActivityAssetRepository 创建活动藏品Repository实例 -func NewActivityAssetRepository(db *gorm.DB) ActivityAssetRepository { - return &activityAssetRepository{db: db} -} - -// Create 创建活动藏品 -func (r *activityAssetRepository) Create(asset *models.ActivityAsset) error { - if asset == nil { - return errors.New("activity asset cannot be nil") - } - if asset.OwnerUID <= 0 { - return errors.New("owner_uid must be greater than 0") - } - if asset.StarID <= 0 { - return errors.New("star_id must be greater than 0") - } - return r.db.Create(asset).Error -} - -// GetByID 根据ID查询 -func (r *activityAssetRepository) GetByID(id int64) (*models.ActivityAsset, error) { - if id <= 0 { - return nil, errors.New("id must be greater than 0") - } - var asset models.ActivityAsset - if err := r.db.Where("id = ?", id).First(&asset).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrActivityAssetNotFound - } - return nil, err - } - return &asset, nil -} - -// GetByAssetID 根据asset_id查询 -func (r *activityAssetRepository) GetByAssetID(assetID int64) (*models.ActivityAsset, error) { - if assetID <= 0 { - return nil, errors.New("asset_id must be greater than 0") - } - var asset models.ActivityAsset - if err := r.db.Where("asset_id = ?", assetID).First(&asset).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrActivityAssetNotFound - } - return nil, err - } -return &asset, nil -} - -// GetByAssetIDs 批量查询 -func (r *activityAssetRepository) GetByAssetIDs(assetIDs []int64) ([]*models.ActivityAsset, error) { - if len(assetIDs) == 0 { - return []*models.ActivityAsset{}, nil - } - var assets []*models.ActivityAsset - if err := r.db.Where("asset_id IN ?", assetIDs).Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// GetByOwner 查询用户的活动藏品列表 -func (r *activityAssetRepository) GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.ActivityAsset, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var assets []*models.ActivityAsset - query := r.db.Where("owner_uid = ? AND star_id = ?", ownerUID, starID). - Order("created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// GetByOwnerAndActivityType 查询用户指定活动类型的活动藏品 -func (r *activityAssetRepository) GetByOwnerAndActivityType(ownerUID, starID int64, activityType string, limit, offset int) ([]*models.ActivityAsset, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var assets []*models.ActivityAsset - query := r.db.Where("owner_uid = ? AND star_id = ? AND activity_type = ?", ownerUID, starID, activityType). - Order("created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// GetByOwnerAndActivityID 查询用户指定活动的活动藏品 -func (r *activityAssetRepository) GetByOwnerAndActivityID(ownerUID, starID int64, activityID int64, limit, offset int) ([]*models.ActivityAsset, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var assets []*models.ActivityAsset - query := r.db.Where("owner_uid = ? AND star_id = ? AND activity_id = ?", ownerUID, starID, activityID). - Order("created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// CountByOwner 统计用户的活动藏品数量 -func (r *activityAssetRepository) CountByOwner(ownerUID, starID int64) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.ActivityAsset{}). - Where("owner_uid = ? AND star_id = ?", ownerUID, starID). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndActivityType 统计用户指定活动类型的活动藏品数量 -func (r *activityAssetRepository) CountByOwnerAndActivityType(ownerUID, starID int64, activityType string) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.ActivityAsset{}). - Where("owner_uid = ? AND star_id = ? AND activity_type = ?", ownerUID, starID, activityType). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// UpdateLikeCount 更新点赞数 -func (r *activityAssetRepository) UpdateLikeCount(id int64, likeCount int32) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.ActivityAsset{}). - Where("id = ?", id). - Update("like_count", likeCount).Error -} - -// IncrementLikeCount 增加点赞数 -func (r *activityAssetRepository) IncrementLikeCount(id int64) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.ActivityAsset{}). - Where("id = ?", id). - UpdateColumn("like_count", gorm.Expr("like_count + ?", 1)).Error -} - -// DecrementLikeCount 减少点赞数 -func (r *activityAssetRepository) DecrementLikeCount(id int64) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.ActivityAsset{}). - Where("id = ? AND like_count > ?", id, 0). - UpdateColumn("like_count", gorm.Expr("like_count - ?", 1)).Error -} diff --git a/backend/services/starbookService/repository/asset_registry_repository.go b/backend/services/starbookService/repository/asset_registry_repository.go deleted file mode 100644 index 70dfd05..0000000 --- a/backend/services/starbookService/repository/asset_registry_repository.go +++ /dev/null @@ -1,387 +0,0 @@ -package repository - -import ( - "errors" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - "gorm.io/gorm" -) - -// AssetRegistryRepository 资产统一索引Repository接口 -type AssetRegistryRepository interface { - // Create 创建索引记录 - Create(registry *models.AssetRegistry) error - - // GetByID 根据ID查询 - GetByID(id int64) (*models.AssetRegistry, error) - - // GetByAssetID 根据asset_id查询 - GetByAssetID(assetID int64) (*models.AssetRegistry, error) - - // GetByAssetTypeAndID 根据类型和asset_id查询 - GetByAssetTypeAndID(assetType string, assetID int64) (*models.AssetRegistry, error) - - // GetByOwner 查询用户的所有索引记录 - GetByOwner(ownerUID, starID int64) ([]*models.AssetRegistry, error) - - // GetByOwnerAndType 查询用户指定类型的索引记录 - GetByOwnerAndType(ownerUID, starID int64, assetType string, limit, offset int) ([]*models.AssetRegistry, error) - - // GetByOwnerAndTypeAndGrade 查询用户指定类型和等级的索引记录 - GetByOwnerAndTypeAndGrade(ownerUID, starID int64, assetType string, grade int32, limit, offset int) ([]*models.AssetRegistry, error) - - // GetByOwnerAndTypeAndCategory 查询用户指定类型和分类的索引记录 - GetByOwnerAndTypeAndCategory(ownerUID, starID int64, assetType string, category string, limit, offset int) ([]*models.AssetRegistry, error) - - // GetByOwnerAndTypeAndActivity 查询用户指定类型和活动的索引记录 - GetByOwnerAndTypeAndActivity(ownerUID, starID int64, assetType string, activityID int64, limit, offset int) ([]*models.AssetRegistry, error) - - // CountByOwner 统计用户的索引记录数量 - CountByOwner(ownerUID, starID int64) (int64, error) - - // CountByOwnerAndType 统计用户指定类型的索引记录数量 - CountByOwnerAndType(ownerUID, starID int64, assetType string) (int64, error) - - // CountByOwnerAndTypeAndGrade 统计用户指定类型和等级的索引记录数量 - CountByOwnerAndTypeAndGrade(ownerUID, starID int64, assetType string, grade int32) (int64, error) - - // CountByOwnerAndTypeAndCategory 统计用户指定类型和分类的索引记录数量 - CountByOwnerAndTypeAndCategory(ownerUID, starID int64, assetType string, category string) (int64, error) - - // CountByOwnerAndTypeAndActivity 统计用户指定类型和活动的索引记录数量 - CountByOwnerAndTypeAndActivity(ownerUID, starID int64, assetType string, activityID int64) (int64, error) - - // UpdateLikeCount 更新点赞数 - UpdateLikeCount(assetID int64, likeCount int32) error - - // UpdateGrade 更新等级 - UpdateGrade(assetID int64, grade int32) error - - // Delete 删除索引记录 - Delete(assetID int64) error - - // DeleteByAssetType 删除指定类型的索引记录 - DeleteByAssetType(assetType string, assetID int64) error -} - -// assetRegistryRepository 资产统一索引Repository实现 -type assetRegistryRepository struct { - db *gorm.DB -} - -// NewAssetRegistryRepository 创建资产统一索引Repository实例 -func NewAssetRegistryRepository(db *gorm.DB) AssetRegistryRepository { - return &assetRegistryRepository{db: db} -} - -// Create 创建索引记录 -func (r *assetRegistryRepository) Create(registry *models.AssetRegistry) error { - if registry == nil { - return errors.New("registry cannot be nil") - } - if registry.OwnerUID <= 0 { - return errors.New("owner_uid must be greater than 0") - } - if registry.StarID <= 0 { - return errors.New("star_id must be greater than 0") - } - return r.db.Create(registry).Error -} - -// GetByID 根据ID查询 -func (r *assetRegistryRepository) GetByID(id int64) (*models.AssetRegistry, error) { - if id <= 0 { - return nil, errors.New("id must be greater than 0") - } - var registry models.AssetRegistry - if err := r.db.Where("id = ?", id).First(®istry).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrAssetRegistryNotFound - } - return nil, err - } - return ®istry, nil -} - -// GetByAssetID 根据asset_id查询 -func (r *assetRegistryRepository) GetByAssetID(assetID int64) (*models.AssetRegistry, error) { - if assetID <= 0 { - return nil, errors.New("asset_id must be greater than 0") - } - var registry models.AssetRegistry - if err := r.db.Where("asset_id = ?", assetID).First(®istry).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrAssetRegistryNotFound - } - return nil, err - } - return ®istry, nil -} - -// GetByAssetTypeAndID 根据类型和asset_id查询 -func (r *assetRegistryRepository) GetByAssetTypeAndID(assetType string, assetID int64) (*models.AssetRegistry, error) { - if assetType == "" { - return nil, errors.New("asset_type must not be empty") - } - if assetID <= 0 { - return nil, errors.New("asset_id must be greater than 0") - } - var registry models.AssetRegistry - if err := r.db.Where("asset_type = ? AND asset_id = ?", assetType, assetID).First(®istry).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrAssetRegistryNotFound - } - return nil, err - } - return ®istry, nil -} - -// GetByOwner 查询用户的所有索引记录 -func (r *assetRegistryRepository) GetByOwner(ownerUID, starID int64) ([]*models.AssetRegistry, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var registries []*models.AssetRegistry - if err := r.db. - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ?", ownerUID, starID). - Order("asset_registry.created_at DESC"). - Find(®istries).Error; err != nil { - return nil, err - } - return registries, nil -} - -// GetByOwnerAndType 查询用户指定类型的索引记录 -func (r *assetRegistryRepository) GetByOwnerAndType(ownerUID, starID int64, assetType string, limit, offset int) ([]*models.AssetRegistry, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var registries []*models.AssetRegistry - query := r.db. - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ?", ownerUID, starID, assetType). - Order("asset_registry.created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(®istries).Error; err != nil { - return nil, err - } - return registries, nil -} - -// GetByOwnerAndTypeAndGrade 查询用户指定类型和等级的索引记录 -func (r *assetRegistryRepository) GetByOwnerAndTypeAndGrade(ownerUID, starID int64, assetType string, grade int32, limit, offset int) ([]*models.AssetRegistry, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var registries []*models.AssetRegistry - query := r.db. - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.grade = ?", ownerUID, starID, assetType, grade). - Order("asset_registry.created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(®istries).Error; err != nil { - return nil, err - } - return registries, nil -} - -// GetByOwnerAndTypeAndCategory 查询用户指定类型和分类的索引记录 -func (r *assetRegistryRepository) GetByOwnerAndTypeAndCategory(ownerUID, starID int64, assetType string, category string, limit, offset int) ([]*models.AssetRegistry, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var registries []*models.AssetRegistry - query := r.db. - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.collection_category = ?", ownerUID, starID, assetType, category). - Order("asset_registry.created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(®istries).Error; err != nil { - return nil, err - } - return registries, nil -} - -// GetByOwnerAndTypeAndActivity 查询用户指定类型和活动的索引记录 -func (r *assetRegistryRepository) GetByOwnerAndTypeAndActivity(ownerUID, starID int64, assetType string, activityID int64, limit, offset int) ([]*models.AssetRegistry, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var registries []*models.AssetRegistry - query := r.db. - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.activity_id = ?", ownerUID, starID, assetType, activityID). - Order("asset_registry.created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(®istries).Error; err != nil { - return nil, err - } - return registries, nil -} - -// CountByOwner 统计用户的索引记录数量 -func (r *assetRegistryRepository) CountByOwner(ownerUID, starID int64) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.AssetRegistry{}). - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ?", ownerUID, starID). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndType 统计用户指定类型的索引记录数量 -func (r *assetRegistryRepository) CountByOwnerAndType(ownerUID, starID int64, assetType string) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.AssetRegistry{}). - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ?", ownerUID, starID, assetType). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndTypeAndGrade 统计用户指定类型和等级的索引记录数量 -func (r *assetRegistryRepository) CountByOwnerAndTypeAndGrade(ownerUID, starID int64, assetType string, grade int32) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.AssetRegistry{}). - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.grade = ?", ownerUID, starID, assetType, grade). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndTypeAndCategory 统计用户指定类型和分类的索引记录数量 -func (r *assetRegistryRepository) CountByOwnerAndTypeAndCategory(ownerUID, starID int64, assetType string, category string) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.AssetRegistry{}). - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.collection_category = ?", ownerUID, starID, assetType, category). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndTypeAndActivity 统计用户指定类型和活动的索引记录数量 -func (r *assetRegistryRepository) CountByOwnerAndTypeAndActivity(ownerUID, starID int64, assetType string, activityID int64) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.AssetRegistry{}). - Joins("JOIN assets ON assets.id = asset_registry.asset_id AND assets.deleted_at IS NULL"). - Where("asset_registry.owner_uid = ? AND asset_registry.star_id = ? AND asset_registry.asset_type = ? AND asset_registry.activity_id = ?", ownerUID, starID, assetType, activityID). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// UpdateLikeCount 更新点赞数 -func (r *assetRegistryRepository) UpdateLikeCount(assetID int64, likeCount int32) error { - if assetID <= 0 { - return errors.New("asset_id must be greater than 0") - } - return r.db.Model(&models.AssetRegistry{}). - Where("asset_id = ?", assetID). - Update("like_count", likeCount).Error -} - -// UpdateGrade 更新等级 -func (r *assetRegistryRepository) UpdateGrade(assetID int64, grade int32) error { - if assetID <= 0 { - return errors.New("asset_id must be greater than 0") - } - return r.db.Model(&models.AssetRegistry{}). - Where("asset_id = ?", assetID). - Update("grade", grade).Error -} - -// Delete 删除索引记录 -func (r *assetRegistryRepository) Delete(assetID int64) error { - if assetID <= 0 { - return errors.New("asset_id must be greater than 0") - } - return r.db.Where("asset_id = ?", assetID).Delete(&models.AssetRegistry{}).Error -} - -// DeleteByAssetType 删除指定类型的索引记录 -func (r *assetRegistryRepository) DeleteByAssetType(assetType string, assetID int64) error { - if assetType == "" { - return errors.New("asset_type must not be empty") - } - if assetID <= 0 { - return errors.New("asset_id must be greater than 0") - } - return r.db.Where("asset_type = ? AND asset_id = ?", assetType, assetID). - Delete(&models.AssetRegistry{}).Error -} diff --git a/backend/services/starbookService/repository/collection_repository.go b/backend/services/starbookService/repository/collection_repository.go deleted file mode 100644 index 1c38466..0000000 --- a/backend/services/starbookService/repository/collection_repository.go +++ /dev/null @@ -1,221 +0,0 @@ -package repository - -import ( - "errors" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - "gorm.io/gorm" -) - -// CollectionRepository 典藏藏品Repository接口 -type CollectionRepository interface { - // Create 创建典藏藏品 - Create(asset *models.CollectionAsset) error - - // GetByID 根据ID查询 - GetByID(id int64) (*models.CollectionAsset, error) - - // GetByAssetID 根据asset_id查询 - GetByAssetID(assetID int64) (*models.CollectionAsset, error) - - // GetByAssetIDs 批量查询 - GetByAssetIDs(assetIDs []int64) ([]*models.CollectionAsset, error) - - // GetByOwner 查询用户的典藏藏品列表 - GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.CollectionAsset, error) - - // GetByOwnerAndCategory 查询用户指定分类的典藏藏品 - GetByOwnerAndCategory(ownerUID, starID int64, category string, limit, offset int) ([]*models.CollectionAsset, error) - - // CountByOwner 统计用户的典藏藏品数量 - CountByOwner(ownerUID, starID int64) (int64, error) - - // CountByOwnerAndCategory 统计用户指定分类的典藏藏品数量 - CountByOwnerAndCategory(ownerUID, starID int64, category string) (int64, error) - - // UpdateLikeCount 更新点赞数 - UpdateLikeCount(id int64, likeCount int32) error - - // IncrementLikeCount 增加点赞数 - IncrementLikeCount(id int64) error - - // DecrementLikeCount 减少点赞数 - DecrementLikeCount(id int64) error -} - -// collectionRepository 典藏藏品Repository实现 -type collectionRepository struct { - db *gorm.DB -} - -// NewCollectionRepository 创建典藏藏品Repository实例 -func NewCollectionRepository(db *gorm.DB) CollectionRepository { - return &collectionRepository{db: db} -} - -// Create 创建典藏藏品 -func (r *collectionRepository) Create(asset *models.CollectionAsset) error { - if asset == nil { - return errors.New("collection asset cannot be nil") - } - if asset.OwnerUID <= 0 { - return errors.New("owner_uid must be greater than 0") - } - if asset.StarID <= 0 { - return errors.New("star_id must be greater than 0") - } - return r.db.Create(asset).Error -} - -// GetByID 根据ID查询 -func (r *collectionRepository) GetByID(id int64) (*models.CollectionAsset, error) { - if id <= 0 { - return nil, errors.New("id must be greater than 0") - } - var asset models.CollectionAsset - if err := r.db.Where("id = ?", id).First(&asset).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrCollectionAssetNotFound - } - return nil, err - } - return &asset, nil -} - -// GetByAssetID 根据asset_id查询 -func (r *collectionRepository) GetByAssetID(assetID int64) (*models.CollectionAsset, error) { - if assetID <= 0 { - return nil, errors.New("asset_id must be greater than 0") - } - var asset models.CollectionAsset - if err := r.db.Where("asset_id = ?", assetID).First(&asset).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, appErrors.ErrCollectionAssetNotFound - } - return nil, err - } -return &asset, nil -} - -// GetByAssetIDs 批量查询 -func (r *collectionRepository) GetByAssetIDs(assetIDs []int64) ([]*models.CollectionAsset, error) { - if len(assetIDs) == 0 { - return []*models.CollectionAsset{}, nil - } - var assets []*models.CollectionAsset - if err := r.db.Where("asset_id IN ?", assetIDs).Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// GetByOwner 查询用户的典藏藏品列表 -func (r *collectionRepository) GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.CollectionAsset, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var assets []*models.CollectionAsset - query := r.db.Where("owner_uid = ? AND star_id = ?", ownerUID, starID). - Order("created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// GetByOwnerAndCategory 查询用户指定分类的典藏藏品 -func (r *collectionRepository) GetByOwnerAndCategory(ownerUID, starID int64, category string, limit, offset int) ([]*models.CollectionAsset, error) { - if ownerUID <= 0 { - return nil, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return nil, errors.New("star_id must be greater than 0") - } - var assets []*models.CollectionAsset - query := r.db.Where("owner_uid = ? AND star_id = ? AND category = ?", ownerUID, starID, category). - Order("created_at DESC") - if limit > 0 { - query = query.Limit(limit) - } - if offset > 0 { - query = query.Offset(offset) - } - if err := query.Find(&assets).Error; err != nil { - return nil, err - } - return assets, nil -} - -// CountByOwner 统计用户的典藏藏品数量 -func (r *collectionRepository) CountByOwner(ownerUID, starID int64) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.CollectionAsset{}). - Where("owner_uid = ? AND star_id = ?", ownerUID, starID). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// CountByOwnerAndCategory 统计用户指定分类的典藏藏品数量 -func (r *collectionRepository) CountByOwnerAndCategory(ownerUID, starID int64, category string) (int64, error) { - if ownerUID <= 0 { - return 0, errors.New("owner_uid must be greater than 0") - } - if starID <= 0 { - return 0, errors.New("star_id must be greater than 0") - } - var count int64 - if err := r.db.Model(&models.CollectionAsset{}). - Where("owner_uid = ? AND star_id = ? AND category = ?", ownerUID, starID, category). - Count(&count).Error; err != nil { - return 0, err - } - return count, nil -} - -// UpdateLikeCount 更新点赞数 -func (r *collectionRepository) UpdateLikeCount(id int64, likeCount int32) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.CollectionAsset{}). - Where("id = ?", id). - Update("like_count", likeCount).Error -} - -// IncrementLikeCount 增加点赞数 -func (r *collectionRepository) IncrementLikeCount(id int64) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.CollectionAsset{}). - Where("id = ?", id). - UpdateColumn("like_count", gorm.Expr("like_count + ?", 1)).Error -} - -// DecrementLikeCount 减少点赞数 -func (r *collectionRepository) DecrementLikeCount(id int64) error { - if id <= 0 { - return errors.New("id must be greater than 0") - } - return r.db.Model(&models.CollectionAsset{}). - Where("id = ? AND like_count > ?", id, 0). - UpdateColumn("like_count", gorm.Expr("like_count - ?", 1)).Error -} diff --git a/backend/services/starbookService/service/activity_asset_service.go b/backend/services/starbookService/service/activity_asset_service.go deleted file mode 100644 index 31c9c42..0000000 --- a/backend/services/starbookService/service/activity_asset_service.go +++ /dev/null @@ -1,132 +0,0 @@ -package service - -import ( - "time" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - "github.com/topfans/backend/services/starbookService/repository" -) - -// ActivityAssetService 活动藏品服务接口 -type ActivityAssetService interface { - // Create 创建活动藏品 - Create(asset *models.ActivityAsset) error - - // GetByID 根据ID获取 - GetByID(id int64) (*models.ActivityAsset, error) - - // GetByAssetID 根据asset_id获取 - GetByAssetID(assetID int64) (*models.ActivityAsset, error) - - // GetByOwner 获取用户的活动藏品 - GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.ActivityAsset, error) - - // GetByOwnerAndActivityType 获取用户指定活动类型的活动藏品 - GetByOwnerAndActivityType(ownerUID, starID int64, activityType string, limit, offset int) ([]*models.ActivityAsset, error) - - // GetByOwnerAndActivityID 获取用户指定活动的活动藏品 - GetByOwnerAndActivityID(ownerUID, starID int64, activityID int64, limit, offset int) ([]*models.ActivityAsset, error) - - // CountByOwner 统计用户的活动藏品数量 - CountByOwner(ownerUID, starID int64) (int64, error) - - // CountByOwnerAndActivityType 统计用户指定活动类型的活动藏品数量 - CountByOwnerAndActivityType(ownerUID, starID int64, activityType string) (int64, error) - - // IncrementLikeCount 增加点赞数 - IncrementLikeCount(id int64) error - - // DecrementLikeCount 减少点赞数 - DecrementLikeCount(id int64) error -} - -// activityAssetService 活动藏品服务实现 -type activityAssetService struct { - activityRepo repository.ActivityAssetRepository - registryRepo repository.AssetRegistryRepository -} - -// NewActivityAssetService 创建活动藏品服务实例 -func NewActivityAssetService( - activityRepo repository.ActivityAssetRepository, - registryRepo repository.AssetRegistryRepository, -) ActivityAssetService { - return &activityAssetService{ - activityRepo: activityRepo, - registryRepo: registryRepo, - } -} - -// Create 创建活动藏品 -func (s *activityAssetService) Create(asset *models.ActivityAsset) error { - if asset == nil { - return appErrors.ErrInvalidAssetStatus - } - - // 创建活动藏品记录 - if err := s.activityRepo.Create(asset); err != nil { - return err - } - - // 同步写入 asset_registry - registry := &models.AssetRegistry{ - AssetID: asset.AssetID, - AssetType: models.AssetTypeActivity, - OwnerUID: asset.OwnerUID, - StarID: asset.StarID, - ActivityID: &asset.ActivityID, - ActivityType: &asset.ActivityType, - Status: asset.Status, - LikeCount: asset.LikeCount, - CreatedAt: time.Now().UnixMilli(), - UpdatedAt: time.Now().UnixMilli(), - } - - return s.registryRepo.Create(registry) -} - -// GetByID 根据ID获取 -func (s *activityAssetService) GetByID(id int64) (*models.ActivityAsset, error) { - return s.activityRepo.GetByID(id) -} - -// GetByAssetID 根据asset_id获取 -func (s *activityAssetService) GetByAssetID(assetID int64) (*models.ActivityAsset, error) { - return s.activityRepo.GetByAssetID(assetID) -} - -// GetByOwner 获取用户的活动藏品 -func (s *activityAssetService) GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.ActivityAsset, error) { - return s.activityRepo.GetByOwner(ownerUID, starID, limit, offset) -} - -// GetByOwnerAndActivityType 获取用户指定活动类型的活动藏品 -func (s *activityAssetService) GetByOwnerAndActivityType(ownerUID, starID int64, activityType string, limit, offset int) ([]*models.ActivityAsset, error) { - return s.activityRepo.GetByOwnerAndActivityType(ownerUID, starID, activityType, limit, offset) -} - -// GetByOwnerAndActivityID 获取用户指定活动的活动藏品 -func (s *activityAssetService) GetByOwnerAndActivityID(ownerUID, starID int64, activityID int64, limit, offset int) ([]*models.ActivityAsset, error) { - return s.activityRepo.GetByOwnerAndActivityID(ownerUID, starID, activityID, limit, offset) -} - -// CountByOwner 统计用户的活动藏品数量 -func (s *activityAssetService) CountByOwner(ownerUID, starID int64) (int64, error) { - return s.activityRepo.CountByOwner(ownerUID, starID) -} - -// CountByOwnerAndActivityType 统计用户指定活动类型的活动藏品数量 -func (s *activityAssetService) CountByOwnerAndActivityType(ownerUID, starID int64, activityType string) (int64, error) { - return s.activityRepo.CountByOwnerAndActivityType(ownerUID, starID, activityType) -} - -// IncrementLikeCount 增加点赞数 -func (s *activityAssetService) IncrementLikeCount(id int64) error { - return s.activityRepo.IncrementLikeCount(id) -} - -// DecrementLikeCount 减少点赞数 -func (s *activityAssetService) DecrementLikeCount(id int64) error { - return s.activityRepo.DecrementLikeCount(id) -} diff --git a/backend/services/starbookService/service/collection_service.go b/backend/services/starbookService/service/collection_service.go deleted file mode 100644 index 92b43fc..0000000 --- a/backend/services/starbookService/service/collection_service.go +++ /dev/null @@ -1,123 +0,0 @@ -package service - -import ( - "time" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - "github.com/topfans/backend/services/starbookService/repository" -) - -// CollectionService 典藏服务接口 -type CollectionService interface { - // Create 创建典藏藏品 - Create(asset *models.CollectionAsset) error - - // GetByID 根据ID获取 - GetByID(id int64) (*models.CollectionAsset, error) - - // GetByAssetID 根据asset_id获取 - GetByAssetID(assetID int64) (*models.CollectionAsset, error) - - // GetByOwner 获取用户的典藏藏品 - GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.CollectionAsset, error) - - // GetByOwnerAndCategory 获取用户指定分类的典藏藏品 - GetByOwnerAndCategory(ownerUID, starID int64, category string, limit, offset int) ([]*models.CollectionAsset, error) - - // CountByOwner 统计用户的典藏藏品数量 - CountByOwner(ownerUID, starID int64) (int64, error) - - // CountByOwnerAndCategory 统计用户指定分类的典藏藏品数量 - CountByOwnerAndCategory(ownerUID, starID int64, category string) (int64, error) - - // IncrementLikeCount 增加点赞数 - IncrementLikeCount(id int64) error - - // DecrementLikeCount 减少点赞数 - DecrementLikeCount(id int64) error -} - -// collectionService 典藏服务实现 -type collectionService struct { - collectionRepo repository.CollectionRepository - registryRepo repository.AssetRegistryRepository -} - -// NewCollectionService 创建典藏服务实例 -func NewCollectionService( - collectionRepo repository.CollectionRepository, - registryRepo repository.AssetRegistryRepository, -) CollectionService { - return &collectionService{ - collectionRepo: collectionRepo, - registryRepo: registryRepo, - } -} - -// Create 创建典藏藏品 -func (s *collectionService) Create(asset *models.CollectionAsset) error { - if asset == nil { - return appErrors.ErrInvalidAssetStatus - } - - // 创建典藏藏品记录 - if err := s.collectionRepo.Create(asset); err != nil { - return err - } - - // 同步写入 asset_registry - registry := &models.AssetRegistry{ - AssetID: asset.AssetID, - AssetType: models.AssetTypeCollection, - OwnerUID: asset.OwnerUID, - StarID: asset.StarID, - CollectionCategory: &asset.Category, - Status: asset.Status, - LikeCount: asset.LikeCount, - CreatedAt: time.Now().UnixMilli(), - UpdatedAt: time.Now().UnixMilli(), - } - - return s.registryRepo.Create(registry) -} - -// GetByID 根据ID获取 -func (s *collectionService) GetByID(id int64) (*models.CollectionAsset, error) { - return s.collectionRepo.GetByID(id) -} - -// GetByAssetID 根据asset_id获取 -func (s *collectionService) GetByAssetID(assetID int64) (*models.CollectionAsset, error) { - return s.collectionRepo.GetByAssetID(assetID) -} - -// GetByOwner 获取用户的典藏藏品 -func (s *collectionService) GetByOwner(ownerUID, starID int64, limit, offset int) ([]*models.CollectionAsset, error) { - return s.collectionRepo.GetByOwner(ownerUID, starID, limit, offset) -} - -// GetByOwnerAndCategory 获取用户指定分类的典藏藏品 -func (s *collectionService) GetByOwnerAndCategory(ownerUID, starID int64, category string, limit, offset int) ([]*models.CollectionAsset, error) { - return s.collectionRepo.GetByOwnerAndCategory(ownerUID, starID, category, limit, offset) -} - -// CountByOwner 统计用户的典藏藏品数量 -func (s *collectionService) CountByOwner(ownerUID, starID int64) (int64, error) { - return s.collectionRepo.CountByOwner(ownerUID, starID) -} - -// CountByOwnerAndCategory 统计用户指定分类的典藏藏品数量 -func (s *collectionService) CountByOwnerAndCategory(ownerUID, starID int64, category string) (int64, error) { - return s.collectionRepo.CountByOwnerAndCategory(ownerUID, starID, category) -} - -// IncrementLikeCount 增加点赞数 -func (s *collectionService) IncrementLikeCount(id int64) error { - return s.collectionRepo.IncrementLikeCount(id) -} - -// DecrementLikeCount 减少点赞数 -func (s *collectionService) DecrementLikeCount(id int64) error { - return s.collectionRepo.DecrementLikeCount(id) -} diff --git a/backend/services/starbookService/service/starbook_service.go b/backend/services/starbookService/service/starbook_service.go deleted file mode 100644 index 065e6f0..0000000 --- a/backend/services/starbookService/service/starbook_service.go +++ /dev/null @@ -1,448 +0,0 @@ -package service - -import ( - "sort" - - appErrors "github.com/topfans/backend/pkg/errors" - "github.com/topfans/backend/pkg/models" - pb "github.com/topfans/backend/pkg/proto/starbook" - assetRepo "github.com/topfans/backend/services/assetService/repository" - starbookRepo "github.com/topfans/backend/services/starbookService/repository" - "gorm.io/gorm" -) - -// StarbookService 星册服务接口 -type StarbookService interface { - // GetStarbookHome 获取星册首页数据 - GetStarbookHome(ownerUID, starID int64) (*pb.GetStarbookHomeResponse, error) - - // GetStarbookItems 获取星册藏品列表(分页) - GetStarbookItems(req *pb.GetStarbookItemsRequest, ownerUID, starID int64) (*pb.GetStarbookItemsResponse, error) -} - -// starbookService 星册服务实现 -type starbookService struct { - db *gorm.DB - registryRepo starbookRepo.AssetRegistryRepository - assetRepo assetRepo.AssetRepository - collectionRepo starbookRepo.CollectionRepository - activityRepo starbookRepo.ActivityAssetRepository -} - -// NewStarbookService 创建星册服务实例 -func NewStarbookService( - db *gorm.DB, - registryRepo starbookRepo.AssetRegistryRepository, - assetRepo assetRepo.AssetRepository, - collectionRepo starbookRepo.CollectionRepository, - activityRepo starbookRepo.ActivityAssetRepository, -) StarbookService { - return &starbookService{ - db: db, - registryRepo: registryRepo, - assetRepo: assetRepo, - collectionRepo: collectionRepo, - activityRepo: activityRepo, - } -} - -// 常量 -const ( - HomePageSize = 3 // 首页每组最多显示数量 - CastloveCategory = "castlove" - CategoryNameRegular = "原创" - CategoryNameCollection = "典藏" - CategoryNameActivity = "活动" -) - -// GetStarbookHome 获取星册首页数据 -func (s *starbookService) GetStarbookHome(ownerUID, starID int64) (*pb.GetStarbookHomeResponse, error) { - // 1. 查询所有索引记录 - registries, err := s.registryRepo.GetByOwner(ownerUID, starID) - if err != nil { - return nil, err - } - - // 2. 按 type 分组 - typeGroups := make(map[string][]*models.AssetRegistry) - for _, reg := range registries { - typeGroups[reg.AssetType] = append(typeGroups[reg.AssetType], reg) - } - - // 3. 构建响应 - groups := make([]*pb.AssetGroup, 0) - - // 处理原创藏品 (regular) - if regs, ok := typeGroups[models.AssetTypeRegular]; ok { - group := s.buildRegularGroup(ownerUID, starID, regs) - if group != nil { - groups = append(groups, group) - } - } - - // 处理典藏藏品 (collection) - if regs, ok := typeGroups[models.AssetTypeCollection]; ok { - group := s.buildCollectionGroup(ownerUID, starID, regs) - if group != nil { - groups = append(groups, group) - } - } - - // 处理活动藏品 (activity) - if regs, ok := typeGroups[models.AssetTypeActivity]; ok { - group := s.buildActivityGroup(ownerUID, starID, regs) - if group != nil { - groups = append(groups, group) - } - } - - return &pb.GetStarbookHomeResponse{ - Data: &pb.StarbookHomeData{ - Groups: groups, - }, - }, nil -} - -// buildRegularGroup 构建原创藏品分组 -func (s *starbookService) buildRegularGroup(ownerUID, starID int64, registries []*models.AssetRegistry) *pb.AssetGroup { - // 按 grade 分组 - gradeGroups := make(map[int32][]*models.AssetRegistry) - for _, reg := range registries { - if reg.Grade != nil { - gradeGroups[*reg.Grade] = append(gradeGroups[*reg.Grade], reg) - } - } - - // 构建 GradeSection - grades := make([]*pb.GradeSection, 0) - for grade, regs := range gradeGroups { - // 排序:按点赞数降序,保留前3 - sort.Slice(regs, func(i, j int) bool { - return regs[i].LikeCount > regs[j].LikeCount - }) - - // 截取前3条(点赞数最高的3个) - displayRegs := regs - hasMore := false - if len(regs) > HomePageSize { - displayRegs = regs[:HomePageSize] - hasMore = true - } - - // 获取资产详情并生成预签名URL - items := s.buildAssetItemsFromRegistries(displayRegs, models.AssetTypeRegular) - - gradeSection := &pb.GradeSection{ - Grade: grade, - Items: items, - TotalCount: int32(len(regs)), - HasMore: hasMore, - } - grades = append(grades, gradeSection) - } - - // 按 grade 降序排序 - sort.Slice(grades, func(i, j int) bool { - return grades[i].Grade > grades[j].Grade - }) - - // 计算 total_count 和 has_more - totalCount := int32(0) - hasMore := false - for _, g := range grades { - totalCount += g.TotalCount - if g.HasMore { - hasMore = true - } - } - - return &pb.AssetGroup{ - Type: models.AssetTypeRegular, - Category: CastloveCategory, - CategoryName: CategoryNameRegular, - Grades: grades, - TotalCount: totalCount, - HasMore: hasMore, - } -} - -// buildCollectionGroup 构建典藏藏品分组 -func (s *starbookService) buildCollectionGroup(ownerUID, starID int64, registries []*models.AssetRegistry) *pb.AssetGroup { - // 按 category 分组 - categoryGroups := make(map[string][]*models.AssetRegistry) - for _, reg := range registries { - if reg.CollectionCategory != nil && *reg.CollectionCategory != "" { - categoryGroups[*reg.CollectionCategory] = append(categoryGroups[*reg.CollectionCategory], reg) - } - } - - // 构建 AssetGroup items - allItems := make([]*pb.AssetItem, 0) - for category, regs := range categoryGroups { - // 排序:按创建时间降序 - sort.Slice(regs, func(i, j int) bool { - return regs[i].CreatedAt > regs[j].CreatedAt - }) - - // 截取前3条(点赞数最高的3个) - displayRegs := regs - if len(regs) > HomePageSize { - displayRegs = regs[:HomePageSize] - } - - // 获取资产详情 - items := s.buildAssetItemsFromRegistries(displayRegs, models.AssetTypeCollection) - for _, item := range items { - item.Category = category - } - allItems = append(allItems, items...) - } - - // 计算 total_count 和 has_more - totalCount := int32(len(registries)) - hasMore := len(registries) > HomePageSize - - return &pb.AssetGroup{ - Type: models.AssetTypeCollection, - Category: "", - CategoryName: CategoryNameCollection, - Items: allItems, - TotalCount: totalCount, - HasMore: hasMore, - } -} - -// buildActivityGroup 构建活动藏品分组 -func (s *starbookService) buildActivityGroup(ownerUID, starID int64, registries []*models.AssetRegistry) *pb.AssetGroup { - // 按 activity_type 分组 - typeGroups := make(map[string][]*models.AssetRegistry) - for _, reg := range registries { - if reg.ActivityType != nil && *reg.ActivityType != "" { - typeGroups[*reg.ActivityType] = append(typeGroups[*reg.ActivityType], reg) - } - } - - // 构建 AssetGroup items - allItems := make([]*pb.AssetItem, 0) - for activityType, regs := range typeGroups { - // 排序:按创建时间降序 - sort.Slice(regs, func(i, j int) bool { - return regs[i].CreatedAt > regs[j].CreatedAt - }) - - // 截取前3条(点赞数最高的3个) - displayRegs := regs - if len(regs) > HomePageSize { - displayRegs = regs[:HomePageSize] - } - - // 获取资产详情 - items := s.buildAssetItemsFromRegistries(displayRegs, models.AssetTypeActivity) - for _, item := range items { - item.Category = activityType - } - allItems = append(allItems, items...) - } - - // 计算 total_count 和 has_more - totalCount := int32(len(registries)) - hasMore := len(registries) > HomePageSize - - return &pb.AssetGroup{ - Type: models.AssetTypeActivity, - Category: "", - CategoryName: CategoryNameActivity, - Items: allItems, - TotalCount: totalCount, - HasMore: hasMore, - } -} - -// buildAssetItemsFromRegistries 从索引记录构建资产项(使用批量查询优化) -func (s *starbookService) buildAssetItemsFromRegistries(registries []*models.AssetRegistry, assetType string) []*pb.AssetItem { - if len(registries) == 0 { - return []*pb.AssetItem{} - } - - items := make([]*pb.AssetItem, 0, len(registries)) - - // 收集所有 asset IDs - assetIDs := make([]int64, 0, len(registries)) - for _, reg := range registries { - assetIDs = append(assetIDs, reg.AssetID) - } - - // 批量查询资产信息(替代 N+1 查询) - var assetCoverMap map[int64]string // assetID -> coverURL - var assetNameMap map[int64]string // assetID -> name - var categoryMap map[int64]string // assetID -> category - var assetLikeCountMap map[int64]int32 // assetID -> likeCount - - switch assetType { - case models.AssetTypeRegular: - assets, err := s.assetRepo.GetByIDs(assetIDs) - if err == nil && len(assets) > 0 { - assetCoverMap = make(map[int64]string) - assetNameMap = make(map[int64]string) - assetLikeCountMap = make(map[int64]int32) - for _, asset := range assets { - assetCoverMap[asset.ID] = asset.CoverURL - assetNameMap[asset.ID] = asset.Name - assetLikeCountMap[asset.ID] = asset.LikeCount - } - } - case models.AssetTypeCollection: - colAssets, err := s.collectionRepo.GetByAssetIDs(assetIDs) - if err == nil && len(colAssets) > 0 { - assetCoverMap = make(map[int64]string) - assetNameMap = make(map[int64]string) - categoryMap = make(map[int64]string) - for _, colAsset := range colAssets { - assetCoverMap[colAsset.AssetID] = colAsset.CoverURL - assetNameMap[colAsset.AssetID] = colAsset.Name - if colAsset.Category != "" { - categoryMap[colAsset.AssetID] = colAsset.Category - } - } - } - case models.AssetTypeActivity: - actAssets, err := s.activityRepo.GetByAssetIDs(assetIDs) - if err == nil && len(actAssets) > 0 { - assetCoverMap = make(map[int64]string) - assetNameMap = make(map[int64]string) - categoryMap = make(map[int64]string) - for _, actAsset := range actAssets { - assetCoverMap[actAsset.AssetID] = actAsset.CoverURL - assetNameMap[actAsset.AssetID] = actAsset.Name - if actAsset.ActivityType != "" { - categoryMap[actAsset.AssetID] = actAsset.ActivityType - } - } - } - } - - // 构建 items - for _, reg := range registries { - item := &pb.AssetItem{ - AssetId: reg.AssetID, - LikeCount: reg.LikeCount, - CreatedAt: reg.CreatedAt, - Category: CastloveCategory, - Grade: 0, - DisplayStatus: reg.DisplayStatus, - } - - // grade 处理 - if assetType == models.AssetTypeRegular && reg.Grade != nil { - item.Grade = *reg.Grade - } - - // 填充资产信息 - if name, ok := assetNameMap[reg.AssetID]; ok { - item.Name = name - } - if coverURL, ok := assetCoverMap[reg.AssetID]; ok && coverURL != "" { - item.CoverUrlSigned = coverURL - } - if cat, ok := categoryMap[reg.AssetID]; ok { - item.Category = cat - } - - // 从 assets 表获取点赞数(regular 类型) - if assetType == models.AssetTypeRegular { - if likeCount, ok := assetLikeCountMap[reg.AssetID]; ok { - item.LikeCount = likeCount - } - } - - items = append(items, item) - } - - return items -} - -// GetStarbookItems 获取星册藏品列表(分页) -func (s *starbookService) GetStarbookItems(req *pb.GetStarbookItemsRequest, ownerUID, starID int64) (*pb.GetStarbookItemsResponse, error) { - // 参数验证 - if req.Type == "" { - return nil, appErrors.ErrInvalidAssetType - } - - assetType := req.Type - page := req.Page - if page <= 0 { - page = 1 - } - pageSize := req.PageSize - if pageSize <= 0 { - pageSize = 20 - } - offset := (page - 1) * pageSize - - var registries []*models.AssetRegistry - var totalCount int64 - var err error - - switch assetType { - case models.AssetTypeRegular: - grade := req.Grade - if grade <= 0 { - grade = 1 - } - registries, err = s.registryRepo.GetByOwnerAndTypeAndGrade(ownerUID, starID, assetType, grade, int(pageSize), int(offset)) - if err != nil { - return nil, err - } - totalCount, err = s.registryRepo.CountByOwnerAndTypeAndGrade(ownerUID, starID, assetType, grade) - if err != nil { - return nil, err - } - - case models.AssetTypeCollection: - category := req.Category - if category == "" { - category = CastloveCategory - } - registries, err = s.registryRepo.GetByOwnerAndTypeAndCategory(ownerUID, starID, assetType, category, int(pageSize), int(offset)) - if err != nil { - return nil, err - } - totalCount, err = s.registryRepo.CountByOwnerAndTypeAndCategory(ownerUID, starID, assetType, category) - if err != nil { - return nil, err - } - - case models.AssetTypeActivity: - category := req.Category - if category == "" { - category = CastloveCategory - } - registries, err = s.registryRepo.GetByOwnerAndTypeAndCategory(ownerUID, starID, assetType, category, int(pageSize), int(offset)) - if err != nil { - return nil, err - } - totalCount, err = s.registryRepo.CountByOwnerAndTypeAndCategory(ownerUID, starID, assetType, category) - if err != nil { - return nil, err - } - - default: - return nil, appErrors.ErrInvalidAssetType - } - - // 构建 items - items := s.buildAssetItemsFromRegistries(registries, assetType) - - hasMore := int64(page*pageSize) < totalCount - - return &pb.GetStarbookItemsResponse{ - Data: &pb.AssetListData{ - Items: items, - Total: totalCount, - Page: page, - PageSize: pageSize, - HasMore: hasMore, - }, - }, nil -} -