Files
backend_v2/internal/service/street_snap_service.go
toom1996 ffe84efc4c update
2026-09-03 00:32:52 +08:00

156 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"errors"
"net/http"
"fashionapi/internal/dto"
"fashionapi/internal/model"
"fashionapi/internal/pkg/hashid"
"fashionapi/internal/repository"
)
// StreetSnapService 街拍业务接口。
type StreetSnapService interface {
List(ctx context.Context, q dto.StreetSnapQuery) ([]dto.PublicStreetSnap, int64, error)
Detail(ctx context.Context, id string) (*dto.PublicStreetSnapDetail, error)
// Popular 返回热度前 N 个街拍(按图片数降序),供 SSG 首页热门街拍展示。
Popular(ctx context.Context, limit int) ([]dto.PublicStreetSnap, error)
}
type streetSnapService struct {
repo repository.StreetSnapRepository
}
// NewStreetSnapService 创建街拍服务。
func NewStreetSnapService(repo repository.StreetSnapRepository) StreetSnapService {
return &streetSnapService{repo: repo}
}
// ErrStreetSnapNotFound 街拍不存在。
var ErrStreetSnapNotFound = NewError(http.StatusNotFound, "street snap not found")
// List 查询街拍列表,并按需附带每条的前 N 张图。
func (s *streetSnapService) List(ctx context.Context, q dto.StreetSnapQuery) ([]dto.PublicStreetSnap, int64, error) {
q.Normalize()
rows, total, err := s.repo.List(ctx, q)
if err != nil {
return nil, 0, internalErr(err.Error())
}
list := make([]dto.PublicStreetSnap, 0, len(rows))
ids := make([]uint32, 0, len(rows))
for _, r := range rows {
ids = append(ids, r.ID)
list = append(list, dto.PublicStreetSnap{
UID: hashid.EncodeTyped(hashid.TypeSnap, r.ID),
Title: r.Title,
Cover: r.Cover,
ImageCount: r.ImageCount,
})
}
if q.Images > 0 && len(list) > 0 {
if err := s.attachImages(ctx, list, ids, q.Images); err != nil {
return nil, 0, internalErr(err.Error())
}
}
return list, total, nil
}
// attachImages 用单次 IN 查询为列表批量补齐图片,避免前端逐条请求详情。
func (s *streetSnapService) attachImages(ctx context.Context, list []dto.PublicStreetSnap, ids []uint32, limit int) error {
grouped, err := s.repo.ImagesBySnapIDs(ctx, ids)
if err != nil {
return err
}
for i := range list {
imgs, ok := grouped[ids[i]]
if !ok {
continue
}
// 缩略图条带剔除主图(cover),避免与卡片主图重复。cover 恒等于图片列表首张。
imgs = excludeCoverSnap(imgs, list[i].Cover)
if len(imgs) > limit {
imgs = imgs[:limit]
}
list[i].Images = toPublicSnapImages(imgs)
}
return nil
}
// excludeCoverSnap 同 excludeCover,作用于街拍图片列表。
func excludeCoverSnap(imgs []model.StreetSnapImage, cover string) []model.StreetSnapImage {
if cover == "" {
return imgs
}
kept := imgs[:0]
for _, im := range imgs {
if im.Image != cover {
kept = append(kept, im)
}
}
return kept
}
// Detail 查询街拍详情,含完整图片集。
func (s *streetSnapService) Detail(ctx context.Context, id string) (*dto.PublicStreetSnapDetail, error) {
snap, err := s.repo.FindByID(ctx, id)
if err != nil {
if errors.Is(err, repository.ErrNotFound) {
return nil, ErrStreetSnapNotFound
}
return nil, internalErr(err.Error())
}
imgs, err := s.repo.ListImages(ctx, id)
if err != nil {
return nil, internalErr(err.Error())
}
return &dto.PublicStreetSnapDetail{
UID: hashid.EncodeTyped(hashid.TypeSnap, snap.ID),
Title: snap.Title,
Cover: snap.Cover,
Images: toPublicSnapImages(imgs),
}, nil
}
// IDs 返回全部街拍的编码 uid(供 SSG 枚举详情页路径使用,对外暴露的即编码串)。
// Popular 返回热度前 N 个街拍(按图片数降序),供 SSG 首页热门街拍展示。
func (s *streetSnapService) Popular(ctx context.Context, limit int) ([]dto.PublicStreetSnap, error) {
rows, err := s.repo.Popular(ctx, limit)
if err != nil {
return nil, internalErr(err.Error())
}
list := make([]dto.PublicStreetSnap, 0, len(rows))
for _, r := range rows {
list = append(list, dto.PublicStreetSnap{
UID: hashid.EncodeTyped(hashid.TypeSnap, r.ID),
Title: r.Title,
Cover: r.Cover,
ImageCount: r.ImageCount,
})
}
return list, nil
}
// 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{
ID: hashid.EncodeTyped(hashid.TypeSnapImage, im.ID),
Image: im.Image,
Name: im.Name,
})
}
return out
}