update
This commit is contained in:
@ -144,9 +144,9 @@ func main() {
|
||||
engine := router.New(router.Options{
|
||||
Config: cfg,
|
||||
JWT: jwtManager,
|
||||
Article: handler.NewArticleHandler(articleSvc),
|
||||
Article: handler.NewArticleHandler(articleSvc, favSvc),
|
||||
Brand: handler.NewBrandHandler(brandSvc),
|
||||
StreetSnap: handler.NewStreetSnapHandler(snapSvc),
|
||||
StreetSnap: handler.NewStreetSnapHandler(snapSvc, favSvc),
|
||||
Auth: handler.NewAuthHandler(authSvc),
|
||||
Favorite: handler.NewFavoriteHandler(favSvc),
|
||||
History: handler.NewHistoryHandler(histSvc),
|
||||
|
||||
@ -80,6 +80,7 @@ type PublicArticleImage struct {
|
||||
Name string `json:"name"`
|
||||
IsDetail uint8 `json:"is_detail"` // 0=主图 1=细节图(详情接口 images 仅含主图;细节在 Details 分组)
|
||||
LookIndex uint32 `json:"look_index"` // 细节图归属的主图序号(用于前端分组展开)
|
||||
Favorited bool `json:"favorited,omitempty"` // 已登录时该图片是否被当前用户收藏(image 级)
|
||||
}
|
||||
|
||||
// RunwayLookDetails 某个主图(look)对应的细节图集合,供详情页「细节入口」按需展开。
|
||||
@ -117,6 +118,7 @@ type PublicArticleDetail struct {
|
||||
BrandName string `json:"brand_name"`
|
||||
Images []PublicArticleImage `json:"images"` // 仅主图(look 图),默认展示
|
||||
Details []RunwayLookDetails `json:"details"` // 按主图分组的细节图(「细节入口」展开用);无细节时为空
|
||||
Favorited bool `json:"favorited,omitempty"` // 已登录时该图集是否被当前用户收藏(gallery 级,r= 前缀)
|
||||
}
|
||||
|
||||
// AdminRunway 后台管理用的走秀列表项:在 PublicArticle 基础上补回管理字段,
|
||||
|
||||
@ -66,4 +66,5 @@ type PublicStreetSnapDetail struct {
|
||||
Title string `json:"title"`
|
||||
Cover string `json:"cover"`
|
||||
Images []PublicArticleImage `json:"images"`
|
||||
Favorited bool `json:"favorited,omitempty"` // 已登录时该图集是否被当前用户收藏(gallery 级,s= 前缀)
|
||||
}
|
||||
|
||||
@ -17,11 +17,12 @@ import (
|
||||
// ArticleHandler 对外公开的文章接口。
|
||||
type ArticleHandler struct {
|
||||
articles service.ArticleService
|
||||
favs service.FavoriteService
|
||||
}
|
||||
|
||||
// NewArticleHandler 创建文章 handler。
|
||||
func NewArticleHandler(articles service.ArticleService) *ArticleHandler {
|
||||
return &ArticleHandler{articles: articles}
|
||||
func NewArticleHandler(articles service.ArticleService, favs service.FavoriteService) *ArticleHandler {
|
||||
return &ArticleHandler{articles: articles, favs: favs}
|
||||
}
|
||||
|
||||
// List 走秀列表(分页 + 单值筛选 + 排序)。
|
||||
@ -109,5 +110,29 @@ func (h *ArticleHandler) Detail(c *gin.Context) {
|
||||
detail.Images = detail.Images[:dto.PreviewLimit]
|
||||
preview = true
|
||||
}
|
||||
|
||||
// 已登录:把当前用户对该图集(gallery 级)与每张图片(image 级)的收藏态随详情返回,
|
||||
// 前端无需再单独调 /me/favorites/checks。gallery uid(r=)与图片 id(i=)前缀不同,
|
||||
// 混传 FilterExisting 不影响查询;匿名请求不查(保持公开接口无用户态、可缓存)。
|
||||
if uid, ok := middleware.UserIDFrom(c); ok {
|
||||
ids := make([]string, 0, len(detail.Images)+1)
|
||||
ids = append(ids, detail.UID)
|
||||
for _, im := range detail.Images {
|
||||
if im.ID != "" {
|
||||
ids = append(ids, im.ID)
|
||||
}
|
||||
}
|
||||
if hit, err := h.favs.Check(c.Request.Context(), uid, ids); err == nil {
|
||||
set := make(map[string]bool, len(hit))
|
||||
for _, id := range hit {
|
||||
set[id] = true
|
||||
}
|
||||
detail.Favorited = set[detail.UID]
|
||||
for i := range detail.Images {
|
||||
detail.Images[i].Favorited = set[detail.Images[i].ID]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.DataPreview(c, http.StatusOK, detail, preview, imageTotal)
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"fashionapi/internal/dto"
|
||||
"fashionapi/internal/middleware"
|
||||
"fashionapi/internal/pkg/hashid"
|
||||
"fashionapi/internal/pkg/response"
|
||||
"fashionapi/internal/service"
|
||||
@ -15,12 +16,13 @@ import (
|
||||
|
||||
// StreetSnapHandler 对外公开的街拍接口。
|
||||
type StreetSnapHandler struct {
|
||||
svc service.StreetSnapService
|
||||
svc service.StreetSnapService
|
||||
favs service.FavoriteService
|
||||
}
|
||||
|
||||
// NewStreetSnapHandler 创建街拍 handler。
|
||||
func NewStreetSnapHandler(svc service.StreetSnapService) *StreetSnapHandler {
|
||||
return &StreetSnapHandler{svc: svc}
|
||||
func NewStreetSnapHandler(svc service.StreetSnapService, favs service.FavoriteService) *StreetSnapHandler {
|
||||
return &StreetSnapHandler{svc: svc, favs: favs}
|
||||
}
|
||||
|
||||
// List 街拍列表(分页 + 排序 + 年份过滤)。
|
||||
@ -93,5 +95,28 @@ func (h *StreetSnapHandler) Detail(c *gin.Context) {
|
||||
detail.Images = detail.Images[:dto.PreviewLimit]
|
||||
preview = true
|
||||
}
|
||||
|
||||
// 已登录:图集(gallery 级 s=)与每张图片(image 级 j=)收藏态随详情返回,
|
||||
// 前端无需再单独调 /me/favorites/checks。
|
||||
if uid, ok := middleware.UserIDFrom(c); ok {
|
||||
ids := make([]string, 0, len(detail.Images)+1)
|
||||
ids = append(ids, detail.UID)
|
||||
for _, im := range detail.Images {
|
||||
if im.ID != "" {
|
||||
ids = append(ids, im.ID)
|
||||
}
|
||||
}
|
||||
if hit, err := h.favs.Check(c.Request.Context(), uid, ids); err == nil {
|
||||
set := make(map[string]bool, len(hit))
|
||||
for _, id := range hit {
|
||||
set[id] = true
|
||||
}
|
||||
detail.Favorited = set[detail.UID]
|
||||
for i := range detail.Images {
|
||||
detail.Images[i].Favorited = set[detail.Images[i].ID]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.DataPreview(c, http.StatusOK, detail, preview, imageTotal)
|
||||
}
|
||||
|
||||
@ -141,7 +141,6 @@ func New(opt Options) *gin.Engine {
|
||||
legacy.GET("/favorites", opt.Favorite.List)
|
||||
legacy.POST("/favorites", opt.Favorite.Add)
|
||||
legacy.DELETE("/favorites/:uid", opt.Favorite.Remove)
|
||||
legacy.POST("/favorites/check", opt.Favorite.Check)
|
||||
|
||||
legacy.GET("/history", opt.History.List)
|
||||
legacy.POST("/history", opt.History.Record)
|
||||
|
||||
Reference in New Issue
Block a user