chore(backend): remove starbookService + proto (config 4.2 cleanup)
- 删 services/starbookService 目录 (Phase 2 决策, owner 已迁 assetService); - 删 backend/proto/starbook.proto (proto 源, 不再被任何 service 引用)。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7ff2d5cdc4
commit
f46464fdf9
@ -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;
|
|
||||||
}
|
|
||||||
@ -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")
|
|
||||||
}
|
|
||||||
@ -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)
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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)
|
|
||||||
}
|
|
||||||
@ -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)
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user