feat: 06 互动与内容治理落地(评论 / 点赞 / 举报 / 敏感词 / 审核留证)

为什么:
1) 产品侧要先把内容治理闭环跑通才能谈上线:评论可发布、可翻页、可删除,
   违规内容能在后台被审核与驳回,举报要有工单可追溯。本提交把这套补齐。
2) 审核不能只靠人肉:敏感词按 BLOCK/REPLACE/REVIEW 三档处置,
   机审通过即发布(可配置为 PRE_REVIEW 全部先审后发),人审与机审的结论
   都写进 content_audit_record,争议时可回答"当时凭什么放行/驳回"。
3) 举报处理必须与处置打通:结论成立会联动驳回被举报评论,并可选同时封禁被举报用户,
   避免"工单处理完了但违规内容还挂着"。
4) 顺带修复一个真实缺陷:user_favorite / content_like 上有唯一索引,而全局配置会把
   deleteById 改写成逻辑删除,导致取消收藏/点赞后旧的 deleted 行仍占位,
   再次收藏或点赞直接撞唯一索引报错。关系类数据没有留证价值,改为显式物理删除,
   并补了"取消后再来一次"的回归自测。
This commit is contained in:
Vicky committed 2026-10-15 12:03:32 +08:00
1 parent b3179fc836
commit af1dc48494
48 files changed
+1752 -14

No files matched your search

@@ -208,6 +208,18 @@ public class DramaService {
return dramaMapper.selectList(Wrappers.<Drama>lambdaQuery().in(Drama::getId, ids));
}
/** 点赞数原子增减:并发下用 SQL 自增,不做读改写,避免丢更新。 */
public void adjustLikeCount(Long dramaId, int delta) {
if (dramaId == null || delta == 0) {
return;
}
dramaMapper.update(null, Wrappers.<Drama>lambdaUpdate()
.eq(Drama::getId, dramaId)
.setSql(delta > 0
? "like_count = like_count + 1"
: "like_count = GREATEST(like_count - 1, 0)"));
}
/** 剧集数量变化后同步冗余字段。 */
public void syncTotalEpisodes(Long dramaId) {
Long count = dramaEpisodeMapper.selectCount(