feat: 入库结果落库 + 品牌详情展示更新记录

背景:任务只有 status=done,分不清「新建」「已存在跳过」「已删除跳过」,
品牌更新历史只能在进程日志里翻,日志一滚就没了。

- ingest_jobs 新增 outcome / note / brand_id(迁移 2026-10-25-01)
  outcome 记结果类型,note 记人话细节(新建 N 张图 / 已存在(status=published))
- 提交任务时解出 brand_id 落库,品牌详情页按 (brand_id, id DESC) 直接查
- 处理时优先用 job.brand_id,payload 里的 hashid 只作老任务兜底:
  避免「别的实例盐不同 → 解出错品牌 → 整场 brand not found」再发生
- 品牌编辑页新增「更新记录」区块:时间 / 场次 / 结果 / 明细(含失败原因与尝试次数)
- 测试:fake 仓储补齐新接口,capture 仓储记录 outcome 供断言
This commit is contained in:
toom1996
2026-10-25 11:06:16 +08:00
parent c483018cc8
commit c8a70760cc
9 changed files with 297 additions and 24 deletions

View File

@ -19,8 +19,25 @@ type IngestJob struct {
LastError string `gorm:"column:last_error;type:text" json:"last_error"`
Kind string `gorm:"column:kind;size:16;not null;default:'crawl'" json:"kind"` // crawl|media_cleanup
NextAttemptAt uint32 `gorm:"column:next_attempt_at;not null;default:0" json:"next_attempt_at"` // 重试退避:到达该 unix 时间才可被领取
// Outcome 结果类型(见 IngestOutcome* 常量),Note 是人可读的细节。
// 只有 done 状态才有意义:同为 done,「新建 42 张图」和「实体已存在跳过」是完全不同的事,
// 后台的「品牌更新记录」靠这两个字段说清楚每次到底做了什么。
Outcome string `gorm:"column:outcome;size:24;not null;default:''" json:"outcome"`
Note string `gorm:"column:note;type:text;not null;default:''" json:"note"`
// BrandID 提交时就解出的品牌 id(街拍为 0),供品牌详情页直接按品牌查更新记录。
BrandID uint32 `gorm:"column:brand_id;not null;default:0" json:"brand_id"`
}
// 入库结果类型(ingest_jobs.outcome)。
const (
IngestOutcomeCreated = "created" // 新建入站
IngestOutcomeReused = "reused_rejected" // 复用被驳回的记录并覆盖
IngestOutcomeSkippedExisting = "skipped_existing" // 实体已存在,跳过(不重下图片)
IngestOutcomeSkippedDeleted = "skipped_deleted" // 实体已软删,跳过(删除即永久)
IngestOutcomeCleaned = "cleaned" // 媒体清理任务
IngestOutcomeNoop = "noop" // 无需处理(空载荷)
)
// TableName 指定队列表名。
func (IngestJob) TableName() string { return "ingest_jobs" }