optimize the list of comments

This commit is contained in:
landaiqing
2024-09-25 11:46:49 +08:00
parent bb2f49fe74
commit 97175c3d67
9 changed files with 333 additions and 99 deletions

View File

@@ -14,6 +14,7 @@ import (
type CommentAPI struct{} type CommentAPI struct{}
var wg sync.WaitGroup var wg sync.WaitGroup
var mx sync.Mutex
var commentReplyService = service.Service.CommentReplyService var commentReplyService = service.Service.CommentReplyService
// CommentImages 评论图片 // CommentImages 评论图片
@@ -42,10 +43,10 @@ type CommentContent struct {
Likes int64 `json:"likes"` Likes int64 `json:"likes"`
ReplyCount int64 `json:"reply_count"` ReplyCount int64 `json:"reply_count"`
CreatedTime time.Time `json:"created_time"` CreatedTime time.Time `json:"created_time"`
Dislikes int64 `json:"dislikes"`
Location string `json:"location"` Location string `json:"location"`
Browser string `json:"browser"` Browser string `json:"browser"`
OperatingSystem string `json:"operating_system"` OperatingSystem string `json:"operating_system"`
IsLiked bool `json:"is_liked" default:"false"`
Images []string `json:"images,omitempty"` Images []string `json:"images,omitempty"`
} }

View File

