Files
backend_v2/internal/dto/article.go
2026-09-20 01:06:13 +08:00

136 lines
7.0 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 dto
// ---------- 请求 ----------
// ArticleQuery 走秀列表查询条件(GET /public/runway-looks)。
//
// 设计原则:参数尽可能少、不复用。
// - 所有筛选均为单值(前端已全改为单选),不再支持多选数组;
// - 按品牌过滤走查询参数 brand_id(hashid 编码串),不再使用独立嵌套路由;
// - 关键词搜索已移除(无前端调用);season_code 冗余(season+year 已覆盖)也已移除。
// - 分页 size 与附图 images 由服务端固定(ArticleFixedSize / ArticleFixedImages),前端不传、不可调。
type ArticleQuery struct {
Page int
Size int // 服务端固定为 ArticleFixedSize,不从 query 读取
Collection string // 单值:rtw / menswear / couture / resort / pre_fall
Season string // 单值:spring / fall
Year int // 单值年份,0 表示不过滤
Sort string // newest(默认)/ year_desc / year_asc
Images int // 服务端固定为 ArticleFixedImages,不从 query 读取
// Locale 语言:cn | en。空时由 service 回落默认 en。
// 决定 title / description / brand_name 出参选取 *_en 还是 *_cn。
Locale string
// BrandIDs 由列表接口从查询参数 brand_id(hashid 编码串)解码注入;为空表示不过滤。
BrandIDs []uint32
}
// 列表分页与附图数量由服务端固定(前端无调整入口),不再从 query 读取。
const (
ArticleFixedSize = 24 // 每页条数(runway-looks 分页固定值)
articleMaxSize = 100
ArticleFixedImages = 6 // 列表每篇附带前 N 张缩略图
imagesMax = 12
// PreviewLimit 未登录用户在列表接口可见的预览条数上限;
// 超过部分由前端登录门禁提示,避免公开接口一次性吐出全部图集。
PreviewLimit = 5
)
// Normalize 校正分页与附图参数,防止非法值打穿数据库。
func (q *ArticleQuery) Normalize() {
if q.Page < 1 {
q.Page = 1
}
if q.Size < 1 || q.Size > articleMaxSize {
q.Size = ArticleFixedSize
}
if q.Images < 0 {
q.Images = 0
}
if q.Images > imagesMax {
q.Images = imagesMax
}
if q.Sort == "" {
q.Sort = "newest"
}
}
// Offset 返回 SQL 偏移量。
func (q ArticleQuery) Offset() int { return (q.Page - 1) * q.Size }
// ---------- 响应 ----------
// PublicArticleImage 对外展示用的图片结构。
//
// ID 是图片自身的编码 id(hashid,类型进密码:i=走秀单图 / j=街拍单图),供「单图收藏」定位到具体某一张;
// 此前只有 image + name,前端无法稳定标识单张图片,故补充该字段。
//
// Image 与 Thumb 的关系:
// - Image 是「该接口场景下的主用地址」——详情接口给展示样式(high),列表接口直接给缩略图(thumb,
// 列表只需小图,不给大图以免浪费带宽)。
// - Thumb 恒为缩略图地址(thumb 样式),**仅详情接口填充**:详情返回的是展示样式大图,
// 但大图灯箱左栏缩略图条 / 右下角细节缩略图只要几十到一百多像素,用大图纯属浪费,
// 故额外给出 Thumb 供这些「小尺寸场景」使用。列表接口不填(其 Image 本身就是缩略图)。
type PublicArticleImage struct {
ID string `json:"id"`
Image string `json:"image"`
Thumb string `json:"thumb,omitempty"`
Name string `json:"name"`
IsDetail uint8 `json:"is_detail"` // 0=主图 1=细节图(详情接口 images 仅含主图,细节图挂在所属主图的 Detail 下)
LookIndex uint32 `json:"look_index"` // 该图归属的主图序号;细节图与所属主图同值
Favorited bool `json:"favorited,omitempty"` // 已登录时该图片是否被当前用户收藏(image 级)
// Detail 仅详情接口填充:该主图(look)下的细节图子集,元素形状与 Images 递归同构。
// 「look → 细节」的层级与前端 UI 一致,前端直接读它即可,无需再维护一份
// 「按 look_index 分组」的映射表。列表接口不填(omitempty 后不出现)。
Detail []PublicArticleImage `json:"detail,omitempty"`
}
// PublicArticle 对外展示用的精简文章结构(走秀列表)。
//
// 只返回前端真正渲染的字段:id / brand_id / title / cover / brand_name / image_count / images。
// year / season / season_code / collection_type / published_at / summary 前端从不展示,
// 且排序已由后端按真实走秀新旧(year + season 优先级)完成,故响应不再携带这些元数据。
// 对外只暴露编码后的 UID(非自增主键),防止爬虫顺序枚举;brand_id 同样编码为 brand_uid。
type PublicArticle struct {
UID string `json:"id"` // 编码后的文章 id(无序串)
BrandUID string `json:"brand_id"` // 编码后的品牌 id(无序串)
Title string `json:"title"`
Cover string `json:"cover"` // 封面相对路径,如 /uploads/xxx.jpg
BrandName string `json:"brand_name"` // JOIN brands 得到
ImageCount uint16 `json:"image_count"` // 该走秀图片总数(列表卡片 "N+" 角标用)
Images []PublicArticleImage `json:"images"` // 列表附带的每篇前 N 张缩略图
}
// PublicArticleDetail 对外只读文章详情:含正文与完整图片集,不暴露管理字段。
//
// 与列表一致,只返回前端渲染所需的字段;后台管理用的额外元数据(季节 / 年份 / 系列等)
// 见 AdminRunway,由后台列表接口单独返回。
type PublicArticleDetail struct {
UID string `json:"id"` // 编码后的文章 id(无序串)
BrandUID string `json:"brand_id"` // 编码后的品牌 id(无序串)
Title string `json:"title"`
Description string `json:"description"`
Cover string `json:"cover"`
BrandName string `json:"brand_name"`
// Images 仅含主图(look 图),默认展示;每个主图的细节图挂在它自己的 Detail 子数组下。
Images []PublicArticleImage `json:"images"`
Favorited bool `json:"favorited,omitempty"` // 已登录时该图集是否被当前用户收藏(gallery 级)
}
// AdminRunway 后台管理用的走秀列表项:在 PublicArticle 基础上补回管理字段,
// 供后台按季节 / 年份 / 系列筛选与展示(对外 PublicArticle 刻意不暴露这些元数据)。
type AdminRunway struct {
UID string `json:"id"` // 编码后的文章 id(无序串)
BrandUID string `json:"brand_id"` // 编码后的品牌 id(无序串)
BrandName string `json:"brand_name"` // JOIN brands 得到(优先 en)
Title string `json:"title"`
Year uint16 `json:"year"` // 年份(如 2024)
Season string `json:"season"` // spring / fall
CollectionType string `json:"collection_type"` // rtw / menswear / couture / resort / pre_fall
SeasonCode string `json:"season_code"` // SS26 / FW25 / RES26 / PF25
ImageCount uint16 `json:"image_count"`
}