package model import ( "context" "encoding/json" "fmt" "time" "github.com/go-redis/redis/v8" "gorm.io/gorm" ) const ( prefixCommentListKey = "comment:list:%d:%d:%d" // postId:page:pageSize prefixCommentKey = "comment:%d" // commentId prefixReplyListKey = "reply:list:%d" // commentId prefixCommentUpvoteKey = "comment:upvote:%d:%d" // userId:commentId ) // PComment 评论 type Comment struct { *Model PostId int64 `json:"post_id" gorm:"post_id"` // POST ID UserId int64 `json:"user_id" gorm:"user_id"` // 用户ID Ip string `json:"ip" gorm:"ip"` // IP地址 IpLoc string `json:"ip_loc" gorm:"ip_loc"` // IP城市地址 Content string `json:"content" gorm:"content"` // 评论内容 Image string `json:"image" gorm:"image"` // 评论图片 WithUserIds string `json:"with_user_ids" gorm:"with_user_ids"` // 被艾特的用户 IsEssence int8 `json:"is_essence" gorm:"is_essence"` // 是否精选 ReplyCount int64 `json:"reply_count" gorm:"reply_count"` // 回复数 ThumbsUpCount int64 `json:"thumbs_up_count" gorm:"thumbs_up_count"` // 点赞数 } // TableName 表名称 func (*Comment) TableName() string { return "p_comment" } type CommentModel struct { conn *gorm.DB redis *redis.Client } func NewCommentModel(conn *gorm.DB, rdb *redis.Client) *CommentModel { return &CommentModel{ conn: conn, redis: rdb, } } // GetCommentList 获取评论列表(带缓存) func (m *CommentModel) GetCommentList(ctx context.Context, postId int64, page, pageSize int) ([]*Comment, error) { // 尝试从缓存获取 key := fmt.Sprintf(prefixCommentListKey, postId, page, pageSize) data, err := m.redis.Get(ctx, key).Bytes() if err == nil { var comments []*Comment if err := json.Unmarshal(data, &comments); err == nil { return comments, nil } } // 从数据库获取 var comments []*Comment offset := (page - 1) * pageSize err = m.conn.WithContext(ctx). Where("post_id = ? AND parent_id = 0", postId). Order("created_on DESC"). Offset(offset). Limit(pageSize). Find(&comments).Error if err != nil { return nil, err } // 写入缓存 if data, err := json.Marshal(comments); err == nil { m.redis.Set(ctx, key, data, 5*time.Minute) // 评论列表缓存时间较短 } return comments, nil } // GetLatestReplies 获取最新的N条回复(带缓存) func (m *CommentModel) GetLatestReplies(ctx context.Context, commentId int64, limit int) ([]*Comment, error) { // 尝试从缓存获取 key := fmt.Sprintf(prefixReplyListKey, commentId) data, err := m.redis.Get(ctx, key).Bytes() if err == nil { var replies []*Comment if err := json.Unmarshal(data, &replies); err == nil { return replies, nil } } // 从数据库获取 var replies []*Comment err = m.conn.WithContext(ctx). Where("parent_id = ?", commentId). Order("created_on DESC"). Limit(limit). Find(&replies).Error if err != nil { return nil, err } // 写入缓存 if data, err := json.Marshal(replies); err == nil { m.redis.Set(ctx, key, data, 5*time.Minute) } return replies, nil } // IsCommentUpvotedByUser 检查用户是否点赞了评论/回复(带缓存) func (m *CommentModel) IsCommentUpvotedByUser(ctx context.Context, userId, commentId int64) (bool, error) { // 尝试从缓存获取 key := fmt.Sprintf(prefixCommentUpvoteKey, userId, commentId) exists, err := m.redis.Exists(ctx, key).Result() if err == nil && exists == 1 { return m.redis.Get(ctx, key).Bool() } // 从数据库获取 var count int64 err = m.conn.WithContext(ctx).Model(&CommentUpvote{}). Where("user_id = ? AND comment_id = ? AND is_del = 0", userId, commentId). Count(&count).Error if err != nil { return false, err } // 写入缓存 isUpvoted := count > 0 m.redis.Set(ctx, key, isUpvoted, cacheExpiry) return isUpvoted, nil } // GetReplyList 获取回复列表(带缓存) func (m *CommentModel) GetReplyList(ctx context.Context, commentId int64, page, pageSize int) ([]*Comment, error) { // 尝试从缓存获取 key := fmt.Sprintf(prefixReplyListKey+":%d:%d", commentId, page, pageSize) data, err := m.redis.Get(ctx, key).Bytes() if err == nil { var replies []*Comment if err := json.Unmarshal(data, &replies); err == nil { return replies, nil } } // 从数据库获取 var replies []*Comment offset := (page - 1) * pageSize err = m.conn.WithContext(ctx). Where("parent_id = ?", commentId). Order("created_on DESC"). Offset(offset). Limit(pageSize). Find(&replies).Error if err != nil { return nil, err } // 写入缓存 if data, err := json.Marshal(replies); err == nil { m.redis.Set(ctx, key, data, 5*time.Minute) // 回复列表缓存时间较短 } return replies, nil } // Create 创建评论 func (m *CommentModel) Create(ctx context.Context, comment *Comment) error { err := m.conn.WithContext(ctx).Create(comment).Error if err != nil { return err } // 删除相关缓存 m.ClearCommentListCache(ctx, comment.PostId) return nil } // ClearCommentListCache 清除评论列表缓存 func (m *CommentModel) ClearCommentListCache(ctx context.Context, postId int64) error { // 清除评论列表缓存 pattern := fmt.Sprintf("comment:list:%d*", postId) keys, err := m.redis.Keys(ctx, pattern).Result() if err != nil { return err } if len(keys) > 0 { m.redis.Del(ctx, keys...) } // 清除回复列表缓存 pattern = fmt.Sprintf(prefixReplyListKey+"*", postId) keys, err = m.redis.Keys(ctx, pattern).Result() if err != nil { return err } if len(keys) > 0 { m.redis.Del(ctx, keys...) } return nil } // IncrementUpvoteCount 增加点赞数 func (m *CommentModel) IncrementUpvoteCount(ctx context.Context, commentId int64, increment int) error { err := m.conn.WithContext(ctx).Model(&Comment{}). Where("id = ?", commentId). UpdateColumn("thumbs_up_count", gorm.Expr("thumbs_up_count + ?", increment)).Error if err != nil { return err } // 删除评论缓存 key := fmt.Sprintf(prefixCommentKey, commentId) m.redis.Del(ctx, key) return nil } // CreateCommentUpvote 创建评论点赞记录 func (m *CommentModel) CreateCommentUpvote(ctx context.Context, upvote *CommentUpvote) error { err := m.conn.WithContext(ctx).Create(upvote).Error if err != nil { return err } // 删除点赞状态缓存 key := fmt.Sprintf(prefixCommentUpvoteKey, upvote.UserId, upvote.CommentId) m.redis.Del(ctx, key) return nil } // DeleteCommentUpvote 删除评论点赞记录 func (m *CommentModel) DeleteCommentUpvote(ctx context.Context, userId, commentId int64) error { err := m.conn.WithContext(ctx).Model(&CommentUpvote{}). Where("user_id = ? AND comment_id = ?", userId, commentId). Update("is_del", 1).Error if err != nil { return err } // 删除点赞状态缓存 key := fmt.Sprintf(prefixCommentUpvoteKey, userId, commentId) m.redis.Del(ctx, key) return nil } // 获取评论 func (m *CommentModel) GetComment(ctx context.Context, commentId int64) (*Comment, error) { var comment Comment err := m.conn.WithContext(ctx).Where("id = ?", commentId).First(&comment).Error if err != nil { return nil, err } return &comment, nil } // IncrementReplyCount 增加回复数 func (m *CommentModel) IncrementReplyCount(ctx context.Context, commentId int64, increment int) error { err := m.conn.WithContext(ctx).Model(&Comment{}). Where("id = ?", commentId). UpdateColumn("reply_count", gorm.Expr("reply_count + ?", increment)).Error if err != nil { return err } // 删除评论缓存 key := fmt.Sprintf(prefixCommentKey, commentId) m.redis.Del(ctx, key) return nil } // Delete 删除评论 func (m *CommentModel) Delete(ctx context.Context, commentId int64) error { return m.conn.WithContext(ctx).Model(&Comment{}). Where("id = ?", commentId). Updates(map[string]interface{}{ "is_del": 1, "deleted_on": time.Now().Unix(), "modified_on": time.Now().Unix(), }).Error }