2025-11-17 14:11:46 +08:00
|
|
|
|
package repository
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
"dianshang/internal/model"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type CommentRepository struct {
|
|
|
|
|
|
db *gorm.DB
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewCommentRepository(db *gorm.DB) *CommentRepository {
|
|
|
|
|
|
return &CommentRepository{db: db}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create 创建评论
|
|
|
|
|
|
func (r *CommentRepository) Create(comment *model.Comment) error {
|
|
|
|
|
|
return r.db.Create(comment).Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetByID 根据ID获取评论
|
|
|
|
|
|
func (r *CommentRepository) GetByID(id uint) (*model.Comment, error) {
|
|
|
|
|
|
var comment model.Comment
|
|
|
|
|
|
err := r.db.Preload("User").Preload("Product").Preload("Order").Preload("Replies.User").First(&comment, id).Error
|
|
|
|
|
|
return &comment, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetByProductID 根据商品ID获取评论列表
|
|
|
|
|
|
func (r *CommentRepository) GetByProductID(productID uint, offset, limit int, rating int) ([]model.Comment, int64, error) {
|
|
|
|
|
|
var comments []model.Comment
|
|
|
|
|
|
var total int64
|
|
|
|
|
|
|
|
|
|
|
|
query := r.db.Model(&model.Comment{}).Where("product_id = ? AND status = ?", productID, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 按评分筛选
|
|
|
|
|
|
if rating > 0 && rating <= 5 {
|
|
|
|
|
|
query = query.Where("rating = ?", rating)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取总数
|
|
|
|
|
|
if err := query.Count(&total).Error; err != nil {
|
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取评论列表
|
|
|
|
|
|
err := query.Preload("User").Preload("Replies", "status = ?", 1).Preload("Replies.User").
|
|
|
|
|
|
Order("created_at DESC").Offset(offset).Limit(limit).Find(&comments).Error
|
|
|
|
|
|
|
|
|
|
|
|
return comments, total, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetByUserID 根据用户ID获取评论列表
|
|
|
|
|
|
func (r *CommentRepository) GetByUserID(userID uint, offset, limit int) ([]model.Comment, int64, error) {
|
|
|
|
|
|
var comments []model.Comment
|
|
|
|
|
|
var total int64
|
|
|
|
|
|
|
|
|
|
|
|
query := r.db.Model(&model.Comment{}).Where("user_id = ? AND status = ?", userID, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取总数
|
|
|
|
|
|
if err := query.Count(&total).Error; err != nil {
|
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取评论列表
|
|
|
|
|
|
err := query.Preload("Product").Preload("Replies", "status = ?", 1).Preload("Replies.User").
|
|
|
|
|
|
Order("created_at DESC").Offset(offset).Limit(limit).Find(&comments).Error
|
|
|
|
|
|
|
|
|
|
|
|
return comments, total, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetByOrderItemID 根据订单项ID获取评论
|
|
|
|
|
|
func (r *CommentRepository) GetByOrderItemID(orderItemID uint) (*model.Comment, error) {
|
|
|
|
|
|
var comment model.Comment
|
|
|
|
|
|
err := r.db.Where("order_item_id = ? AND status = ?", orderItemID, 1).First(&comment).Error
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
return &comment, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Update 更新评论
|
|
|
|
|
|
func (r *CommentRepository) Update(comment *model.Comment) error {
|
|
|
|
|
|
return r.db.Save(comment).Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete 删除评论(软删除)
|
|
|
|
|
|
func (r *CommentRepository) Delete(id uint) error {
|
|
|
|
|
|
return r.db.Model(&model.Comment{}).Where("id = ?", id).Update("status", 3).Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetStats 获取商品评论统计
|
|
|
|
|
|
func (r *CommentRepository) GetStats(productID uint) (*model.CommentStats, error) {
|
|
|
|
|
|
var stats model.CommentStats
|
|
|
|
|
|
stats.ProductID = productID
|
|
|
|
|
|
|
|
|
|
|
|
// 获取总评论数和平均评分
|
|
|
|
|
|
err := r.db.Model(&model.Comment{}).
|
|
|
|
|
|
Select("COUNT(*) as total_count, AVG(rating) as average_rating").
|
|
|
|
|
|
Where("product_id = ? AND status = ?", productID, 1).
|
|
|
|
|
|
Scan(&stats).Error
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取各星级评论数
|
|
|
|
|
|
var ratingCounts []struct {
|
|
|
|
|
|
Rating int `json:"rating"`
|
|
|
|
|
|
Count int `json:"count"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err = r.db.Model(&model.Comment{}).
|
|
|
|
|
|
Select("rating, COUNT(*) as count").
|
|
|
|
|
|
Where("product_id = ? AND status = ?", productID, 1).
|
|
|
|
|
|
Group("rating").
|
|
|
|
|
|
Scan(&ratingCounts).Error
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 填充各星级评论数
|
|
|
|
|
|
for _, rc := range ratingCounts {
|
|
|
|
|
|
switch rc.Rating {
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
stats.Rating1Count = rc.Count
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
stats.Rating2Count = rc.Count
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
stats.Rating3Count = rc.Count
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
stats.Rating4Count = rc.Count
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
stats.Rating5Count = rc.Count
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取带图评论数
|
|
|
|
|
|
var hasImagesCount int64
|
|
|
|
|
|
err = r.db.Model(&model.Comment{}).
|
|
|
|
|
|
Where("product_id = ? AND status = ? AND images != '' AND images != '[]'", productID, 1).
|
|
|
|
|
|
Count(&hasImagesCount).Error
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
stats.HasImagesCount = int(hasImagesCount)
|
|
|
|
|
|
|
|
|
|
|
|
return &stats, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetList 获取评论列表(管理端使用)
|
|
|
|
|
|
func (r *CommentRepository) GetList(offset, limit int, conditions map[string]interface{}) ([]model.Comment, int64, error) {
|
|
|
|
|
|
var comments []model.Comment
|
|
|
|
|
|
var total int64
|
|
|
|
|
|
|
|
|
|
|
|
query := r.db.Model(&model.Comment{})
|
|
|
|
|
|
|
|
|
|
|
|
// 添加查询条件
|
|
|
|
|
|
for key, value := range conditions {
|
|
|
|
|
|
switch key {
|
|
|
|
|
|
case "product_id":
|
|
|
|
|
|
query = query.Where("product_id = ?", value)
|
|
|
|
|
|
case "user_id":
|
|
|
|
|
|
query = query.Where("user_id = ?", value)
|
|
|
|
|
|
case "rating":
|
|
|
|
|
|
query = query.Where("rating = ?", value)
|
|
|
|
|
|
case "status":
|
|
|
|
|
|
query = query.Where("status = ?", value)
|
|
|
|
|
|
case "keyword":
|
|
|
|
|
|
query = query.Where("content LIKE ?", "%"+value.(string)+"%")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取总数
|
|
|
|
|
|
if err := query.Count(&total).Error; err != nil {
|
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取评论列表
|
|
|
|
|
|
err := query.Preload("User").Preload("Product").Preload("Order").
|
|
|
|
|
|
Order("created_at DESC").Offset(offset).Limit(limit).Find(&comments).Error
|
|
|
|
|
|
|
|
|
|
|
|
return comments, total, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CreateReply 创建评论回复
|
|
|
|
|
|
func (r *CommentRepository) CreateReply(reply *model.CommentReply) error {
|
|
|
|
|
|
tx := r.db.Begin()
|
|
|
|
|
|
|
|
|
|
|
|
// 创建回复
|
|
|
|
|
|
if err := tx.Create(reply).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新评论回复数量
|
|
|
|
|
|
if err := tx.Model(&model.Comment{}).Where("id = ?", reply.CommentID).
|
|
|
|
|
|
UpdateColumn("reply_count", gorm.Expr("reply_count + ?", 1)).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tx.Commit().Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-28 15:18:10 +08:00
|
|
|
|
// GetHighRatingComments 获取高分评论(用于首页展示)
|
|
|
|
|
|
func (r *CommentRepository) GetHighRatingComments(limit int, minRating int) ([]model.Comment, error) {
|
|
|
|
|
|
var comments []model.Comment
|
|
|
|
|
|
|
|
|
|
|
|
// 获取评分>=minRating的评论,按评分降序、创建时间降序排列
|
|
|
|
|
|
err := r.db.Model(&model.Comment{}).
|
|
|
|
|
|
Where("status = ? AND rating >= ?", 1, minRating).
|
|
|
|
|
|
Preload("User").
|
|
|
|
|
|
Preload("Product").
|
|
|
|
|
|
Order("rating DESC, created_at DESC").
|
|
|
|
|
|
Limit(limit).
|
|
|
|
|
|
Find(&comments).Error
|
|
|
|
|
|
|
|
|
|
|
|
return comments, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 14:11:46 +08:00
|
|
|
|
// GetReplies 获取评论回复列表
|
|
|
|
|
|
func (r *CommentRepository) GetReplies(commentID uint) ([]model.CommentReply, error) {
|
|
|
|
|
|
var replies []model.CommentReply
|
|
|
|
|
|
err := r.db.Where("comment_id = ? AND status = ?", commentID, 1).
|
|
|
|
|
|
Preload("User").Order("created_at ASC").Find(&replies).Error
|
|
|
|
|
|
return replies, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LikeComment 点赞评论
|
|
|
|
|
|
func (r *CommentRepository) LikeComment(commentID, userID uint) error {
|
|
|
|
|
|
tx := r.db.Begin()
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已点赞
|
|
|
|
|
|
var count int64
|
|
|
|
|
|
if err := tx.Model(&model.CommentLike{}).Where("comment_id = ? AND user_id = ?", commentID, userID).Count(&count).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if count > 0 {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return fmt.Errorf("已经点赞过了")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建点赞记录
|
|
|
|
|
|
like := &model.CommentLike{
|
|
|
|
|
|
CommentID: commentID,
|
|
|
|
|
|
UserID: userID,
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := tx.Create(like).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新评论点赞数量
|
|
|
|
|
|
if err := tx.Model(&model.Comment{}).Where("id = ?", commentID).
|
|
|
|
|
|
UpdateColumn("like_count", gorm.Expr("like_count + ?", 1)).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tx.Commit().Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UnlikeComment 取消点赞评论
|
|
|
|
|
|
func (r *CommentRepository) UnlikeComment(commentID, userID uint) error {
|
|
|
|
|
|
tx := r.db.Begin()
|
|
|
|
|
|
|
|
|
|
|
|
// 删除点赞记录
|
|
|
|
|
|
if err := tx.Where("comment_id = ? AND user_id = ?", commentID, userID).Delete(&model.CommentLike{}).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新评论点赞数量
|
|
|
|
|
|
if err := tx.Model(&model.Comment{}).Where("id = ?", commentID).
|
|
|
|
|
|
UpdateColumn("like_count", gorm.Expr("like_count - ?", 1)).Error; err != nil {
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tx.Commit().Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateProductStats 更新商品评论统计
|
|
|
|
|
|
func (r *CommentRepository) UpdateProductStats(productID uint) error {
|
|
|
|
|
|
var stats struct {
|
|
|
|
|
|
Count int `json:"count"`
|
|
|
|
|
|
Rating float64 `json:"rating"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err := r.db.Model(&model.Comment{}).
|
|
|
|
|
|
Select("COUNT(*) as count, AVG(rating) as rating").
|
|
|
|
|
|
Where("product_id = ? AND status = ?", productID, 1).
|
|
|
|
|
|
Scan(&stats).Error
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return r.db.Model(&model.Product{}).Where("id = ?", productID).
|
|
|
|
|
|
Updates(map[string]interface{}{
|
|
|
|
|
|
"comment_count": stats.Count,
|
|
|
|
|
|
"average_rating": stats.Rating,
|
|
|
|
|
|
}).Error
|
|
|
|
|
|
}
|