99 lines
4.0 KiB
Go
99 lines
4.0 KiB
Go
package dto
|
||
|
||
// ---------- 请求 ----------
|
||
|
||
// ArticleQuery 文章列表查询条件。
|
||
//
|
||
// 全部筛选项均支持多值(HBX 风格复选框),由 handler 从 query string 解析后填充。
|
||
type ArticleQuery struct {
|
||
Page int
|
||
Size int
|
||
Keyword string // 标题模糊搜索
|
||
BrandID string // 单个品牌 id
|
||
BrandIDs []uint32 // 多个品牌 id(brand_ids 逗号分隔)
|
||
CollectionTypes []string // rtw / menswear / couture / resort / pre_fall
|
||
Seasons []string // spring / fall
|
||
SeasonCode string // SS26 / FW25,精确匹配
|
||
Years []int // 年份
|
||
Sort string // newest / year_desc / year_asc / image_count
|
||
WithImages int // 列表附带每篇前 N 张图,0 表示不带
|
||
|
||
// Locale 语言:cn | en。空时由 service 回落默认 en。
|
||
// 决定 title / description / brand_name 出参选取 *_en 还是 *_cn。
|
||
Locale string
|
||
}
|
||
|
||
// 列表分页与附图数量的边界,与原项目保持一致。
|
||
const (
|
||
articleDefaultSize = 12
|
||
articleMaxSize = 100
|
||
withImagesMax = 12
|
||
)
|
||
|
||
// Normalize 校正分页与附图参数,防止非法值打穿数据库。
|
||
func (q *ArticleQuery) Normalize() {
|
||
if q.Page < 1 {
|
||
q.Page = 1
|
||
}
|
||
if q.Size < 1 || q.Size > articleMaxSize {
|
||
q.Size = articleDefaultSize
|
||
}
|
||
if q.WithImages < 0 {
|
||
q.WithImages = 0
|
||
}
|
||
if q.WithImages > withImagesMax {
|
||
q.WithImages = withImagesMax
|
||
}
|
||
if q.Sort == "" {
|
||
q.Sort = "newest"
|
||
}
|
||
}
|
||
|
||
// Offset 返回 SQL 偏移量。
|
||
func (q ArticleQuery) Offset() int { return (q.Page - 1) * q.Size }
|
||
|
||
// ---------- 响应 ----------
|
||
|
||
// PublicArticleImage 对外展示用的图片结构(仅 url + 名称)。
|
||
type PublicArticleImage struct {
|
||
Image string `json:"image"`
|
||
Name string `json:"name"`
|
||
}
|
||
|
||
// PublicArticle 对外展示用的精简文章结构。
|
||
//
|
||
// 刻意剔除后台管理字段(is_deleted / updated_at / description 全文)。
|
||
// 对外只暴露编码后的 UID(非自增主键),防止爬虫顺序枚举;
|
||
// 同时把 brand_id 也编码为 brand_uid,品牌跳转同样不可枚举。
|
||
type PublicArticle struct {
|
||
UID string `json:"id"` // 编码后的文章 id(无序串)
|
||
BrandUID string `json:"brand_id"` // 编码后的品牌 id(无序串)
|
||
Title string `json:"title"`
|
||
Summary string `json:"summary"` // description 截断后的对外摘要
|
||
Cover string `json:"cover"` // 封面相对路径,如 /uploads/xxx.jpg
|
||
BrandName string `json:"brand_name"` // JOIN brand 得到
|
||
Year uint16 `json:"year"`
|
||
ImageCount uint16 `json:"image_count"`
|
||
CollectionType string `json:"collection_type"` // rtw/menswear/couture/resort/pre_fall
|
||
Season string `json:"season"` // spring/fall/空
|
||
SeasonCode string `json:"season_code"` // SS26/FW25/RES26/PF25
|
||
PublishedAt uint32 `json:"published_at"` // = created_at,Unix 秒
|
||
Images []PublicArticleImage `json:"images"` // with_images 参数控制,未请求时为 null
|
||
}
|
||
|
||
// PublicArticleDetail 对外只读文章详情:含正文与完整图片集,不暴露管理字段。
|
||
type PublicArticleDetail struct {
|
||
UID string `json:"id"` // 编码后的文章 id(无序串)
|
||
BrandUID string `json:"brand_id"` // 编码后的品牌 id(无序串)
|
||
Title string `json:"title"`
|
||
Summary string `json:"summary"`
|
||
Description string `json:"description"`
|
||
Cover string `json:"cover"`
|
||
BrandName string `json:"brand_name"`
|
||
Year uint16 `json:"year"`
|
||
ImageCount uint16 `json:"image_count"`
|
||
SourceURL string `json:"source_url"`
|
||
PublishedAt uint32 `json:"published_at"`
|
||
Images []PublicArticleImage `json:"images"`
|
||
}
|