feat: 评论/帖子编辑历史与编辑标记,内容锁定

- 新增 smartDiff 差异计算与 EditHistoryModal 编辑历史弹窗,替换原 CommentEditHistoryModal
- 新增 PostEditedMark 编辑标记展示
- 新增内容锁定机制(content_lock)防止并发编辑冲突
- 审核与通知服务适配
This commit is contained in:
2026-09-25 23:41:45 +08:00
parent cab8230803
commit 5270fee2b7
40 changed files with 2521 additions and 350 deletions

View File

@@ -68,6 +68,11 @@ type updateSettingsRequest struct {
PointsReplyDailyCap *int `json:"points_reply_daily_cap"`
PointsRecommendReward *int `json:"points_recommend_reward"`
PostEditLockHours *int `json:"post_edit_lock_hours"`
CommentEditLockHours *int `json:"comment_edit_lock_hours"`
NecroReplyAfterHours *int `json:"necro_reply_after_hours"`
NecroReplyPenalty *int `json:"necro_reply_penalty"`
Levels *[]model.LevelDef `json:"levels"`
LevelsFx *bool `json:"levels_fx"`
}
@@ -120,6 +125,11 @@ func settingsPayload(saved service.PublicSiteSettings) gin.H {
"points_reply_daily_cap": saved.PointsReplyDailyCap,
"points_recommend_reward": saved.PointsRecommendReward,
"post_edit_lock_hours": saved.PostEditLockHours,
"comment_edit_lock_hours": saved.CommentEditLockHours,
"necro_reply_after_hours": saved.NecroReplyAfterHours,
"necro_reply_penalty": saved.NecroReplyPenalty,
"levels": saved.Levels,
"levels_fx": saved.LevelsFx,
}
@@ -142,7 +152,9 @@ func (req *updateSettingsRequest) hasAny() bool {
req.PointsCheckinBase != nil || req.PointsStreakEveryDays != nil || req.PointsStreakBonus != nil ||
req.PointsPostReward != nil || req.PointsPostDailyCap != nil ||
req.PointsReplyReward != nil || req.PointsReplyDailyCap != nil ||
req.PointsRecommendReward != nil || req.Levels != nil || req.LevelsFx != nil
req.PointsRecommendReward != nil || req.Levels != nil || req.LevelsFx != nil ||
req.PostEditLockHours != nil || req.CommentEditLockHours != nil ||
req.NecroReplyAfterHours != nil || req.NecroReplyPenalty != nil
}
// AdminGetSettings 超管读取站点设置(与公开 payload 字段一致)
@@ -247,6 +259,29 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
return
}
}
lockRules := []struct {
req *int
set func(int) error
hint string
}{
{req.PostEditLockHours, h.Setting.SetPostEditLockHours, "帖子可编辑时长须为 0–8760 小时"},
{req.CommentEditLockHours, h.Setting.SetCommentEditLockHours, "评论可编辑时长须为 0–8760 小时"},
{req.NecroReplyAfterHours, h.Setting.SetNecroReplyAfterHours, "旧帖回复阈值须为 0–8760 小时"},
{req.NecroReplyPenalty, h.Setting.SetNecroReplyPenalty, "旧帖回复扣分须为 0–100"},
}
for _, r := range lockRules {
if r.req == nil {
continue
}
if err := r.set(*r.req); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": r.hint})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
pointsRules := []struct {
req *int
set func(int) error