Files
backend_v2/internal/model/runway.go
toom1996 e930ac41c8 feat: 爬虫页取代抓取任务/入库任务两页,抓取改全量+覆盖率跳过
一、后台只留一个「爬虫」页(/admin/spider)
抓取与入库本就是同一条流水线的上下游,分两页看谁都看不全。
新页三块:状态条(在线/卡住 + 队列数 + 待入库数)、正在抓(含进度与心跳)、
最近入库结果(品牌/场次/结果/说明)。只读,取消与重试一并下线。

二、抓取一律全量
删除品牌页的场次上限下拉与 hidden maxShows=3,入队固定 0(全量)。
crawl_tasks.max_shows 列保留,历史任务照常显示。

三、跳过判定改覆盖率
- brand_runways 增加 expected_images(spider 上报的应有张数)
- /shows/covered 返回 images + expected
- 实际张数 >= 应有 - 5 才跳过;expected=0 时回落 10 张阈值
- 实体已存在时不再直接跳过:按 key 比对把缺的图补进库(repaired)
  否则「判定不完整→重爬→后端跳过」会形成死循环,带宽白花、缺图永远补不上

四、租约 900→300 秒,且心跳算存活
只看 locked_at 会把跑了几小时的全量抓取误判成卡死;
加上 progress_at 后,真卡住 5 分钟才回收。
2026-10-25 23:59:54 +08:00

62 lines
3.7 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 model
// BrandRunway 走秀档案(对外称"文章")。
type BrandRunway struct {
ID uint32 `gorm:"primaryKey;column:id" json:"id"`
// i18n 列(方案 A):*_en 为规范英文(当前数据全英文),*_cn 为中文;
// 服务端按 locale 选列,缺翻译回落另一语言。
// (原通用 title / description 列已删除,统一由 *_en/*_cn 取代。)
TitleEn string `gorm:"column:title_en" json:"title_en"`
TitleCn string `gorm:"column:title_cn" json:"title_cn"`
DescriptionEn string `gorm:"column:description_en" json:"description_en"`
DescriptionCn string `gorm:"column:description_cn" json:"description_cn"`
CreatedAt uint32 `gorm:"column:created_at" json:"created_at"`
UpdatedAt uint32 `gorm:"column:updated_at" json:"updated_at"`
IsDeleted uint8 `gorm:"column:is_deleted" json:"is_deleted"`
ImageCount uint16 `gorm:"column:image_count" json:"image_count"`
// ExpectedImages 该场秀应有的图片总数(spider 上报)。0 = 未知(本字段上线前的历史数据)。
//
// 用途:重爬前的覆盖率判定——实际张数接近应有张数才算「抓全了」。
// 只看「有没有图」会把当初只抓到十几张的场次永久判成已完成,缺的图再也补不上。
ExpectedImages int `gorm:"column:expected_images;not null;default:0" json:"expected_images"`
BrandID uint32 `gorm:"column:brand_id" json:"brand_id"`
Year uint16 `gorm:"column:year" json:"year"`
Cover string `gorm:"column:cover" json:"cover"`
// 分类字段:由 title 解析回填(历史数据迁移一次性写入,现已由外部 SQL 迁移维护)
CollectionType string `gorm:"column:collection_type;size:16;not null;default:''" json:"collection_type"` // rtw/menswear/couture/resort/pre_fall
Season string `gorm:"column:season;size:8" json:"season"` // spring/fall/null
SeasonCode string `gorm:"column:season_code;size:8;not null;default:''" json:"season_code"` // SS26/FW25/RES26/PF25
PublishedAt uint32 `gorm:"column:published_at" json:"published_at"` // 发布时间 Unix 时间戳(秒);0=未抽取。Vogue datePublished;标题缺年份时用于矫正 year
// 审核态与溯源(单表发布模型;列由 db/migrations/2026-09-22-01-single-table-publish.sql 添加)。
Status string `gorm:"column:status;size:16;not null;default:'pending'" json:"status"`
JobID uint32 `gorm:"column:job_id;not null;default:0" json:"job_id"` // 关联 ingest_jobs.id(重跑溯源)
Reviewer string `gorm:"column:reviewer;size:64;not null;default:''" json:"reviewer"` // 审核人(admin 账号)
}
// TableName 指定表名。
func (BrandRunway) TableName() string { return "brand_runways" }
// RunwayRow 走秀档案的查询投影行。
//
// 独立于 BrandRunway 定义,是为了承载 JOIN brands 得到的品牌名(en/cn 两列)。
type RunwayRow struct {
ID uint32 `gorm:"column:id"`
BrandID uint32 `gorm:"column:brand_id"`
TitleEn string `gorm:"column:title_en"`
TitleCn string `gorm:"column:title_cn"`
DescriptionEn string `gorm:"column:description_en"`
DescriptionCn string `gorm:"column:description_cn"`
Cover string `gorm:"column:cover"`
Year uint16 `gorm:"column:year"`
ImageCount uint16 `gorm:"column:image_count"`
CollectionType string `gorm:"column:collection_type"`
Season string `gorm:"column:season"`
SeasonCode string `gorm:"column:season_code"`
Status string `gorm:"column:status"`
CreatedAt uint32 `gorm:"column:created_at"`
BrandNameEn string `gorm:"column:brand_name_en"`
BrandNameCn string `gorm:"column:brand_name_cn"`
}