feat: 新增文章阅读量计数(已登录去重 + 访客防刷)
- Post 模型新增 ViewsCount 冗余计数字段 - 新建 PostReadLog 表(user_id + post_id 唯一索引),已登录用户每篇文章只计一次 - 新建 PostGuestReadLog 表(visitor_id + post_id 唯一索引),访客基于 Cookie 标识去重 - Repository 层新增 RecordRead / RecordGuestRead / IncrementViewsCount - Service 层编排去重-计数逻辑,计数失败不影响页面渲染 - Controller 层 ShowPage + ShowAPI 触发计数,仅 approved 状态生效 - 双层防刷:唯一索引去重 + 2 秒冷却间隔 - 访客 Cookie (visitor_id) 基于 crypto/rand 生成,30 天有效期
This commit is contained in:
@ -25,6 +25,7 @@ type Post struct {
|
||||
LikesCount int `gorm:"default:0" json:"likes_count"` // 点赞数(冗余计数器)
|
||||
DislikesCount int `gorm:"default:0" json:"dislikes_count"` // 踩数(冗余计数器,仅后台可见)
|
||||
FavoritesCount int `gorm:"default:0" json:"favorites_count"` // 收藏数(冗余计数器)
|
||||
ViewsCount int `gorm:"default:0" json:"views_count"` // 阅读数(冗余计数器,已登录去重)
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
20
internal/model/post_read_log.go
Normal file
20
internal/model/post_read_log.go
Normal file
@ -0,0 +1,20 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// PostReadLog 文章阅读记录(已登录用户每篇文章只记录一次)
|
||||
type PostReadLog struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
UserID uint `gorm:"uniqueIndex:idx_user_post_read;not null" json:"user_id"`
|
||||
PostID uint `gorm:"uniqueIndex:idx_user_post_read;not null" json:"post_id"`
|
||||
ReadAt time.Time `gorm:"autoCreateTime" json:"read_at"`
|
||||
}
|
||||
|
||||
// PostGuestReadLog 访客阅读记录(未登录用户,基于 Cookie 标识去重)
|
||||
type PostGuestReadLog struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
VisitorID string `gorm:"uniqueIndex:idx_visitor_post_read;type:varchar(64);not null" json:"visitor_id"`
|
||||
PostID uint `gorm:"uniqueIndex:idx_visitor_post_read;not null" json:"post_id"`
|
||||
ReadAt time.Time `gorm:"autoCreateTime" json:"read_at"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user