⚡ optimize the list of comments
This commit is contained in:
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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 {
|
||||||
userIds := make([]string, 0, len(page.Records))
|
global.LOG.Errorln(pageDB.Error)
|
||||||
for _, comment := range page.Records {
|
return
|
||||||
userIds = append(userIds, comment.UserId)
|
|
||||||
}
|
}
|
||||||
|
if len(page.Records) == 0 {
|
||||||
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
|
||||||
queryUser.In(&n.UID, userIds)
|
|
||||||
userInfos, _ := gplus.SelectList(queryUser)
|
|
||||||
|
|
||||||
userInfoMap := make(map[string]model.ScaAuthUser, len(userInfos))
|
|
||||||
for _, userInfo := range userInfos {
|
|
||||||
userInfoMap[*userInfo.UID] = *userInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
commentChannel := make(chan CommentContent, len(page.Records))
|
|
||||||
imagesBase64S := make([][]string, len(page.Records)) // 存储每条评论的图片
|
|
||||||
|
|
||||||
for index, comment := range page.Records {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(comment model.ScaCommentReply, index int) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
// 使用 context 设置超时时间
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 设置超时,2秒
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// 获取评论图片并处理
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userIds := make([]string, 0, len(page.Records))
|
||||||
|
commentIds := make([]int64, 0, len(page.Records))
|
||||||
|
for _, comment := range page.Records {
|
||||||
|
userIds = append(userIds, comment.UserId)
|
||||||
|
commentIds = append(commentIds, comment.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结果存储
|
||||||
|
userInfoMap := make(map[string]model.ScaAuthUser)
|
||||||
|
likeMap := make(map[int64]bool)
|
||||||
|
commentImagesMap := make(map[int64]CommentImages)
|
||||||
|
|
||||||
|
// 使用 WaitGroup 等待协程完成
|
||||||
|
wg.Add(3)
|
||||||
|
|
||||||
|
// 查询评论用户信息
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 查询评论点赞状态
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if len(page.Records) > 0 {
|
||||||
|
queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
|
||||||
|
queryLike.Eq(&l.TopicId, commentListRequest.TopicId).Eq(&l.UserId, commentListRequest.UserID).In(&l.CommentId, commentIds)
|
||||||
|
likes, likesDB := gplus.SelectList(queryLike)
|
||||||
|
if likesDB.Error != nil {
|
||||||
|
global.LOG.Errorln(likesDB.Error)
|
||||||
|
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 {
|
||||||
|
// 将图片转换为base64
|
||||||
|
for _, img := range imgData.Images {
|
||||||
mimeType := getMimeType(img)
|
mimeType := getMimeType(img)
|
||||||
base64Img := base64.StdEncoding.EncodeToString(img)
|
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||||
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||||
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
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 {
|
||||||
userIds := make([]string, 0, len(page.Records))
|
global.LOG.Errorln(pageDB.Error)
|
||||||
replyUserIds := make([]string, 0, len(page.Records))
|
return
|
||||||
|
|
||||||
// 收集用户 ID 和回复用户 ID
|
|
||||||
for _, comment := range page.Records {
|
|
||||||
userIds = append(userIds, comment.UserId)
|
|
||||||
if comment.ReplyUser != "" {
|
|
||||||
replyUserIds = append(replyUserIds, comment.ReplyUser)
|
|
||||||
}
|
}
|
||||||
}
|
if len(page.Records) == 0 {
|
||||||
|
result.OkWithData(CommentResponse{Comments: []CommentContent{}, Size: page.Size, Current: page.Current, Total: page.Total}, c)
|
||||||
// 查询评论用户信息
|
|
||||||
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
|
||||||
queryUser.In(&n.UID, userIds)
|
|
||||||
userInfos, _ := gplus.SelectList(queryUser)
|
|
||||||
|
|
||||||
userInfoMap := make(map[string]model.ScaAuthUser, len(userInfos))
|
|
||||||
for _, userInfo := range userInfos {
|
|
||||||
userInfoMap[*userInfo.UID] = *userInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询回复用户信息
|
|
||||||
replyUserInfoMap := make(map[string]model.ScaAuthUser)
|
|
||||||
if len(replyUserIds) > 0 {
|
|
||||||
queryReplyUser, m := gplus.NewQuery[model.ScaAuthUser]()
|
|
||||||
queryReplyUser.In(&m.UID, replyUserIds)
|
|
||||||
replyUserInfos, _ := gplus.SelectList(queryReplyUser)
|
|
||||||
|
|
||||||
for _, replyUserInfo := range replyUserInfos {
|
|
||||||
replyUserInfoMap[*replyUserInfo.UID] = *replyUserInfo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replyChannel := make(chan CommentContent, len(page.Records)) // 使用通道传递回复内容
|
|
||||||
imagesBase64S := make([][]string, len(page.Records)) // 存储每条回复的图片
|
|
||||||
|
|
||||||
for index, reply := range page.Records {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(reply model.ScaCommentReply, index int) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
// 使用 context 设置超时时间
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将图片转换为base64
|
userIdsSet := make(map[string]struct{}) // 使用集合去重用户 ID
|
||||||
|
commentIds := make([]int64, 0, len(page.Records))
|
||||||
|
// 收集用户 ID 和评论 ID
|
||||||
|
for _, comment := range page.Records {
|
||||||
|
userIdsSet[comment.UserId] = struct{}{} // 去重
|
||||||
|
commentIds = append(commentIds, comment.Id)
|
||||||
|
if comment.ReplyUser != "" {
|
||||||
|
userIdsSet[comment.ReplyUser] = struct{}{} // 去重
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将用户 ID 转换为切片
|
||||||
|
userIds := make([]string, 0, len(userIdsSet))
|
||||||
|
for userId := range userIdsSet {
|
||||||
|
userIds = append(userIds, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
likeMap := make(map[int64]bool, len(page.Records))
|
||||||
|
commentImagesMap := make(map[int64]CommentImages)
|
||||||
|
userInfoMap := make(map[string]model.ScaAuthUser, len(userIds))
|
||||||
|
|
||||||
|
wg.Add(3)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
// 查询评论点赞状态
|
||||||
|
|
||||||
|
if len(page.Records) > 0 {
|
||||||
|
queryLike, l := gplus.NewQuery[model.ScaCommentLikes]()
|
||||||
|
queryLike.Eq(&l.TopicId, replyListRequest.TopicId).Eq(&l.UserId, replyListRequest.UserID).In(&l.CommentId, commentIds)
|
||||||
|
likes, likesDB := gplus.SelectList(queryLike)
|
||||||
|
if likesDB.Error != nil {
|
||||||
|
global.LOG.Errorln(likesDB.Error)
|
||||||
|
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) {
|
||||||
|
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
|
var imagesBase64 []string
|
||||||
for _, img := range replyImages.Images {
|
if imgData, ok := commentImagesMap[reply.Id]; ok {
|
||||||
|
// 将图片转换为base64
|
||||||
|
for _, img := range imgData.Images {
|
||||||
mimeType := getMimeType(img)
|
mimeType := getMimeType(img)
|
||||||
base64Img := base64.StdEncoding.EncodeToString(img)
|
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||||
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||||
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
||||||
}
|
}
|
||||||
imagesBase64S[index] = imagesBase64 // 保存到切片中
|
}
|
||||||
|
userInfo, exist := userInfoMap[reply.UserId]
|
||||||
userInfo := userInfoMap[reply.UserId]
|
if !exist {
|
||||||
replyUserInfo := replyUserInfoMap[reply.ReplyUser]
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (CommentAPI) CommentDislikes(c *gin.Context) {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
@@ -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"`
|
|
||||||
}
|
}
|
||||||
|
@@ -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!"
|
@@ -70,3 +70,7 @@ CommentSubmitSuccess = "评论提交成功!"
|
|||||||
ImageStorageError = "图片存储错误!"
|
ImageStorageError = "图片存储错误!"
|
||||||
ImageDecodeError = "图片解码错误!"
|
ImageDecodeError = "图片解码错误!"
|
||||||
ImageSaveError = "图片保存错误!"
|
ImageSaveError = "图片保存错误!"
|
||||||
|
CommentLikeSuccess = "评论点赞成功!"
|
||||||
|
CommentLikeFailed = "评论点赞失败!"
|
||||||
|
CommentDislikeSuccess = "评论取消点赞成功!"
|
||||||
|
CommentDislikeFailed = "评论取消点赞失败!"
|
@@ -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 {
|
||||||
|
@@ -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"`
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user