package dto // ---------- 请求 ---------- // ArticleQuery 走秀列表查询条件(GET /public/runways)。 // // 设计原则:参数尽可能少、不复用。 // - 所有筛选均为单值(前端已全改为单选),不再支持多选数组; // - 按品牌过滤走查询参数 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 ) // 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,前端无法稳定标识单张图片,故补充该字段。 type PublicArticleImage struct { ID string `json:"id"` Image string `json:"image"` Name string `json:"name"` } // 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 brand 得到 ImageCount uint16 `json:"image_count"` // 该走秀图片总数(列表卡片 "N+" 角标用) Images []PublicArticleImage `json:"images"` // 列表附带的每篇前 N 张缩略图 } // PublicArticleDetail 对外只读文章详情:含正文与完整图片集,不暴露管理字段。 // // 与列表一致,只返回前端渲染所需的字段;image_count / source_url / 各类时间季节元数据前端均不展示,已移除。 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 []PublicArticleImage `json:"images"` }