package service import ( "context" "time" "fashionapi/internal/dto" "fashionapi/internal/model" "fashionapi/internal/repository" ) // FavoriteService 收藏业务接口。所有方法均要求调用方已通过中间件解析出 userID。 type FavoriteService interface { // ListPaged 分页取当前用户收藏(服务端分页,与收藏总量解耦)。 ListPaged(ctx context.Context, userID uint32, page, perPage int) ([]dto.FavoriteItem, int64, error) // Add 新增收藏(幂等)。 Add(ctx context.Context, userID uint32, req dto.FavoriteAdd) (*dto.FavoriteItem, error) // Remove 删除收藏。 Remove(ctx context.Context, userID uint32, targetUID string) error // Check 返回给定 ids 中已收藏的子集(列表页打勾用)。 Check(ctx context.Context, userID uint32, ids []string) ([]string, error) } type favoriteService struct { favs repository.FavoriteRepository } // NewFavoriteService 创建收藏服务。 func NewFavoriteService(favs repository.FavoriteRepository) FavoriteService { return &favoriteService{favs: favs} } func (s *favoriteService) ListPaged(ctx context.Context, userID uint32, page, perPage int) ([]dto.FavoriteItem, int64, error) { rows, err := s.favs.ListPaged(ctx, userID, page, perPage) if err != nil { return nil, 0, internalErr(err.Error()) } total, err := s.favs.CountByUser(ctx, userID) if err != nil { return nil, 0, internalErr(err.Error()) } out := make([]dto.FavoriteItem, 0, len(rows)) for _, r := range rows { out = append(out, toFavoriteItem(r)) } return out, total, nil } func (s *favoriteService) Add(ctx context.Context, userID uint32, req dto.FavoriteAdd) (*dto.FavoriteItem, error) { if req.TargetType != "runway" && req.TargetType != "street" { return nil, badRequest("invalid target_type") } if req.TargetUID == "" { return nil, badRequest("target_uid required") } row := &model.Favorite{ UserID: userID, TargetType: req.TargetType, TargetUID: req.TargetUID, Title: req.Title, Cover: req.Cover, Brand: req.Brand, CreatedAt: uint32(time.Now().Unix()), } if err := s.favs.Add(ctx, row); err != nil { return nil, internalErr(err.Error()) } item := toFavoriteItem(*row) return &item, nil } func (s *favoriteService) Remove(ctx context.Context, userID uint32, targetUID string) error { if targetUID == "" { return badRequest("target_uid required") } if err := s.favs.Remove(ctx, userID, targetUID); err != nil { return internalErr(err.Error()) } return nil } func (s *favoriteService) Check(ctx context.Context, userID uint32, ids []string) ([]string, error) { if len(ids) == 0 { return []string{}, nil } got, err := s.favs.FilterExisting(ctx, userID, ids) if err != nil { return nil, internalErr(err.Error()) } return got, nil } func toFavoriteItem(r model.Favorite) dto.FavoriteItem { return dto.FavoriteItem{ ID: r.TargetUID, Type: r.TargetType, Title: r.Title, Cover: r.Cover, Brand: r.Brand, AddedAt: r.CreatedAt, } }