⚡ optimize the list of comments
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package dto
|
||||
|
||||
type RotateCaptchaRequest struct {
|
||||
Angle int `json:"angle"`
|
||||
Key string `json:"key"`
|
||||
Angle int `json:"angle" binding:"required"`
|
||||
Key string `json:"key" binding:"required"`
|
||||
}
|
||||
|
@@ -1,14 +1,22 @@
|
||||
package comment_api
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"schisandra-cloud-album/service"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CommentAPI struct{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var commentReplyService = service.Service.CommentReplyService
|
||||
|
||||
// CommentImages 评论图片
|
||||
type CommentImages struct {
|
||||
TopicId string `json:"topic_id" bson:"topic_id" required:"true"`
|
||||
CommentId int64 `json:"comment_id" bson:"comment_id" required:"true"`
|
||||
@@ -17,6 +25,7 @@ type CommentImages struct {
|
||||
CreatedAt string `json:"created_at" bson:"created_at" required:"true"`
|
||||
}
|
||||
|
||||
// CommentContent 评论内容
|
||||
type CommentContent struct {
|
||||
NickName string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
@@ -40,9 +49,88 @@ type CommentContent struct {
|
||||
Images []string `json:"images,omitempty"`
|
||||
}
|
||||
|
||||
// CommentResponse 评论返回值
|
||||
type CommentResponse struct {
|
||||
Size int `json:"size"`
|
||||
Total int64 `json:"total"`
|
||||
Current int `json:"current"`
|
||||
Comments []CommentContent `json:"comments"`
|
||||
}
|
||||
|
||||
// base64ToBytes 将base64字符串转换为字节数组
|
||||
func base64ToBytes(base64Str string) ([]byte, error) {
|
||||
reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64Str))
|
||||
data, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to decode base64 string")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// processImages 处理图片,将 base64 字符串转换为字节数组
|
||||
func processImages(images []string) ([][]byte, error) {
|
||||
var imagesData [][]byte
|
||||
dataChan := make(chan []byte, len(images)) // 创建一个带缓冲的 channel
|
||||
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||
|
||||
for _, img := range images {
|
||||
wg.Add(1) // 增加 WaitGroup 的计数
|
||||
go func(img string) {
|
||||
defer wg.Done() // 函数结束时减少计数
|
||||
|
||||
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||
data, err := base64ToBytes(imgWithoutPrefix)
|
||||
if err != nil {
|
||||
return // 出错时直接返回
|
||||
}
|
||||
dataChan <- data // 将结果发送到 channel
|
||||
}(img)
|
||||
}
|
||||
|
||||
wg.Wait() // 等待所有 goroutine 完成
|
||||
close(dataChan) // 关闭 channel
|
||||
|
||||
for data := range dataChan { // 收集所有结果
|
||||
imagesData = append(imagesData, data)
|
||||
}
|
||||
|
||||
return imagesData, nil
|
||||
}
|
||||
|
||||
// getMimeType 获取 MIME 类型
|
||||
func getMimeType(data []byte) string {
|
||||
if len(data) < 4 {
|
||||
return "application/octet-stream" // 默认类型
|
||||
}
|
||||
|
||||
// 判断 JPEG
|
||||
if data[0] == 0xFF && data[1] == 0xD8 {
|
||||
return "image/jpeg"
|
||||
}
|
||||
|
||||
// 判断 PNG
|
||||
if len(data) >= 8 && data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 &&
|
||||
data[4] == 0x0D && data[5] == 0x0A && data[6] == 0x1A && data[7] == 0x0A {
|
||||
return "image/png"
|
||||
}
|
||||
|
||||
// 判断 GIF
|
||||
if len(data) >= 6 && data[0] == 'G' && data[1] == 'I' && data[2] == 'F' {
|
||||
return "image/gif"
|
||||
}
|
||||
// 判断 WEBP
|
||||
if len(data) >= 12 && data[0] == 0x52 && data[1] == 0x49 && data[2] == 0x46 && data[3] == 0x46 &&
|
||||
data[8] == 0x57 && data[9] == 0x45 && data[10] == 0x42 && data[11] == 0x50 {
|
||||
return "image/webp"
|
||||
}
|
||||
// 判断svg
|
||||
if len(data) >= 4 && data[0] == '<' && data[1] == '?' && data[2] == 'x' && data[3] == 'm' {
|
||||
return "image/svg+xml"
|
||||
}
|
||||
// 判断JPG
|
||||
if len(data) >= 3 && data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF {
|
||||
return "image/jpeg"
|
||||
}
|
||||
|
||||
return "application/octet-stream" // 默认类型
|
||||
}
|
||||
|
@@ -11,16 +11,12 @@ import (
|
||||
"github.com/mssola/useragent"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"io"
|
||||
"regexp"
|
||||
"schisandra-cloud-album/api/comment_api/dto"
|
||||
"schisandra-cloud-album/common/enum"
|
||||
"schisandra-cloud-album/common/result"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
"schisandra-cloud-album/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -38,11 +34,6 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
|
||||
if commentRequest.Content == "" || commentRequest.UserID == "" || commentRequest.TopicId == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
if len(commentRequest.Images) > 3 {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "TooManyImages"), c)
|
||||
return
|
||||
@@ -69,12 +60,14 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
||||
if commentRequest.UserID == commentRequest.Author {
|
||||
isAuthor = 1
|
||||
}
|
||||
|
||||
tx := global.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
commentReply := model.ScaCommentReply{
|
||||
Content: commentRequest.Content,
|
||||
UserId: commentRequest.UserID,
|
||||
@@ -88,26 +81,38 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
||||
OperatingSystem: operatingSystem,
|
||||
Agent: userAgent,
|
||||
}
|
||||
// 使用 goroutine 进行异步评论保存
|
||||
errCh := make(chan error, 2)
|
||||
go func() {
|
||||
errCh <- commentReplyService.CreateCommentReply(&commentReply)
|
||||
}()
|
||||
|
||||
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||
// 等待评论回复的创建
|
||||
if err = <-errCh; err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理图片异步上传
|
||||
if len(commentRequest.Images) > 0 {
|
||||
|
||||
var imagesData [][]byte
|
||||
for _, img := range commentRequest.Images {
|
||||
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||
data, err := base64ToBytes(imgWithoutPrefix)
|
||||
imagesDataCh := make(chan [][]byte)
|
||||
go func() {
|
||||
imagesData, err := processImages(commentRequest.Images)
|
||||
if err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
tx.Rollback()
|
||||
imagesDataCh <- nil // 发送失败信号
|
||||
return
|
||||
}
|
||||
imagesData = append(imagesData, data)
|
||||
imagesDataCh <- imagesData // 发送处理成功的数据
|
||||
}()
|
||||
|
||||
imagesData := <-imagesDataCh
|
||||
if imagesData == nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
commentImages := CommentImages{
|
||||
@@ -117,28 +122,19 @@ func (CommentAPI) CommentSubmit(c *gin.Context) {
|
||||
Images: imagesData,
|
||||
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 使用 goroutine 进行异步图片保存
|
||||
go func() {
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
tx.Commit()
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||
return
|
||||
}
|
||||
|
||||
// base64ToBytes 将base64字符串转换为字节数组
|
||||
func base64ToBytes(base64Str string) ([]byte, error) {
|
||||
reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64Str))
|
||||
data, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to decode base64 string")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ReplySubmit 提交回复
|
||||
// @Summary 提交回复
|
||||
// @Description 提交回复
|
||||
@@ -154,14 +150,6 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if replyCommentRequest.Content == "" ||
|
||||
replyCommentRequest.UserID == "" ||
|
||||
replyCommentRequest.TopicId == "" ||
|
||||
strconv.FormatInt(replyCommentRequest.ReplyId, 10) == "" ||
|
||||
replyCommentRequest.ReplyUser == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
if len(replyCommentRequest.Images) > 3 {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "TooManyImages"), c)
|
||||
return
|
||||
@@ -172,8 +160,8 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
||||
global.LOG.Errorln("user-agent is empty")
|
||||
return
|
||||
}
|
||||
ua := useragent.New(userAgent)
|
||||
|
||||
ua := useragent.New(userAgent)
|
||||
ip := utils.GetClientIP(c)
|
||||
location, err := global.IP2Location.SearchByStr(ip)
|
||||
if err != nil {
|
||||
@@ -188,12 +176,14 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
||||
if replyCommentRequest.UserID == replyCommentRequest.Author {
|
||||
isAuthor = 1
|
||||
}
|
||||
|
||||
tx := global.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
commentReply := model.ScaCommentReply{
|
||||
Content: replyCommentRequest.Content,
|
||||
UserId: replyCommentRequest.UserID,
|
||||
@@ -209,33 +199,44 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
||||
OperatingSystem: operatingSystem,
|
||||
Agent: userAgent,
|
||||
}
|
||||
// 使用 goroutine 进行异步评论保存
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
|
||||
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
err = commentReplyService.UpdateCommentReplyCount(replyCommentRequest.ReplyId)
|
||||
if err != nil {
|
||||
errCh <- commentReplyService.CreateCommentReply(&commentReply)
|
||||
}()
|
||||
go func() {
|
||||
|
||||
errCh <- commentReplyService.UpdateCommentReplyCount(replyCommentRequest.ReplyId)
|
||||
}()
|
||||
// 等待评论回复的创建
|
||||
if err = <-errCh; err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理图片异步上传
|
||||
if len(replyCommentRequest.Images) > 0 {
|
||||
|
||||
var imagesData [][]byte
|
||||
for _, img := range replyCommentRequest.Images {
|
||||
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||
data, err := base64ToBytes(imgWithoutPrefix)
|
||||
imagesDataCh := make(chan [][]byte)
|
||||
go func() {
|
||||
imagesData, err := processImages(replyCommentRequest.Images)
|
||||
if err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
tx.Rollback()
|
||||
imagesDataCh <- nil // 发送失败信号
|
||||
return
|
||||
}
|
||||
imagesData = append(imagesData, data)
|
||||
imagesDataCh <- imagesData // 发送处理成功的数据
|
||||
}()
|
||||
|
||||
imagesData := <-imagesDataCh
|
||||
if imagesData == nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
commentImages := CommentImages{
|
||||
TopicId: replyCommentRequest.TopicId,
|
||||
CommentId: commentReply.Id,
|
||||
@@ -243,12 +244,13 @@ func (CommentAPI) ReplySubmit(c *gin.Context) {
|
||||
Images: imagesData,
|
||||
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 使用 goroutine 进行异步图片保存
|
||||
go func() {
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
tx.Commit()
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||
@@ -270,15 +272,6 @@ func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if replyReplyRequest.Content == "" ||
|
||||
replyReplyRequest.UserID == "" ||
|
||||
replyReplyRequest.TopicId == "" ||
|
||||
replyReplyRequest.ReplyTo == 0 ||
|
||||
replyReplyRequest.ReplyId == 0 ||
|
||||
replyReplyRequest.ReplyUser == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
if len(replyReplyRequest.Images) > 3 {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "TooManyImages"), c)
|
||||
return
|
||||
@@ -289,8 +282,8 @@ func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||
global.LOG.Errorln("user-agent is empty")
|
||||
return
|
||||
}
|
||||
ua := useragent.New(userAgent)
|
||||
|
||||
ua := useragent.New(userAgent)
|
||||
ip := utils.GetClientIP(c)
|
||||
location, err := global.IP2Location.SearchByStr(ip)
|
||||
if err != nil {
|
||||
@@ -305,12 +298,14 @@ func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||
if replyReplyRequest.UserID == replyReplyRequest.Author {
|
||||
isAuthor = 1
|
||||
}
|
||||
|
||||
tx := global.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
commentReply := model.ScaCommentReply{
|
||||
Content: replyReplyRequest.Content,
|
||||
UserId: replyReplyRequest.UserID,
|
||||
@@ -328,32 +323,40 @@ func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||
Agent: userAgent,
|
||||
}
|
||||
|
||||
if err = commentReplyService.CreateCommentReply(&commentReply); err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
err = commentReplyService.UpdateCommentReplyCount(replyReplyRequest.ReplyId)
|
||||
if err != nil {
|
||||
errCh := make(chan error, 2)
|
||||
go func() {
|
||||
errCh <- commentReplyService.CreateCommentReply(&commentReply)
|
||||
}()
|
||||
go func() {
|
||||
errCh <- commentReplyService.UpdateCommentReplyCount(replyReplyRequest.ReplyId)
|
||||
}()
|
||||
|
||||
if err = <-errCh; err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
if len(replyReplyRequest.Images) > 0 {
|
||||
|
||||
var imagesData [][]byte
|
||||
for _, img := range replyReplyRequest.Images {
|
||||
re := regexp.MustCompile(`^data:image/\w+;base64,`)
|
||||
imgWithoutPrefix := re.ReplaceAllString(img, "")
|
||||
data, err := base64ToBytes(imgWithoutPrefix)
|
||||
imagesDataCh := make(chan [][]byte)
|
||||
go func() {
|
||||
imagesData, err := processImages(replyReplyRequest.Images)
|
||||
if err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
tx.Rollback()
|
||||
imagesDataCh <- nil
|
||||
return
|
||||
}
|
||||
imagesData = append(imagesData, data)
|
||||
imagesDataCh <- imagesData
|
||||
}()
|
||||
|
||||
imagesData := <-imagesDataCh
|
||||
if imagesData == nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
commentImages := CommentImages{
|
||||
TopicId: replyReplyRequest.TopicId,
|
||||
CommentId: commentReply.Id,
|
||||
@@ -361,12 +364,13 @@ func (CommentAPI) ReplyReplySubmit(c *gin.Context) {
|
||||
Images: imagesData,
|
||||
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitFailed"), c)
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理图片保存
|
||||
go func() {
|
||||
if _, err = global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").InsertOne(context.Background(), commentImages); err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
tx.Commit()
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CommentSubmitSuccess"), c)
|
||||
@@ -388,38 +392,57 @@ func (CommentAPI) CommentList(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
if commentListRequest.TopicId == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
query, u := gplus.NewQuery[model.ScaCommentReply]()
|
||||
page := gplus.NewPage[model.ScaCommentReply](commentListRequest.Page, commentListRequest.Size)
|
||||
query.Eq(&u.TopicId, commentListRequest.TopicId).Eq(&u.CommentType, enum.COMMENT).OrderByDesc(&u.Likes)
|
||||
page, _ = gplus.SelectPage(page, query)
|
||||
|
||||
var commentsWithImages []CommentContent
|
||||
|
||||
userIds := make([]string, 0, len(page.Records))
|
||||
for _, comment := range page.Records {
|
||||
// 获取评论图片
|
||||
commentImages := CommentImages{}
|
||||
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(context.Background(), bson.M{"comment_id": comment.Id}).Decode(&commentImages)
|
||||
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
|
||||
global.LOG.Errorln(wrong)
|
||||
}
|
||||
// 将图片转换为base64
|
||||
var imagesBase64 []string
|
||||
for _, img := range commentImages.Images {
|
||||
mimeType := getMimeType(img) // 动态获取 MIME 类型
|
||||
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
||||
}
|
||||
// 组装评论数据
|
||||
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
||||
queryUser.Eq(&n.UID, comment.UserId)
|
||||
userInfo, _ := gplus.SelectOne(queryUser)
|
||||
commentsWithImages = append(commentsWithImages,
|
||||
CommentContent{
|
||||
userIds = append(userIds, comment.UserId)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 将图片转换为base64
|
||||
var imagesBase64 []string
|
||||
for _, img := range commentImages.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[comment.UserId]
|
||||
commentContent := CommentContent{
|
||||
Avatar: *userInfo.Avatar,
|
||||
NickName: *userInfo.Nickname,
|
||||
Id: comment.Id,
|
||||
@@ -435,8 +458,21 @@ func (CommentAPI) CommentList(c *gin.Context) {
|
||||
Browser: comment.Browser,
|
||||
OperatingSystem: comment.OperatingSystem,
|
||||
Images: imagesBase64,
|
||||
})
|
||||
}
|
||||
commentChannel <- commentContent
|
||||
}(*comment, index)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(commentChannel)
|
||||
}()
|
||||
|
||||
var commentsWithImages []CommentContent
|
||||
for commentContent := range commentChannel {
|
||||
commentsWithImages = append(commentsWithImages, commentContent)
|
||||
}
|
||||
|
||||
response := CommentResponse{
|
||||
Comments: commentsWithImages,
|
||||
Size: page.Size,
|
||||
@@ -447,30 +483,6 @@ func (CommentAPI) CommentList(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
func getMimeType(data []byte) string {
|
||||
if len(data) < 4 {
|
||||
return "application/octet-stream" // 默认类型
|
||||
}
|
||||
|
||||
// 判断 JPEG
|
||||
if data[0] == 0xFF && data[1] == 0xD8 {
|
||||
return "image/jpeg"
|
||||
}
|
||||
|
||||
// 判断 PNG
|
||||
if len(data) >= 8 && data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47 &&
|
||||
data[4] == 0x0D && data[5] == 0x0A && data[6] == 0x1A && data[7] == 0x0A {
|
||||
return "image/png"
|
||||
}
|
||||
|
||||
// 判断 GIF
|
||||
if len(data) >= 6 && data[0] == 'G' && data[1] == 'I' && data[2] == 'F' {
|
||||
return "image/gif"
|
||||
}
|
||||
|
||||
return "application/octet-stream" // 默认类型
|
||||
}
|
||||
|
||||
// ReplyList 获取回复列表
|
||||
// @Summary 获取回复列表
|
||||
// @Description 获取回复列表
|
||||
@@ -486,65 +498,113 @@ func (CommentAPI) ReplyList(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
if replyListRequest.TopicId == "" || strconv.FormatInt(replyListRequest.CommentId, 10) == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
query, u := gplus.NewQuery[model.ScaCommentReply]()
|
||||
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)
|
||||
page, _ = gplus.SelectPage(page, query)
|
||||
|
||||
var commentsWithImages []CommentContent
|
||||
userIds := make([]string, 0, len(page.Records))
|
||||
replyUserIds := make([]string, 0, len(page.Records))
|
||||
|
||||
// 收集用户 ID 和回复用户 ID
|
||||
for _, comment := range page.Records {
|
||||
// 获取评论图片
|
||||
commentImages := CommentImages{}
|
||||
wrong := global.MongoDB.Database(global.CONFIG.MongoDB.DB).Collection("comment_images").FindOne(context.Background(), bson.M{"comment_id": comment.Id}).Decode(&commentImages)
|
||||
if wrong != nil && !errors.Is(wrong, mongo.ErrNoDocuments) {
|
||||
global.LOG.Errorln(wrong)
|
||||
userIds = append(userIds, comment.UserId)
|
||||
if comment.ReplyUser != "" {
|
||||
replyUserIds = append(replyUserIds, comment.ReplyUser)
|
||||
}
|
||||
// 将图片转换为base64
|
||||
var imagesBase64 []string
|
||||
for _, img := range commentImages.Images {
|
||||
mimeType := getMimeType(img) // 动态获取 MIME 类型
|
||||
base64Img := base64.StdEncoding.EncodeToString(img)
|
||||
base64WithPrefix := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Img)
|
||||
imagesBase64 = append(imagesBase64, base64WithPrefix)
|
||||
}
|
||||
// 查询评论用户信息
|
||||
queryUser, n := gplus.NewQuery[model.ScaAuthUser]()
|
||||
queryUser.Eq(&n.UID, comment.UserId)
|
||||
userInfo, _ := gplus.SelectOne(queryUser)
|
||||
// 查询回复用户信息
|
||||
}
|
||||
|
||||
// 查询评论用户信息
|
||||
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.Eq(&m.UID, comment.ReplyUser)
|
||||
replyUserInfo, _ := gplus.SelectOne(queryReplyUser)
|
||||
commentsWithImages = append(commentsWithImages,
|
||||
CommentContent{
|
||||
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
|
||||
}
|
||||
|
||||
// 将图片转换为base64
|
||||
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]
|
||||
replyUserInfo := replyUserInfoMap[reply.ReplyUser]
|
||||
commentContent := CommentContent{
|
||||
Avatar: *userInfo.Avatar,
|
||||
NickName: *userInfo.Nickname,
|
||||
Id: comment.Id,
|
||||
UserId: comment.UserId,
|
||||
TopicId: comment.TopicId,
|
||||
Dislikes: comment.Dislikes,
|
||||
Content: comment.Content,
|
||||
Id: reply.Id,
|
||||
UserId: reply.UserId,
|
||||
TopicId: reply.TopicId,
|
||||
Dislikes: reply.Dislikes,
|
||||
Content: reply.Content,
|
||||
ReplyUsername: *replyUserInfo.Nickname,
|
||||
ReplyCount: comment.ReplyCount,
|
||||
Likes: comment.Likes,
|
||||
CreatedTime: comment.CreatedTime,
|
||||
ReplyUser: comment.ReplyUser,
|
||||
ReplyId: comment.ReplyId,
|
||||
ReplyTo: comment.ReplyTo,
|
||||
Author: comment.Author,
|
||||
Location: comment.Location,
|
||||
Browser: comment.Browser,
|
||||
OperatingSystem: comment.OperatingSystem,
|
||||
ReplyCount: reply.ReplyCount,
|
||||
Likes: reply.Likes,
|
||||
CreatedTime: reply.CreatedTime,
|
||||
ReplyUser: reply.ReplyUser,
|
||||
ReplyId: reply.ReplyId,
|
||||
ReplyTo: reply.ReplyTo,
|
||||
Author: reply.Author,
|
||||
Location: reply.Location,
|
||||
Browser: reply.Browser,
|
||||
OperatingSystem: reply.OperatingSystem,
|
||||
Images: imagesBase64,
|
||||
})
|
||||
}
|
||||
replyChannel <- commentContent // 发送到通道
|
||||
}(*reply, index)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(replyChannel) // 关闭通道
|
||||
}()
|
||||
|
||||
var repliesWithImages []CommentContent
|
||||
for replyContent := range replyChannel {
|
||||
repliesWithImages = append(repliesWithImages, replyContent) // 从通道获取回复内容
|
||||
}
|
||||
|
||||
response := CommentResponse{
|
||||
Comments: commentsWithImages,
|
||||
Comments: repliesWithImages,
|
||||
Size: page.Size,
|
||||
Current: page.Current,
|
||||
Total: page.Total,
|
||||
@@ -552,3 +612,17 @@ func (CommentAPI) ReplyList(c *gin.Context) {
|
||||
result.OkWithData(response, c)
|
||||
return
|
||||
}
|
||||
|
||||
// CommentLikes 点赞评论
|
||||
func (CommentAPI) CommentLikes(c *gin.Context) {
|
||||
likeRequest := dto.CommentLikeRequest{}
|
||||
err := c.ShouldBindJSON(&likeRequest)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (CommentAPI) CommentDislikes(c *gin.Context) {
|
||||
|
||||
}
|
||||
|
@@ -1,41 +1,47 @@
|
||||
package dto
|
||||
|
||||
type CommentRequest struct {
|
||||
Content string `json:"content"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Images []string `json:"images"`
|
||||
UserID string `json:"user_id"`
|
||||
TopicId string `json:"topic_id"`
|
||||
Author string `json:"author"`
|
||||
UserID string `json:"user_id" binding:"required"`
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
Author string `json:"author" binding:"required"`
|
||||
}
|
||||
type ReplyCommentRequest struct {
|
||||
Content string `json:"content"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Images []string `json:"images"`
|
||||
UserID string `json:"user_id"`
|
||||
TopicId string `json:"topic_id"`
|
||||
ReplyId int64 `json:"reply_id"`
|
||||
ReplyUser string `json:"reply_user"`
|
||||
Author string `json:"author"`
|
||||
UserID string `json:"user_id" binding:"required"`
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
ReplyId int64 `json:"reply_id" binding:"required"`
|
||||
ReplyUser string `json:"reply_user" binding:"required"`
|
||||
Author string `json:"author" binding:"required"`
|
||||
}
|
||||
|
||||
type ReplyReplyRequest struct {
|
||||
Content string `json:"content"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Images []string `json:"images"`
|
||||
UserID string `json:"user_id"`
|
||||
TopicId string `json:"topic_id"`
|
||||
ReplyTo int64 `json:"reply_to"`
|
||||
ReplyId int64 `json:"reply_id"`
|
||||
ReplyUser string `json:"reply_user"`
|
||||
Author string `json:"author"`
|
||||
UserID string `json:"user_id" binding:"required"`
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
ReplyTo int64 `json:"reply_to" binding:"required"`
|
||||
ReplyId int64 `json:"reply_id" binding:"required"`
|
||||
ReplyUser string `json:"reply_user" binding:"required"`
|
||||
Author string `json:"author" binding:"required""`
|
||||
}
|
||||
|
||||
type CommentListRequest struct {
|
||||
TopicId string `json:"topic_id"`
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
Page int `json:"page" default:"1"`
|
||||
Size int `json:"size" default:"5"`
|
||||
}
|
||||
type ReplyListRequest struct {
|
||||
TopicId string `json:"topic_id"`
|
||||
CommentId int64 `json:"comment_id"`
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
CommentId int64 `json:"comment_id" binding:"required"`
|
||||
Page int `json:"page" default:"1"`
|
||||
Size int `json:"size" default:"5"`
|
||||
}
|
||||
type CommentLikeRequest struct {
|
||||
TopicId string `json:"topic_id" binding:"required"`
|
||||
CommentId int64 `json:"comment_id" binding:"required"`
|
||||
UserID string `json:"user_id" binding:"required"`
|
||||
Type int `json:"type" binding:"required"`
|
||||
}
|
||||
|
@@ -301,11 +301,11 @@ func handelUserLogin(userId string, clientId string) bool {
|
||||
resultChan <- false
|
||||
return
|
||||
}
|
||||
responseData := map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": data,
|
||||
"success": true,
|
||||
responseData := result.Response{
|
||||
Data: data,
|
||||
Message: "success",
|
||||
Code: 200,
|
||||
Success: true,
|
||||
}
|
||||
tokenData, err := json.Marshal(responseData)
|
||||
if err != nil {
|
||||
|
@@ -1,11 +1,11 @@
|
||||
package dto
|
||||
|
||||
type RoleRequestDto struct {
|
||||
RoleName string `json:"role_name"`
|
||||
RoleKey string `json:"role_key"`
|
||||
RoleName string `json:"role_name" binding:"required"`
|
||||
RoleKey string `json:"role_key" binding:"required"`
|
||||
}
|
||||
|
||||
type AddRoleToUserRequestDto struct {
|
||||
Uid string `json:"uid"`
|
||||
RoleKey string `json:"role_key"`
|
||||
Uid string `json:"uid" binding:"required"`
|
||||
RoleKey string `json:"role_key" binding:"required"`
|
||||
}
|
||||
|
@@ -4,36 +4,36 @@ import "encoding/json"
|
||||
|
||||
// RefreshTokenRequest 刷新token请求
|
||||
type RefreshTokenRequest struct {
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
RefreshToken string `json:"refresh_token" binding:"required"`
|
||||
}
|
||||
|
||||
// PhoneLoginRequest 手机号登录请求
|
||||
type PhoneLoginRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
Captcha string `json:"captcha"`
|
||||
AutoLogin bool `json:"auto_login"`
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
Captcha string `json:"captcha" binding:"required"`
|
||||
AutoLogin bool `json:"auto_login" binding:"required"`
|
||||
}
|
||||
|
||||
// AccountLoginRequest 账号登录请求
|
||||
type AccountLoginRequest struct {
|
||||
Account string `json:"account"`
|
||||
Password string `json:"password"`
|
||||
AutoLogin bool `json:"auto_login"`
|
||||
Account string `json:"account" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
AutoLogin bool `json:"auto_login" binding:"required"`
|
||||
}
|
||||
|
||||
// AddUserRequest 新增用户请求
|
||||
type AddUserRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Phone string `json:"phone"`
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
}
|
||||
|
||||
// ResetPasswordRequest 重置密码请求
|
||||
type ResetPasswordRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
Captcha string `json:"captcha"`
|
||||
Password string `json:"password"`
|
||||
Repassword string `json:"repassword"`
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
Captcha string `json:"captcha" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
Repassword string `json:"repassword" binding:"required"`
|
||||
}
|
||||
|
||||
// ResponseData 返回数据
|
||||
|
@@ -118,10 +118,6 @@ func (UserAPI) AccountLogin(c *gin.Context) {
|
||||
}
|
||||
account := accountLoginRequest.Account
|
||||
password := accountLoginRequest.Password
|
||||
if account == "" || password == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AccountAndPasswordNotEmpty"), c)
|
||||
return
|
||||
}
|
||||
|
||||
var user model.ScaAuthUser
|
||||
if utils.IsPhone(account) {
|
||||
@@ -163,10 +159,6 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
phone := request.Phone
|
||||
captcha := request.Captcha
|
||||
autoLogin := request.AutoLogin
|
||||
if phone == "" || captcha == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneAndCaptchaNotEmpty"), c)
|
||||
return
|
||||
}
|
||||
if !utils.IsPhone(phone) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneErrorFormat"), c)
|
||||
return
|
||||
@@ -273,10 +265,6 @@ func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
refreshToken := request.RefreshToken
|
||||
if refreshToken == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
parseRefreshToken, isUpd, err := utils.ParseRefreshToken(refreshToken)
|
||||
if err != nil || !isUpd {
|
||||
global.LOG.Errorln(err)
|
||||
@@ -369,12 +357,6 @@ func (UserAPI) ResetPassword(c *gin.Context) {
|
||||
captcha := resetPasswordRequest.Captcha
|
||||
password := resetPasswordRequest.Password
|
||||
repassword := resetPasswordRequest.Repassword
|
||||
|
||||
if phone == "" || captcha == "" || password == "" || repassword == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.IsPhone(phone) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneError"), c)
|
||||
return
|
||||
|
@@ -9,8 +9,9 @@ type MongoDB struct {
|
||||
DB string `yaml:"db"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
MaxOpenConn int `yaml:"max-open-conn"`
|
||||
MaxIdleConn int `yaml:"max-idle-conn"`
|
||||
MaxOpenConn uint64 `yaml:"max-open-conn"`
|
||||
MaxIdleConn uint64 `yaml:"max-idle-conn"`
|
||||
Timeout int `yaml:"timeout"`
|
||||
}
|
||||
|
||||
func (m *MongoDB) MongoDsn() string {
|
||||
|
@@ -2,7 +2,6 @@ package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"schisandra-cloud-album/global"
|
||||
@@ -24,6 +23,9 @@ func InitMongoDB() {
|
||||
Password: global.CONFIG.MongoDB.Password,
|
||||
PasswordSet: true,
|
||||
})
|
||||
clientOptions.SetConnectTimeout(time.Duration(global.CONFIG.MongoDB.Timeout) * time.Second)
|
||||
clientOptions.SetMaxPoolSize(global.CONFIG.MongoDB.MaxOpenConn)
|
||||
clientOptions.SetMaxConnecting(global.CONFIG.MongoDB.MaxIdleConn)
|
||||
connect, err := mongo.Connect(ctx, clientOptions)
|
||||
if err != nil {
|
||||
global.LOG.Fatalf(err.Error())
|
||||
@@ -36,5 +38,4 @@ func InitMongoDB() {
|
||||
return
|
||||
}
|
||||
global.MongoDB = connect
|
||||
fmt.Println("Connected to MongoDB!")
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ const ScaCommentLikesTableName = "sca_comment_likes"
|
||||
// ScaCommentLikes 评论点赞表
|
||||
type ScaCommentLikes struct {
|
||||
Id int64 `gorm:"column:id;type:bigint(20);primary_key" json:"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"`
|
||||
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"`
|
||||
|
@@ -45,7 +45,7 @@ func (CommentReplyService) GetCommentListOrderByLikesDesc(topicID uint, page, pa
|
||||
func (CommentReplyService) UpdateCommentReplyCount(commentID int64) error {
|
||||
// 使用事务处理错误
|
||||
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
||||
result := tx.Model(&model.ScaCommentReply{}).Where("id = ?", commentID).Update("reply_count", gorm.Expr("reply_count + ?", 1))
|
||||
result := tx.Model(&model.ScaCommentReply{}).Where("id = ? and deleted = 0", commentID).Update("reply_count", gorm.Expr("reply_count + ?", 1))
|
||||
if result.Error != nil {
|
||||
return result.Error // 返回更新错误
|
||||
}
|
||||
|
Reference in New Issue
Block a user