移除旧版 HTML 模板与兼容层,并完善私信、举报、媒体存储与 SEO。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-03 16:37:11 +08:00
parent 060b7707cb
commit 48db333272
121 changed files with 11147 additions and 3225 deletions

View File

@@ -14,6 +14,13 @@ const (
RoleAdmin Role = "admin"
)
// 内容审核状态(帖子 / 评论)
const (
ContentStatusPending = "pending" // 审核中(仅作者与管理员可见)
ContentStatusPublished = "published" // 已公开
ContentStatusRejected = "rejected" // 未通过(仅作者与管理员可见)
)
// User 用户表
// Email / Password / LastLogin* 默认不随帖子等嵌套 User 序列化;
// 个人中心与后台列表请用 UserSelf / UserAdmin。
@@ -24,7 +31,7 @@ type User struct {
Password string `gorm:"size:128;not null" json:"-"`
Nickname string `gorm:"size:64" json:"nickname"`
Signature string `gorm:"size:512;default:''" json:"signature"` // 个人签名
Avatar string `gorm:"size:256" json:"avatar"`
Avatar string `gorm:"size:512" json:"avatar"` // 兼容 CDN / S3 较长绝对 URL
Role Role `gorm:"size:16;default:user" json:"role"`
Banned bool `gorm:"default:false" json:"banned"`
BannedAt *time.Time `json:"banned_at,omitempty"`
@@ -58,7 +65,9 @@ type Post struct {
ContentPlain string `gorm:"type:text" json:"-"` // 正文纯文本,供搜索索引
Tags string `gorm:"size:256" json:"tags"`
Pinned bool `gorm:"default:false" json:"pinned"`
Featured bool `gorm:"default:false;index" json:"featured"` // 精华帖
EditLocked bool `gorm:"default:false" json:"edit_locked"`
Status string `gorm:"size:16;default:published;index" json:"status"` // pending|published|rejected
LikeCount int `gorm:"default:0" json:"like_count"`
ViewCount int `gorm:"default:0" json:"view_count"`
CreatedAt time.Time `json:"created_at"`
@@ -83,6 +92,17 @@ type PostRevision struct {
Editor User `gorm:"foreignKey:EditorID" json:"editor,omitempty"`
}
// CommentRevision 评论编辑历史(每次修改前保存旧版本,管理员可查看)
type CommentRevision struct {
ID uint `gorm:"primaryKey" json:"id"`
CommentID uint `gorm:"index;not null" json:"comment_id"`
EditorID uint `gorm:"index;not null" json:"editor_id"`
Content string `gorm:"type:text;not null" json:"content"`
CreatedAt time.Time `json:"created_at"`
Editor User `gorm:"foreignKey:EditorID" json:"editor,omitempty"`
}
// ForumSetting 论坛全局设置(键值对)
type ForumSetting struct {
Key string `gorm:"primaryKey;size:64" json:"key"`
@@ -101,6 +121,7 @@ type Comment struct {
GuestEmail string `gorm:"size:128" json:"guest_email,omitempty"`
GuestURL string `gorm:"size:256" json:"guest_url,omitempty"`
IsPrivate bool `gorm:"default:false" json:"is_private"`
Status string `gorm:"size:16;default:published;index" json:"status"` // pending|published|rejected
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
@@ -108,7 +129,9 @@ type Comment struct {
User User `gorm:"foreignKey:UserID" json:"user,omitempty"`
Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"`
ReplyTarget *Comment `gorm:"-" json:"reply_target,omitempty"`
ContentHidden bool `gorm:"-" json:"content_hidden"`
// ThreadParentID 嵌套展示用父评论(父评论不可见时回挂到最近可见祖先)
ThreadParentID *uint `gorm:"-" json:"thread_parent_id,omitempty"`
ContentHidden bool `gorm:"-" json:"content_hidden"`
}
// PostLike 帖子点赞
@@ -128,3 +151,76 @@ type PostFavorite struct {
Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"`
}
// 私信类型
const (
MessageKindUser = "user" // 用户互发
MessageKindSystem = "system" // 系统通知
MessageKindReject = "reject" // 帖子被拒/下架
MessageKindReportResult = "report_result" // 举报处理结果
)
// PrivateMessage 站内私信
type PrivateMessage struct {
ID uint `gorm:"primaryKey" json:"id"`
FromUserID uint `gorm:"index;not null" json:"from_user_id"` // 0 表示系统
ToUserID uint `gorm:"index;not null" json:"to_user_id"`
Subject string `gorm:"size:256;not null" json:"subject"`
Content string `gorm:"type:text;not null" json:"content"`
Kind string `gorm:"size:32;default:user;index" json:"kind"`
RelatedPostID *uint `gorm:"index" json:"related_post_id,omitempty"`
RelatedReportID *uint `gorm:"index" json:"related_report_id,omitempty"`
IsRead bool `gorm:"default:false;index" json:"is_read"`
CreatedAt time.Time `json:"created_at"`
FromUser User `gorm:"foreignKey:FromUserID" json:"from_user,omitempty"`
ToUser User `gorm:"foreignKey:ToUserID" json:"to_user,omitempty"`
}
// 举报状态
const (
ReportStatusPending = "pending"
ReportStatusResolved = "resolved"
ReportStatusDismissed = "dismissed"
)
// 举报原因
const (
ReportReasonSpam = "spam"
ReportReasonAbuse = "abuse"
ReportReasonIllegal = "illegal"
ReportReasonIrrelevant = "irrelevant"
ReportReasonOther = "other"
)
// PostReport 帖子举报
type PostReport struct {
ID uint `gorm:"primaryKey" json:"id"`
PostID uint `gorm:"index;not null" json:"post_id"`
ReporterID uint `gorm:"index;not null" json:"reporter_id"`
Reason string `gorm:"size:32;not null" json:"reason"`
Detail string `gorm:"size:1000" json:"detail"`
Status string `gorm:"size:16;default:pending;index" json:"status"`
HandlerID *uint `gorm:"index" json:"handler_id,omitempty"`
HandleNote string `gorm:"size:1000" json:"handle_note"`
CreatedAt time.Time `json:"created_at"`
HandledAt *time.Time `json:"handled_at,omitempty"`
Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"`
Reporter User `gorm:"foreignKey:ReporterID" json:"reporter,omitempty"`
Handler *User `gorm:"foreignKey:HandlerID" json:"handler,omitempty"`
}
// Media 上传媒体索引(真实文件在本地 uploads 或 S3本表供后台列表与统计
type Media struct {
ID uint `gorm:"primaryKey" json:"id"`
Category string `gorm:"size:32;index;not null" json:"category"` // avatars|posts|site
Name string `gorm:"size:255;not null" json:"name"`
URL string `gorm:"size:512;uniqueIndex;not null" json:"url"`
Size int64 `gorm:"not null;default:0" json:"size"`
ContentType string `gorm:"size:64;default:''" json:"content_type"`
StorageType string `gorm:"size:16;index;default:local" json:"storage_type"` // local|s3
UserID *uint `gorm:"index" json:"user_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}