This commit is contained in:
2026-09-15 16:02:45 +08:00
parent 112c5f8e46
commit ade2453083
70 changed files with 1441 additions and 707 deletions
+28 -3
View File
@@ -222,10 +222,24 @@ func (s *ClothesService) processImageAsync(parentCtx context.Context, userID int
"fail_reason": "",
"original_image_path": "",
}
if uerr := dao.ClothesUpdateByUUID(ctx, clothesUUID, updates); uerr != nil {
// 带状态守卫回填:恢复任务可能已把该记录置为失败并回退了额度,
// 此时若无条件写回成功,会出现「额度已退但衣物成功」(白送额度)并残留 COS 对象。
ok, uerr := dao.ClothesUpdateByUUIDIfStatusIn(ctx, clothesUUID,
[]int8{ImageProcessMatting, ImageProcessClassifying, ImageProcessQueuing}, updates)
if uerr != nil {
slog.ErrorContext(ctx, "update clothes after classify failed", "clothes_uuid", clothesUUID, "error", uerr)
return
}
if !ok {
// 记录已被置失败或已删除:本次结果作废,清理刚上传的 COS 对象避免孤儿。
slog.WarnContext(ctx, "clothes no longer processing, discard result",
"clothes_uuid", clothesUUID, "cos_key", cosKey)
if derr := upload.FileDeleteCos(ctx, cosKey); derr != nil {
slog.ErrorContext(ctx, "delete discarded cos image failed",
"clothes_uuid", clothesUUID, "cos_key", cosKey, "error", derr)
}
return
}
_ = os.Remove(originalPath)
}
@@ -370,8 +384,8 @@ func (s *ClothesService) assertClothesVisibleViaOutfitShare(ctx context.Context,
}
return errcode.DatabaseError
}
// 访客查看要求穿搭仍公开可见(属主访问自己的分享始终可查看)。
if share.UserID != userID && !isOutfitPublicVisible(outfit) {
// 访客只读查看:分享正常 + 穿搭未被封禁即可(分享与公开状态解耦,属主访问自己的分享始终可查看)。
if share.UserID != userID && outfit.Status == OutfitStatusBanned {
return errcode.OutfitShareNotFound
}
// 该衣物必须属于该分享的穿搭明细。
@@ -433,6 +447,17 @@ func (s *ClothesService) DeleteByUUID(ctx context.Context, userID int64, request
return nil, cerr
}
// 引用校验:已被穿搭明细 / 衣柜分享明细引用的衣物不允许删除,否则会留下悬挂引用,
// 公开穿搭与分享会变成「空壳」(明细里查不到衣物,前端静默跳过),
// 也与接口文档约定的 50001「衣服已被搭配使用,无法删除」保持一致。
refCount, rerr := s.clothesDao.ClothesReferencedCount(ctx, request.ClothesUUID)
if rerr != nil {
return nil, errcode.DatabaseError
}
if refCount > 0 {
return nil, errcode.ClothesInUse
}
// 事务内锁定衣物行 -> 读最新状态 -> 软删除 -> 条件回退额度 -> 写回退流水,
// 数值变更与流水同事务强一致,并避免与异步处理失败回退并发导致漏退/双退。
vipExpire := getUserVIPExpire(ctx, userID)