Files
toutoukan/controllers/article/getarticle.go

207 lines
6.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package article
import (
"fmt"
"net/http"
"time"
"toutoukan/init/databaseInit"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ArticleList 数据库文章记录结构体
type ArticleList struct {
ArticleID int64 `gorm:"column:articleId;primaryKey;autoIncrement"`
PublishUserID string `gorm:"column:publish_user_id"`
Title string `gorm:"column:title"`
VoteType string `gorm:"column:vote_type"`
EndTime time.Time `gorm:"column:end_time"`
IsEnded bool `gorm:"column:is_ended"`
TotalVotersNum int `gorm:"column:total_voters_num"`
CreateTime time.Time `gorm:"column:create_time"`
Options []ArticleOption `gorm:"foreignKey:VoteArticleID;references:ArticleID"`
}
// ArticleOption 文评选项结构
type ArticleOption struct {
ID int64 `gorm:"column:id"`
VoteArticleID int64 `gorm:"column:vote_article_id"`
OptionContent string `gorm:"column:option_content"`
OptionVotesNum int `gorm:"column:option_votes_num"`
SortOrder int `gorm:"column:sort_order"`
}
// ArticleOptionResp 格式化后的选项响应结构
type ArticleOptionResp struct {
ID int64 `json:"id"`
Name string `json:"name"`
Votes int `json:"votes"`
IsVotedByUser bool `json:"is_voted"`
}
// ArticleResponse 单个文评的响应结构
type ArticleResponse struct {
ID int64 `json:"article_id"`
Title string `json:"article_title"`
VoteType string `json:"vote_type"`
TotalVoters int `json:"total_voters"`
EndTime string `json:"end_time"`
IsEnded bool `json:"is_ended"`
PublisherID string `json:"publisher_id"`
PublisherName string `json:"publisher_name"`
CreateTime string `json:"create_time"`
Options []ArticleOptionResp `json:"options"`
UserHasVoted bool `json:"user_has_voted"`
VotedOptionIDs []int64 `json:"user_voted_option_ids"`
}
// UserReq 请求参数结构体允许uid为空
type UserReq struct {
Uid string `json:"uid" binding:"omitempty"` // 允许uid为空空字符串也合法
}
// ArticleListget 获取所有文评及选项信息支持空uid场景
func ArticleListget(c *gin.Context) {
var req UserReq
// 1. 解析请求参数
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "参数解析失败",
"detail": err.Error(),
})
return
}
// 2. 查询所有文章及关联的选项
var articles []ArticleList
if err := databaseInit.UserDB.Model(&ArticleList{}).
Preload("Options", func(db *gorm.DB) *gorm.DB {
return db.Order("sort_order ASC")
}).
Find(&articles).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "查询文评失败: " + err.Error(),
})
return
}
// 3. 批量查询所有发布者的用户名核心修改获取uid对应的username
// 3.1 收集所有发布者的uid去重
uniquePublishUids := make(map[string]struct{})
for _, article := range articles {
uniquePublishUids[article.PublishUserID] = struct{}{}
}
// 转换为切片便于查询
publishUidList := make([]string, 0, len(uniquePublishUids))
for uid := range uniquePublishUids {
publishUidList = append(publishUidList, uid)
}
// 3.2 从用户表查询这些uid对应的用户名假设用户表为`users`,字段为`user_id`和`username`
type userInfo struct {
UserID string `gorm:"column:uid"` // 对应发布者的PublishUserID
Username string `gorm:"column:username"` // 发布者用户名
}
var publishUsers []userInfo
if len(publishUidList) > 0 {
if err := databaseInit.UserDB.Table("user_info").
Where("uid IN (?)", publishUidList).
Find(&publishUsers).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "查询发布者信息失败: " + err.Error(),
})
return
}
}
// 3.3 构建uid到username的映射方便快速查询
uidToUsername := make(map[string]string)
for _, user := range publishUsers {
uidToUsername[user.UserID] = user.Username
}
// 4. 查询用户投票记录(原有逻辑,保持不变)
userVotesMap := make(map[int64][]int64)
uidValid := req.Uid != ""
if uidValid {
var userAllVotes []UserVote
if err := databaseInit.UserDB.Table("user_votes").
Where("user_id = ?", req.Uid).
Find(&userAllVotes).Error; err != nil && err != gorm.ErrRecordNotFound {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "查询用户投票记录失败: " + err.Error(),
})
return
}
for _, vote := range userAllVotes {
userVotesMap[vote.VoteArticleID] = append(userVotesMap[vote.VoteArticleID], vote.OptionID)
}
}
// 5. 组装响应数据(添加用户名)
var responseList []ArticleResponse
for _, article := range articles {
// 5.1 处理投票状态(原有逻辑)
var votedOptionIDs []int64
var userHasVoted bool
if uidValid {
votedOptionIDs, userHasVoted = userVotesMap[article.ArticleID]
} else {
votedOptionIDs = []int64{}
userHasVoted = false
}
// 5.2 处理选项列表(原有逻辑)
var optionList []ArticleOptionResp
for _, opt := range article.Options {
isVoted := false
if uidValid {
for _, votedID := range votedOptionIDs {
if opt.ID == votedID {
isVoted = true
break
}
}
}
optionList = append(optionList, ArticleOptionResp{
ID: opt.ID,
Name: opt.OptionContent,
Votes: opt.OptionVotesNum,
IsVotedByUser: isVoted,
})
}
// 5.3 获取发布者用户名(核心修改:从映射中查询)
publisherName := uidToUsername[article.PublishUserID]
if publisherName == "" {
publisherName = "未知用户" // 处理用户不存在的情况
}
// 5.4 组装最终响应
articleData := ArticleResponse{
ID: article.ArticleID,
Title: article.Title,
VoteType: article.VoteType,
TotalVoters: article.TotalVotersNum,
EndTime: article.EndTime.Format("2006-01-02 15:04:05"),
IsEnded: article.IsEnded,
PublisherID: article.PublishUserID,
PublisherName: publisherName, // 填充用户名
CreateTime: article.CreateTime.Format("2006-01-02 15:04:05"),
Options: optionList,
UserHasVoted: userHasVoted,
VotedOptionIDs: votedOptionIDs,
}
responseList = append(responseList, articleData)
}
// 6. 返回响应
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": fmt.Sprintf("查询成功,共 %d 篇文章", len(responseList)),
"data": responseList,
})
}