feat(moderation): 帖评删除占位感知与硬删清场

管理删帖须填类型与理由并展示专用页;评论软删占位、版主可硬删不占楼。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 07:01:04 +08:00
parent 2b27703e6c
commit bcb4f6a603
15 changed files with 825 additions and 116 deletions

View File

@@ -303,16 +303,38 @@ func (s *ModerationService) loadCommentUnscoped(actor *Actor, id uint) (*model.C
return &cm, post.BoardID, nil
}
// SoftDeletePost 软删帖子(未删除时)
func (s *ModerationService) SoftDeletePost(actor *Actor, id uint) error {
// SoftDeletePost 软删帖子(未删除时);须填写删除类型与理由,并通知作者
func (s *ModerationService) SoftDeletePost(actor *Actor, id uint, deleteType, deleteReason string) (authorID uint, err error) {
post, err := s.loadPostUnscoped(actor, id)
if err != nil {
return err
return 0, err
}
if post.DeletedAt.Valid {
return errors.New("帖子已在回收站")
return 0, errors.New("帖子已在回收站")
}
return s.db.Delete(post).Error
deleteType = strings.TrimSpace(deleteType)
deleteReason = strings.TrimSpace(deleteReason)
if !model.ValidPostDeleteType(deleteType) {
return 0, errors.New("无效的删除类型")
}
if deleteReason == "" {
return 0, errors.New("请填写删除理由")
}
if len([]rune(deleteReason)) > 200 {
return 0, errors.New("删除理由不能超过 200 字")
}
updates := map[string]interface{}{
"delete_type": deleteType,
"delete_reason": deleteReason,
"deleted_by": actor.ID,
}
if err := s.db.Model(post).Updates(updates).Error; err != nil {
return 0, err
}
if err := s.db.Delete(post).Error; err != nil {
return 0, err
}
return post.UserID, nil
}
// RestorePost 从回收站恢复帖子