update
This commit is contained in:
@ -122,14 +122,19 @@ func (s *articleService) Detail(ctx context.Context, id string, locale string) (
|
||||
}
|
||||
|
||||
// IDs 返回全部文章的编码 uid(供 SSG 枚举详情页路径使用,对外暴露的即编码串)。
|
||||
// toPublicImages 把图片实体映射为对外结构(只保留 url 与名称)。
|
||||
// toPublicImages 把图片实体映射为对外结构(url + 名称 + 图片自身的编码 id)。
|
||||
// ID 用 TypeRunwayImage 前缀编码,与文章 uid(r 前缀)区分开,供单图收藏定位。
|
||||
func toPublicImages(imgs []model.BrandRunwayImage) []dto.PublicArticleImage {
|
||||
if len(imgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]dto.PublicArticleImage, 0, len(imgs))
|
||||
for _, im := range imgs {
|
||||
out = append(out, dto.PublicArticleImage{Image: im.Image, Name: im.Name})
|
||||
out = append(out, dto.PublicArticleImage{
|
||||
ID: hashid.EncodeTyped(hashid.TypeRunwayImage, im.ID),
|
||||
Image: im.Image,
|
||||
Name: im.Name,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fashionapi/internal/dto"
|
||||
@ -12,7 +13,8 @@ import (
|
||||
// FavoriteService 收藏业务接口。所有方法均要求调用方已通过中间件解析出 userID。
|
||||
type FavoriteService interface {
|
||||
// ListPaged 分页取当前用户收藏(服务端分页,与收藏总量解耦)。
|
||||
ListPaged(ctx context.Context, userID uint32, page, perPage int) ([]dto.FavoriteItem, int64, error)
|
||||
// kind 传空表示不限粒度;传 gallery / image 只取对应粒度。
|
||||
ListPaged(ctx context.Context, userID uint32, page, perPage int, kind string) ([]dto.FavoriteItem, int64, error)
|
||||
// Add 新增收藏(幂等)。
|
||||
Add(ctx context.Context, userID uint32, req dto.FavoriteAdd) (*dto.FavoriteItem, error)
|
||||
// Remove 删除收藏。
|
||||
@ -30,12 +32,12 @@ 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)
|
||||
func (s *favoriteService) ListPaged(ctx context.Context, userID uint32, page, perPage int, kind string) ([]dto.FavoriteItem, int64, error) {
|
||||
rows, err := s.favs.ListPaged(ctx, userID, page, perPage, kind)
|
||||
if err != nil {
|
||||
return nil, 0, internalErr(err.Error())
|
||||
}
|
||||
total, err := s.favs.CountByUser(ctx, userID)
|
||||
total, err := s.favs.CountByUser(ctx, userID, kind)
|
||||
if err != nil {
|
||||
return nil, 0, internalErr(err.Error())
|
||||
}
|
||||
@ -47,12 +49,26 @@ func (s *favoriteService) ListPaged(ctx context.Context, userID uint32, page, pe
|
||||
}
|
||||
|
||||
func (s *favoriteService) Add(ctx context.Context, userID uint32, req dto.FavoriteAdd) (*dto.FavoriteItem, error) {
|
||||
if req.TargetType != "runway" && req.TargetType != "street" {
|
||||
if !validTargetType(req.TargetType) {
|
||||
return nil, badRequest("invalid target_type")
|
||||
}
|
||||
if req.TargetUID == "" {
|
||||
return nil, badRequest("target_uid required")
|
||||
}
|
||||
|
||||
// 粒度:请求未显式指定时按 target_type 推断(*_image 即图片收藏)。
|
||||
kind := req.Kind
|
||||
if kind == "" {
|
||||
kind = inferKind(req.TargetType)
|
||||
}
|
||||
if kind != dto.FavoriteKindGallery && kind != dto.FavoriteKindImage {
|
||||
return nil, badRequest("invalid kind")
|
||||
}
|
||||
// 图片收藏必须带上图片地址,否则个人中心无从渲染。
|
||||
if kind == dto.FavoriteKindImage && req.ImageURL == "" {
|
||||
return nil, badRequest("image_url required for image favorite")
|
||||
}
|
||||
|
||||
row := &model.Favorite{
|
||||
UserID: userID,
|
||||
TargetType: req.TargetType,
|
||||
@ -60,6 +76,9 @@ func (s *favoriteService) Add(ctx context.Context, userID uint32, req dto.Favori
|
||||
Title: req.Title,
|
||||
Cover: req.Cover,
|
||||
Brand: req.Brand,
|
||||
Kind: kind,
|
||||
ImageURL: req.ImageURL,
|
||||
ParentUID: req.ParentUID,
|
||||
CreatedAt: uint32(time.Now().Unix()),
|
||||
}
|
||||
if err := s.favs.Add(ctx, row); err != nil {
|
||||
@ -90,13 +109,37 @@ func (s *favoriteService) Check(ctx context.Context, userID uint32, ids []string
|
||||
return got, nil
|
||||
}
|
||||
|
||||
// validTargetType 允许的收藏目标类型:图集两种 + 单图两种。
|
||||
func validTargetType(t string) bool {
|
||||
switch t {
|
||||
case "runway", "street", "runway_image", "snap_image":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// inferKind 由 target_type 推断收藏粒度。
|
||||
func inferKind(targetType string) string {
|
||||
if strings.HasSuffix(targetType, "_image") {
|
||||
return dto.FavoriteKindImage
|
||||
}
|
||||
return dto.FavoriteKindGallery
|
||||
}
|
||||
|
||||
func toFavoriteItem(r model.Favorite) dto.FavoriteItem {
|
||||
kind := r.Kind
|
||||
if kind == "" {
|
||||
kind = dto.FavoriteKindGallery // 历史数据无 kind 列值,一律视为图集
|
||||
}
|
||||
return dto.FavoriteItem{
|
||||
ID: r.TargetUID,
|
||||
Type: r.TargetType,
|
||||
Title: r.Title,
|
||||
Cover: r.Cover,
|
||||
Brand: r.Brand,
|
||||
AddedAt: r.CreatedAt,
|
||||
ID: r.TargetUID,
|
||||
Type: r.TargetType,
|
||||
Title: r.Title,
|
||||
Cover: r.Cover,
|
||||
Brand: r.Brand,
|
||||
AddedAt: r.CreatedAt,
|
||||
Kind: kind,
|
||||
ImageURL: r.ImageURL,
|
||||
ParentUID: r.ParentUID,
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,14 +137,19 @@ func (s *streetSnapService) Popular(ctx context.Context, limit int) ([]dto.Publi
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// toPublicSnapImages 把图片实体映射为对外结构(只保留 url 与名称)。
|
||||
// toPublicSnapImages 把图片实体映射为对外结构(url + 名称 + 图片自身的编码 id)。
|
||||
// ID 用 TypeSnapImage 前缀编码,与街拍 uid(s 前缀)区分开,供单图收藏定位。
|
||||
func toPublicSnapImages(imgs []model.StreetSnapImage) []dto.PublicArticleImage {
|
||||
if len(imgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]dto.PublicArticleImage, 0, len(imgs))
|
||||
for _, im := range imgs {
|
||||
out = append(out, dto.PublicArticleImage{Image: im.Image, Name: im.Name})
|
||||
out = append(out, dto.PublicArticleImage{
|
||||
ID: hashid.EncodeTyped(hashid.TypeSnapImage, im.ID),
|
||||
Image: im.Image,
|
||||
Name: im.Name,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user