fix(publish): 最终审查补修(编辑页删图重算计数、迁移编号后置、图片 id 稳定断言)
D1 编辑页删图:DeleteRunwayImage/DeleteSnapImage 在单事务内取父 id→软删→按存活行重算 image_count,口径与审核侧 SoftDelete*Image 完全一致(走秀只计主图、街拍计全部),并补集成测试(含重复删同一张) D2 不可逆删表迁移 02→05(git mv),使文件名顺序 01→01b→03→04→05 与必需执行顺序一致;同步 README/文件头/规格/计划全部引用 D3 新增「通过审核后图片行 id 集合完全一致」的集成断言,锁住单表发布头号收益 D4 修正 01 迁移文件头「只做三件事」自相矛盾表述;D5 删除受版本控制的陈旧产物 cmd/dbtool/db_dump.json 并加 gitignore 规则;D6 清理遗留空目录 scripts/tmp_verify/
This commit is contained in:
@ -33,7 +33,7 @@ type ArticleRepository interface {
|
||||
GetForEdit(ctx context.Context, id uint32) (*model.BrandRunway, []model.BrandRunwayImage, error)
|
||||
// UpdateRunway 审核/编辑后更新字段(白名单,杜绝任意列注入)。
|
||||
UpdateRunway(ctx context.Context, id uint32, fields map[string]any) error
|
||||
// DeleteRunwayImage 软删单张走秀图片。
|
||||
// DeleteRunwayImage 软删单张走秀图片,并按实际存活主图行数重算 image_count。
|
||||
DeleteRunwayImage(ctx context.Context, imageID uint32) error
|
||||
// GetRunwayImageKey 取单张走秀图片的S4 key(删除前清理用);不存在返回空串。
|
||||
GetRunwayImageKey(ctx context.Context, imageID uint32) (string, error)
|
||||
@ -317,11 +317,36 @@ func (r *articleRepository) UpdateRunway(ctx context.Context, id uint32, fields
|
||||
Updates(clean).Error
|
||||
}
|
||||
|
||||
// DeleteRunwayImage 软删单张走秀图片(后台正式编辑页删图),并同步重算 image_count。
|
||||
//
|
||||
// 与审核侧 SoftDeleteRunwayImage 口径一致:删完按**实际存活主图行数**重算
|
||||
// (`is_deleted = 0 AND is_detail = 0`,细节图不计入)。
|
||||
//
|
||||
// 为什么必须重算而不是「递减 1」:单表发布模型删掉了「晋升时按实际图片行重算」的自愈路径,
|
||||
// 编辑页删图若只递减,过期页面 / 重复提交 / 跨记录重放(命中 0 行仍递减)造成的漂移会永久固化,
|
||||
// 并直接显示在公开列表卡片的「N 张」角标里。
|
||||
//
|
||||
// 入参只有 imageID(拿不到父记录 id),故在一个事务里三步走:取 runway_id → 软删 → 重算。
|
||||
// 图片行不存在时与旧行为一致:静默无操作(不报错、不重算)。
|
||||
func (r *articleRepository) DeleteRunwayImage(ctx context.Context, imageID uint32) error {
|
||||
return r.db.WithContext(ctx).
|
||||
Model(&model.BrandRunwayImage{}).
|
||||
Where("id = ? AND is_deleted = 0", imageID).
|
||||
Updates(map[string]any{"is_deleted": 1, "updated_at": uint32(time.Now().Unix())}).Error
|
||||
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var img model.BrandRunwayImage
|
||||
err := tx.Select("runway_id").Where("id = ?", imageID).First(&img).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&model.BrandRunwayImage{}).
|
||||
Where("id = ? AND is_deleted = 0", imageID).
|
||||
Updates(map[string]any{"is_deleted": 1, "updated_at": uint32(time.Now().Unix())}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Exec(`UPDATE brand_runways SET image_count =
|
||||
(SELECT COUNT(*) FROM brand_runway_images WHERE runway_id = ? AND is_deleted = 0 AND is_detail = 0)
|
||||
WHERE id = ?`, img.RunwayID, img.RunwayID).Error
|
||||
})
|
||||
}
|
||||
|
||||
func (r *articleRepository) GetRunwayImageKey(ctx context.Context, imageID uint32) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user