@@ -3,7 +3,6 @@ package comment_api
import ( import (
"context" "context"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"github.com/acmestack/gorm-plus/gplus" "github.com/acmestack/gorm-plus/gplus"
ginI18n "github.com/gin-contrib/i18n" ginI18n "github.com/gin-contrib/i18n"
@@ -392,63 +391,126 @@ func (CommentAPI) CommentList(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
// 查询评论列表
query, u := gplus.NewQuery[model.ScaCommentReply]() query, u := gplus.NewQuery[model.ScaCommentReply]()
page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size) page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size)
query.Eq(&u.TopicId, commentListRequest.TopicId).Eq(&u.CommentType, enum.COMMENT).OrderByDesc(&u.Likes) query.Eq(&u.TopicId, commentListRequest.TopicId).Eq(&u.CommentType, enum.COMMENT).OrderByDesc(&u.CommentOrder).OrderByDesc(&u.Likes).OrderByDesc(&u.ReplyCount).OrderByDesc(&u.CreatedTime)
page, _ = gplus.SelectPage(page, query) page, pageDB := gplus.SelectPage(page, query)
if pageDB.Error != nil {
global.LOG.Errorln(pageDB.Error)
return
}
if len(page.Records) == 0 {
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
return
}
userIds := make([]string, 0, len(page.Records)) userIds := make([]string, 0, len(page.Records))
commentIds := make([]int64, 0, len(page.Records))
for _, comment := range page.Records { for _, comment := range page.Records {
userIds = append(userIds, comment.UserId) userIds = append(userIds, comment.UserId)
commentIds = append(commentIds, comment.Id)
} }
queryUser, n := gplus.NewQuery[model.ScaAuthUser]() // 结果存储
queryUser.In(&n.UID, userIds) userInfoMap := make(map[string]model.ScaAuthUser)
userInfos, _ := gplus.SelectList(queryUser) likeMap := make(map[int64]bool)
commentImagesMap := make(map[int64]CommentImages)
userInfoMap := make(map[string]model.ScaAuthUser, len(userInfos)) // 使用 WaitGroup 等待协程完成
for _, userInfo := range userInfos { wg.Add(3)
userInfoMap[*userInfo.UID] = *userInfo
}
commentChannel := make(chan CommentContent, len(page.Records)) // 查询评论用户信息
imagesBase64S := make([][]string, len(page.Records)) // 存储每条评论的图片 go func() {
defer wg.Done()
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
queryUser.Select(&n.UID, &n.Avatar, &n.Nickname).In(&n.UID, userIds)
userInfos, userInfosDB := gplus.SelectList(queryUser)
if userInfosDB.Error != nil {
global.LOG.Errorln(userInfosDB.Error)
return
}
for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo
}
}()
for index, comment := range page.Records { // 查询评论点赞状态
wg.Add(1) go func() {
go func(comment model.ScaCommentReply, index int) { defer wg.Done()
defer wg.Done() if len(page.Records) > 0 {
queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
// 使用 context 设置超时时间 queryLike.Eq(&l.TopicId, commentListRequest.TopicId).Eq(&l.UserId, commentListRequest.UserID).In(&l.CommentId, commentIds)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时2秒 likes, likesDB := gplus.SelectList(queryLike)
defer cancel() if likesDB.Error != nil {
global.LOG.Errorln(likesDB.Error)
// 获取评论图片并处理
commentImages := CommentImages{}
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(ctx, bson.M{"comment_id": comment.Id}).Decode(&commentImages)
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
global.LOG.Errorf("Failed to get images for comment ID %s: %v", comment.Id, wrong)
return return
} }
for _, like := range likes {
likeMap[like.CommentId] = true
}
}
}()
// 查询评论图片信息
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时2秒
defer cancel()
cursor, err := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").Find(ctx, bson.M{"comment_id": bson.M{"$in": commentIds}})
if err != nil {
global.LOG.Errorf("Failed to get images for comments: %v", err)
return
}
defer func(cursor *mongo.Cursor, ctx context.Context) {
err := cursor.Close(ctx)
if err != nil {
return
}
}(cursor, ctx)
for cursor.Next(ctx) {
var commentImages CommentImages
if err = cursor.Decode(&commentImages); err != nil {
global.LOG.Errorf("Failed to decode comment images: %v", err)
continue
}
commentImagesMap[commentImages.CommentId] = commentImages
}
}()
// 等待所有查询完成
wg.Wait()
commentChannel := make(chan CommentContent, len(page.Records))
for _, comment := range page.Records {
wg.Add(1)
go func(comment model.ScaCommentReply) {
defer wg.Done()
// 将图片转换为base64 // 将图片转换为base64
var imagesBase64 []string var imagesBase64 []string
for _, img := range commentImages.Images { if imgData, ok := commentImagesMap[comment.Id]; ok {
mimeType := getMimeType(img) // 将图片转换为base64
base64Img := base64.StdEncoding.EncodeToString(img) for _, img := range imgData.Images {
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img) mimeType := getMimeType(img)
imagesBase64 = append(imagesBase64, base64WithPrefix) base64Img := base64.StdEncoding.EncodeToString(img)
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
imagesBase64 = append(imagesBase64, base64WithPrefix)
}
} }
imagesBase64S[index] = imagesBase64 // 保存到切片中
userInfo := userInfoMap[comment.UserId] userInfo, exist := userInfoMap[comment.UserId]
if !exist {
global.LOG.Errorf("Failed to get user info for comment: %s", comment.UserId)
return
}
commentContent := CommentContent{ commentContent := CommentContent{
Avatar: *userInfo.Avatar, Avatar: *userInfo.Avatar,
NickName: *userInfo.Nickname, NickName: *userInfo.Nickname,
Id: comment.Id, Id: comment.Id,
UserId: comment.UserId, UserId: comment.UserId,
TopicId: comment.TopicId, TopicId: comment.TopicId,
Dislikes: comment.Dislikes,
Content: comment.Content, Content: comment.Content,
ReplyCount: comment.ReplyCount, ReplyCount: comment.ReplyCount,
Likes: comment.Likes, Likes: comment.Likes,
@@ -458,9 +520,10 @@ func (CommentAPI) CommentList(c *gin.Context) {
Browser: comment.Browser, Browser: comment.Browser,
OperatingSystem: comment.OperatingSystem, OperatingSystem: comment.OperatingSystem,
Images: imagesBase64, Images: imagesBase64,
IsLiked: likeMap[comment.Id],
} }
commentChannel <- commentContent commentChannel <- commentContent
}(*comment, index) }(*comment)
} }
go func() { go func() {
@@ -500,81 +563,131 @@ func (CommentAPI) ReplyList(c *gin.Context) {
} }
query, u := gplus.NewQuery[model.ScaCommentReply]() query, u := gplus.NewQuery[model.ScaCommentReply]()
page := gplus.NewPage[model.ScaCommentReply](replyListRequest.Page, replyListRequest.Size) page := gplus.NewPage[model.ScaCommentReply](replyListRequest.Page, replyListRequest.Size)
query.Eq(&u.TopicId, replyListRequest.TopicId).Eq(&u.ReplyId, replyListRequest.CommentId).Eq(&u.CommentType, enum.REPLY).OrderByDesc(&u.Likes) query.Eq(&u.TopicId, replyListRequest.TopicId).Eq(&u.ReplyId, replyListRequest.CommentId).Eq(&u.CommentType, enum.REPLY).OrderByDesc(&u.CommentOrder).OrderByDesc(&u.Likes).OrderByDesc(&u.CreatedTime)
page, _ = gplus.SelectPage(page, query) page, pageDB := gplus.SelectPage(page, query)
if pageDB.Error != nil {
global.LOG.Errorln(pageDB.Error)
return
}
if len(page.Records) == 0 {
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
return
}
userIds := make([]string, 0, len(page.Records)) userIdsSet := make(map[string]struct{}) // 使用集合去重用户 ID
replyUserIds := make([]string, 0, len(page.Records)) commentIds := make([]int64, 0, len(page.Records))
// 收集用户 ID 和评论 ID
// 收集用户 ID 和回复用户 ID
for _, comment := range page.Records { for _, comment := range page.Records {
userIds = append(userIds, comment.UserId) userIdsSet[comment.UserId] = struct{}{} // 去重
commentIds = append(commentIds, comment.Id)
if comment.ReplyUser != "" { if comment.ReplyUser != "" {
replyUserIds = append(replyUserIds, comment.ReplyUser) userIdsSet[comment.ReplyUser] = struct{}{} // 去重
} }
} }
// 将用户 ID 转换为切片
// 查询评论用户信息 userIds := make([]string, 0, len(userIdsSet))
queryUser, n := gplus.NewQuery[model.ScaAuthUser]() for userId := range userIdsSet {
queryUser.In(&n.UID, userIds) userIds = append(userIds, userId)
userInfos, _ := gplus.SelectList(queryUser)
userInfoMap := make(map[string]model.ScaAuthUser, len(userInfos))
for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo
} }
// 查询回复用户信息 likeMap := make(map[int64]bool, len(page.Records))
replyUserInfoMap := make(map[string]model.ScaAuthUser) commentImagesMap := make(map[int64]CommentImages)
if len(replyUserIds) > 0 { userInfoMap := make(map[string]model.ScaAuthUser, len(userIds))
queryReplyUser, m := gplus.NewQuery[model.ScaAuthUser]()
queryReplyUser.In(&m.UID, replyUserIds)
replyUserInfos, _ := gplus.SelectList(queryReplyUser)
for _, replyUserInfo := range replyUserInfos { wg.Add(3)
replyUserInfoMap[*replyUserInfo.UID] = *replyUserInfo go func() {
defer wg.Done()
// 查询评论用户信息
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
queryUser.Select(&n.UID, &n.Avatar, &n.Nickname).In(&n.UID, userIds)
userInfos, userInfosDB := gplus.SelectList(queryUser)
if userInfosDB.Error != nil {
global.LOG.Errorln(userInfosDB.Error)
return
} }
} for _, userInfo := range userInfos {
userInfoMap[*userInfo.UID] = *userInfo
}
}()
replyChannel := make(chan CommentContent, len(page.Records)) // 使用通道传递回复内容 go func() {
imagesBase64S := make([][]string, len(page.Records)) // 存储每条回复的图片 defer wg.Done()
// 查询评论点赞状态
for index, reply := range page.Records { if len(page.Records) > 0 {
wg.Add(1) queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
go func(reply model.ScaCommentReply, index int) { queryLike.Eq(&l.TopicId, replyListRequest.TopicId).Eq(&l.UserId, replyListRequest.UserID).In(&l.CommentId, commentIds)
defer wg.Done() likes, likesDB := gplus.SelectList(queryLike)
if likesDB.Error != nil {
// 使用 context 设置超时时间 global.LOG.Errorln(likesDB.Error)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时2秒
defer cancel()
// 获取回复图片并处理
replyImages := CommentImages{}
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(ctx, bson.M{"comment_id": reply.Id}).Decode(&replyImages)
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
global.LOG.Errorf("Failed to get images for reply ID %s: %v", reply.Id, wrong)
return return
} }
for _, like := range likes {
// 将图片转换为base64 likeMap[like.CommentId] = true
var imagesBase64 []string
for _, img := range replyImages.Images {
mimeType := getMimeType(img)
base64Img := base64.StdEncoding.EncodeToString(img)
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
imagesBase64 = append(imagesBase64, base64WithPrefix)
} }
imagesBase64S[index] = imagesBase64 // 保存到切片中 }
}()
userInfo := userInfoMap[reply.UserId] go func() {
replyUserInfo := replyUserInfoMap[reply.ReplyUser] defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时2秒
defer cancel()
cursor, err := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").Find(ctx, bson.M{"comment_id": bson.M{"$in": commentIds}})
if err != nil {
global.LOG.Errorf("Failed to get images for comments: %v", err)
return
}
defer func(cursor *mongo.Cursor, ctx context.Context) {
warn := cursor.Close(ctx)
if warn != nil {
return
}
}(cursor, ctx)
for cursor.Next(ctx) {
var commentImages CommentImages
if e := cursor.Decode(&commentImages); e != nil {
global.LOG.Errorf("Failed to decode comment images: %v", e)
continue
}
commentImagesMap[commentImages.CommentId] = commentImages
}
}()
wg.Wait()
replyChannel := make(chan CommentContent, len(page.Records)) // 使用通道传递回复内容
for _, reply := range page.Records {
wg.Add(1)
go func(reply model.ScaCommentReply) {
defer wg.Done()
var imagesBase64 []string
if imgData, ok := commentImagesMap[reply.Id]; ok {
// 将图片转换为base64
for _, img := range imgData.Images {
mimeType := getMimeType(img)
base64Img := base64.StdEncoding.EncodeToString(img)
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
imagesBase64 = append(imagesBase64, base64WithPrefix)
}
}
userInfo, exist := userInfoMap[reply.UserId]
if !exist {
global.LOG.Errorf("Failed to get user info for comment: %s", reply.UserId)
return
}
replyUserInfo, e := userInfoMap[reply.ReplyUser]
if !e {
global.LOG.Errorf("Failed to get reply user info for comment: %s", reply.ReplyUser)
return
}
commentContent := CommentContent{ commentContent := CommentContent{
Avatar: *userInfo.Avatar, Avatar: *userInfo.Avatar,
NickName: *userInfo.Nickname, NickName: *userInfo.Nickname,
Id: reply.Id, Id: reply.Id,
UserId: reply.UserId, UserId: reply.UserId,
TopicId: reply.TopicId, TopicId: reply.TopicId,
Dislikes: reply.Dislikes,
Content: reply.Content, Content: reply.Content,
ReplyUsername: *replyUserInfo.Nickname, ReplyUsername: *replyUserInfo.Nickname,
ReplyCount: reply.ReplyCount, ReplyCount: reply.ReplyCount,
@@ -588,9 +701,10 @@ func (CommentAPI) ReplyList(c *gin.Context) {
Browser: reply.Browser, Browser: reply.Browser,
OperatingSystem: reply.OperatingSystem, OperatingSystem: reply.OperatingSystem,
Images: imagesBase64, Images: imagesBase64,
IsLiked: likeMap[reply.Id],
} }
replyChannel <- commentContent // 发送到通道 replyChannel <- commentContent // 发送到通道
}(*reply, index) }(*reply)
} }
go func() { go func() {
@@ -614,6 +728,13 @@ func (CommentAPI) ReplyList(c *gin.Context) {
} }
// CommentLikes 点赞评论 // CommentLikes 点赞评论
// @Summary 点赞评论
// @Description 点赞评论
// @Tags 评论
// @Accept json
// @Produce json
// @Param comment_like_request body dto.CommentLikeRequest true "点赞请求"
// @Router /auth/comment/like [post]
func (CommentAPI) CommentLikes(c *gin.Context) { func (CommentAPI) CommentLikes(c *gin.Context) {
likeRequest := dto.CommentLikeRequest{} likeRequest := dto.CommentLikeRequest{}
err := c.ShouldBindJSON(&likeRequest) err := c.ShouldBindJSON(&likeRequest)
@@ -621,8 +742,79 @@ func (CommentAPI) CommentLikes(c *gin.Context) {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
mx.Lock()
defer mx.Unlock()
likes := model.ScaCommentLikes{
CommentId: likeRequest.CommentId,
UserId: likeRequest.UserID,
TopicId: likeRequest.TopicId,
}
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
res := gplus.Insert(&likes)
if res.Error != nil {
tx.Rollback()
global.LOG.Errorln(res.Error)
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentLikeFailed"), c)
return
}
// 更新点赞计数
if err = commentReplyService.UpdateCommentLikesCount(likeRequest.CommentId, likeRequest.TopicId); err != nil {
tx.Rollback()
global.LOG.Errorln(err)
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentLikeFailed"), c)
return
}
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentLikeSuccess"), c)
return
} }
func (CommentAPI) CommentDislikes(c *gin.Context) { // CancelCommentLikes 取消点赞评论
// @Summary 取消点赞评论
// @Description 取消点赞评论
// @Tags 评论
// @Accept json
// @Produce json
// @Param comment_like_request body dto.CommentLikeRequest true "取消点赞请求"
// @Router /auth/comment/cancel_like [post]
func (CommentAPI) CancelCommentLikes(c *gin.Context) {
likeRequest := dto.CommentLikeRequest{}
err := c.ShouldBindJSON(&likeRequest)
if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return
}
mx.Lock()
defer mx.Unlock()
tx := global.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
query, u := gplus.NewQuery[model.ScaCommentLikes]()
query.Eq(&u.CommentId, likeRequest.CommentId).Eq(&u.UserId, likeRequest.UserID).Eq(&u.TopicId, likeRequest.TopicId)
res := gplus.Delete[model.ScaCommentLikes](query)
if res.Error != nil {
tx.Rollback()
global.LOG.Errorln(res.Error)
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentLikeCancelFailed"), c)
return
}
err = commentReplyService.DecrementCommentLikesCount(likeRequest.CommentId, likeRequest.TopicId)
if err != nil {
tx.Rollback()
global.LOG.Errorln(err)
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentLikeCancelFailed"), c)
return
}
tx.Commit()
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentLikeCancelSuccess"), c)
return
} }

View File

@@ -25,15 +25,17 @@ type ReplyReplyRequest struct {
ReplyTo int64 `json:"reply_to" binding:"required"` ReplyTo int64 `json:"reply_to" binding:"required"`
ReplyId int64 `json:"reply_id" binding:"required"` ReplyId int64 `json:"reply_id" binding:"required"`
ReplyUser string `json:"reply_user" binding:"required"` ReplyUser string `json:"reply_user" binding:"required"`
Author string `json:"author" binding:"required""` Author string `json:"author" binding:"required"`
} }
type CommentListRequest struct { type CommentListRequest struct {
UserID string `json:"user_id" binding:"required"`
TopicId string `json:"topic_id" binding:"required"` TopicId string `json:"topic_id" binding:"required"`
Page int `json:"page" default:"1"` Page int `json:"page" default:"1"`
Size int `json:"size" default:"5"` Size int `json:"size" default:"5"`
} }
type ReplyListRequest struct { type ReplyListRequest struct {
UserID string `json:"user_id" binding:"required"`
TopicId string `json:"topic_id" binding:"required"` TopicId string `json:"topic_id" binding:"required"`
CommentId int64 `json:"comment_id" binding:"required"` CommentId int64 `json:"comment_id" binding:"required"`
Page int `json:"page" default:"1"` Page int `json:"page" default:"1"`
@@ -43,5 +45,4 @@ type CommentLikeRequest struct {
TopicId string `json:"topic_id" binding:"required"` TopicId string `json:"topic_id" binding:"required"`
CommentId int64 `json:"comment_id" binding:"required"` CommentId int64 `json:"comment_id" binding:"required"`
UserID string `json:"user_id" binding:"required"` UserID string `json:"user_id" binding:"required"`
Type int `json:"type" binding:"required"`
} }

View File

@@ -70,3 +70,7 @@ CommentSubmitSuccess = "comment submit successfully!"
ImageStorageError = "image storage error!" ImageStorageError = "image storage error!"
ImageDecodeError = "image decode error!" ImageDecodeError = "image decode error!"
ImageSaveError = "image save error!" ImageSaveError = "image save error!"
CommentLikeSuccess = "comment like success!"
CommentLikeFailed = "comment like failed!"
CommentDislikeSuccess = "comment dislike success!"
CommentDislikeFailed = "comment dislike failed!"

View File

@@ -70,3 +70,7 @@ CommentSubmitSuccess = "评论提交成功!"
ImageStorageError = "图片存储错误!" ImageStorageError = "图片存储错误!"
ImageDecodeError = "图片解码错误!" ImageDecodeError = "图片解码错误!"
ImageSaveError = "图片保存错误!" ImageSaveError = "图片保存错误!"
CommentLikeSuccess = "评论点赞成功!"
CommentLikeFailed = "评论点赞失败!"
CommentDislikeSuccess = "评论取消点赞成功!"
CommentDislikeFailed = "评论取消点赞失败!"

View File

@@ -8,7 +8,6 @@ type ScaCommentLikes struct {
TopicId string `gorm:"column:topic_id;type:varchar(20);NOT NULL;comment:主题ID" json:"topic_id"` TopicId string `gorm:"column:topic_id;type:varchar(20);NOT NULL;comment:主题ID" json:"topic_id"`
UserId string `gorm:"column:user_id;type:varchar(20);comment:用户ID;NOT NULL" json:"user_id"` UserId string `gorm:"column:user_id;type:varchar(20);comment:用户ID;NOT NULL" json:"user_id"`
CommentId int64 `gorm:"column:comment_id;type:bigint(20);comment:评论ID;NOT NULL" json:"comment_id"` CommentId int64 `gorm:"column:comment_id;type:bigint(20);comment:评论ID;NOT NULL" json:"comment_id"`
Type int `gorm:"column:type;type:int(11);comment:类型0 点赞 1 踩;NOT NULL" json:"type"`
} }
func (like *ScaCommentLikes) TableName() string { func (like *ScaCommentLikes) TableName() string {

View File

@@ -26,7 +26,6 @@ type ScaCommentReply struct {
Deleted int `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0未删除 1 已删除" json:"-"` Deleted int `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0未删除 1 已删除" json:"-"`
CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"-"` CreatedBy string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"-"`
UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"-"` UpdateBy string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"-"`
Dislikes int64 `gorm:"column:dislikes;type:bigint(20);default:0;comment:踩数" json:"dislikes"`
CommentIp string `gorm:"column:comment_ip;type:varchar(20);comment:评论ip" json:"-"` CommentIp string `gorm:"column:comment_ip;type:varchar(20);comment:评论ip" json:"-"`
Location string `gorm:"column:location;type:varchar(20);comment:评论地址" json:"location"` Location string `gorm:"column:location;type:varchar(20);comment:评论地址" json:"location"`
Browser string `gorm:"column:browser;type:varchar(20);comment:评论浏览器" json:"browser"` Browser string `gorm:"column:browser;type:varchar(20);comment:评论浏览器" json:"browser"`

View File

@@ -13,4 +13,6 @@ func CommentRouter(router *gin.RouterGroup) {
router.POST("/auth/comment/list", commonApi.CommentList) router.POST("/auth/comment/list", commonApi.CommentList)
router.POST("/auth/reply/list", commonApi.ReplyList) router.POST("/auth/reply/list", commonApi.ReplyList)
router.POST("/auth/reply/reply/submit", commonApi.ReplyReplySubmit) router.POST("/auth/reply/reply/submit", commonApi.ReplyReplySubmit)
router.POST("/auth/comment/like", commonApi.CommentLikes)
router.POST("/auth/comment/cancel_like", commonApi.CancelCommentLikes)
} }

View File

@@ -56,3 +56,35 @@ func (CommentReplyService) UpdateCommentReplyCount(commentID int64) error {
}) })
return err return err
} }
// UpdateCommentLikesCount 更新评论 likes 数量
func (CommentReplyService) UpdateCommentLikesCount(commentID int64, topicID string) error {
// 使用事务处理错误
err := global.DB.Transaction(func(tx *gorm.DB) error {
result := tx.Model(&model.ScaCommentReply{}).Where("id = ? and topic_id = ? and deleted = 0", commentID, topicID).Update("likes", gorm.Expr("likes + ?", 1))
if result.Error != nil {
return result.Error // 返回更新错误
}
if result.RowsAffected == 0 {
return fmt.Errorf("comment not found") // 处理评论不存在的情况
}
return nil
})
return err
}
// DecrementCommentLikesCount 减少评论 likes 数量
func (CommentReplyService) DecrementCommentLikesCount(commentID int64, topicID string) error {
// 使用事务处理错误
err := global.DB.Transaction(func(tx *gorm.DB) error {
result := tx.Model(&model.ScaCommentReply{}).Where("id = ? and topic_id = ? and deleted = 0", commentID, topicID).Update("likes", gorm.Expr("likes - ?", 1))
if result.Error != nil {
return result.Error // 返回更新错误
}
if result.RowsAffected == 0 {
return fmt.Errorf("comment not found") // 处理评论不存在的情况
}
return nil
})
return err
}