fix(publish): 软删图片按实际行重算 image_count,状态写入拒绝不存在的记录
This commit is contained in:
@ -24,7 +24,7 @@ type ReviewRepository interface {
|
||||
RecordImages(ctx context.Context, recordID uint32) ([]model.BrandRunwayImage, error)
|
||||
// UpdateRecord 审核前微调字段(白名单,杜绝任意列注入)。
|
||||
UpdateRecord(ctx context.Context, id uint32, fields map[string]any) error
|
||||
// SetRecordStatus 设置状态(通过/驳回)与审核人/驳回理由。
|
||||
// SetRecordStatus 设置状态(通过/驳回)与审核人/驳回理由;记录不存在返回 ErrNotFound。
|
||||
SetRecordStatus(ctx context.Context, id uint32, status, reviewer, reason string) error
|
||||
|
||||
// 街拍镜像方法(对象为 street_snaps / street_snap_images)。
|
||||
@ -32,11 +32,12 @@ type ReviewRepository interface {
|
||||
StreetRecordDetail(ctx context.Context, id uint32) (*model.StreetSnap, error)
|
||||
StreetRecordImages(ctx context.Context, recordID uint32) ([]model.StreetSnapImage, error)
|
||||
UpdateStreetRecord(ctx context.Context, id uint32, fields map[string]any) error
|
||||
// SetStreetRecordStatus 设置状态;记录不存在返回 ErrNotFound。
|
||||
SetStreetRecordStatus(ctx context.Context, id uint32, status, reviewer, reason string) error
|
||||
|
||||
// SoftDeleteRunwayImage 软删单张走秀图片(审核阶段剔除坏图),并同步 image_count。
|
||||
// SoftDeleteRunwayImage 软删单张走秀图片(审核阶段剔除坏图),并按实际存活**主图**行数重算 image_count。
|
||||
SoftDeleteRunwayImage(ctx context.Context, recordID, imgID uint32) error
|
||||
// SoftDeleteStreetImage 软删单张街拍图片,并同步 image_count。
|
||||
// SoftDeleteStreetImage 软删单张街拍图片,并按实际存活行数重算 image_count。
|
||||
SoftDeleteStreetImage(ctx context.Context, recordID, imgID uint32) error
|
||||
// AttachStreetSnapImages 把 imgIDs 变成 mainImgID 的副图(批量并入)。
|
||||
// mainImgID 必须属于同一记录、未被软删、且自身是主图(is_detail=0),否则返回 ErrInvalidImageGroup。
|
||||
@ -139,8 +140,11 @@ func (r *reviewRepository) UpdateRecord(ctx context.Context, id uint32, fields m
|
||||
Updates(clean).Error
|
||||
}
|
||||
|
||||
// SetRecordStatus 命中 0 行说明记录不存在,返回 ErrNotFound。
|
||||
// 否则「对不存在的 id 通过 / 驳回」会被当作成功:handler 只校验 id != 0,id 又来自 URL,
|
||||
// 竞态窗口(记录刚被删除)下会给出假成功 302。
|
||||
func (r *reviewRepository) SetRecordStatus(ctx context.Context, id uint32, status, reviewer, reason string) error {
|
||||
return r.db.WithContext(ctx).
|
||||
res := r.db.WithContext(ctx).
|
||||
Model(&model.BrandRunway{}).
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
@ -148,7 +152,14 @@ func (r *reviewRepository) SetRecordStatus(ctx context.Context, id uint32, statu
|
||||
"reviewer": reviewer,
|
||||
"reject_reason": reason,
|
||||
"updated_at": uint32(time.Now().Unix()),
|
||||
}).Error
|
||||
})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountByStatus 统计传入表(dest 零值指针)中指定状态的行数;供各 ReviewModule 复用。
|
||||
@ -238,8 +249,9 @@ func (r *reviewRepository) UpdateStreetRecord(ctx context.Context, id uint32, fi
|
||||
Updates(clean).Error
|
||||
}
|
||||
|
||||
// SetStreetRecordStatus 命中 0 行说明记录不存在,返回 ErrNotFound(理由同 SetRecordStatus)。
|
||||
func (r *reviewRepository) SetStreetRecordStatus(ctx context.Context, id uint32, status, reviewer, reason string) error {
|
||||
return r.db.WithContext(ctx).
|
||||
res := r.db.WithContext(ctx).
|
||||
Model(&model.StreetSnap{}).
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]any{
|
||||
@ -247,13 +259,29 @@ func (r *reviewRepository) SetStreetRecordStatus(ctx context.Context, id uint32,
|
||||
"reviewer": reviewer,
|
||||
"reject_reason": reason,
|
||||
"updated_at": uint32(time.Now().Unix()),
|
||||
}).Error
|
||||
})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ── 图片软删 ────────────────────────────────────────────────────────────────
|
||||
|
||||
// SoftDeleteRunwayImage 软删单张走秀图片(审核阶段剔除坏图),并同步记录 image_count。
|
||||
// SoftDeleteRunwayImage 软删单张走秀图片(审核阶段剔除坏图),按实际存活主图行数重算 image_count。
|
||||
// 不删S4文件(与正式表既有删除行为一致:仅 DB 标记,避免误删被引用文件)。
|
||||
//
|
||||
// 为什么是「重算」而不是「递减 image_count - 1」:递减的前提是「本次调用必然删掉一行」,
|
||||
// 而 imgID 完全来自 URL 路径、没有归属校验 —— 过期页面 / 重复提交 / 跨记录的重放都会命中 0 行,
|
||||
// GORM 不报错,递减却照常执行,于是只减计数不删图(GREATEST 只钳到 0、永不回补)。
|
||||
// 旧流程靠审核通过时按实际图片行重算能抹平这种漂移;单表发布模型删掉了晋升重建,
|
||||
// 漂移会永久固化在已发布记录上,并直接显示在公开列表卡片的「N 张」角标里。
|
||||
//
|
||||
// 口径与入库一致:只计主图(is_detail = 0)——见 ingest_service.processRunway 的 imageCount = len(p.Looks),
|
||||
// 以及旧 SaveRunwayFromDraft 的 mainCount。细节图不计入。
|
||||
func (r *reviewRepository) SoftDeleteRunwayImage(ctx context.Context, recordID, imgID uint32) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&model.BrandRunwayImage{}).
|
||||
@ -262,10 +290,16 @@ func (r *reviewRepository) SoftDeleteRunwayImage(ctx context.Context, recordID,
|
||||
return err
|
||||
}
|
||||
return r.db.WithContext(ctx).
|
||||
Exec("UPDATE brand_runways SET image_count = GREATEST(image_count - 1, 0) WHERE id = ?", recordID).Error
|
||||
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 = ?`, recordID, recordID).Error
|
||||
}
|
||||
|
||||
// SoftDeleteStreetImage 软删单张街拍图片,并同步记录 image_count。
|
||||
// SoftDeleteStreetImage 软删单张街拍图片,按实际存活行数重算 image_count(理由同 SoftDeleteRunwayImage)。
|
||||
//
|
||||
// 口径与街拍正式表的历史行为一致:计全部存活图片行(主图 + 副图),
|
||||
// 见旧 SaveStreetSnapFromDraft 的 image_count = len(imgs);街拍副图是审核期人工并入的,
|
||||
// 与走秀「is_detail 是入库时的细节图」语义不同。
|
||||
func (r *reviewRepository) SoftDeleteStreetImage(ctx context.Context, recordID, imgID uint32) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&model.StreetSnapImage{}).
|
||||
@ -274,7 +308,9 @@ func (r *reviewRepository) SoftDeleteStreetImage(ctx context.Context, recordID,
|
||||
return err
|
||||
}
|
||||
return r.db.WithContext(ctx).
|
||||
Exec("UPDATE street_snaps SET image_count = GREATEST(image_count - 1, 0) WHERE id = ?", recordID).Error
|
||||
Exec(`UPDATE street_snaps SET image_count =
|
||||
(SELECT COUNT(*) FROM street_snap_images WHERE snap_id = ? AND is_deleted = 0)
|
||||
WHERE id = ?`, recordID, recordID).Error
|
||||
}
|
||||
|
||||
// GetImageKey 取单张图片的S4 key(删除前清理用);不存在返回空串。
|
||||
|
||||
Reference in New Issue
Block a user