diff --git a/controllers/article/getarticle.go b/controllers/article/getarticle.go index 122fdd4..6dfb3a4 100644 --- a/controllers/article/getarticle.go +++ b/controllers/article/getarticle.go @@ -11,31 +11,27 @@ import ( ) // ArticleList 数据库文章记录结构体 -// 添加了与 ArticleOption 的关联 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"` - // 这是关键:定义 Has Many 关联,表示一篇文章有多个选项 - Options []ArticleOption `gorm:"foreignKey:VoteArticleID;references:ArticleID"` + 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"` // 外键,关联 ArticleList + 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"` } -// UserVote 用户投票记录表结构 - // ArticleOptionResp 格式化后的选项响应结构 type ArticleOptionResp struct { ID int64 `json:"id"` @@ -59,15 +55,16 @@ type ArticleResponse struct { VotedOptionIDs []int64 `json:"user_voted_option_ids"` } +// UserReq 请求参数结构体,允许uid为空 type UserReq struct { - Uid string `json:"uid" binding:"required"` + Uid string `json:"uid" binding:"omitempty"` // 允许uid为空,空字符串也合法 } -// ArticleListget 获取所有文评及选项信息(包含用户投票状态) +// ArticleListget 获取所有文评及选项信息(支持空uid场景) func ArticleListget(c *gin.Context) { var req UserReq - // 1. 解析并验证请求参数 + // 1. 解析请求参数,uid为空也能通过校验 if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "参数解析失败", @@ -76,7 +73,7 @@ func ArticleListget(c *gin.Context) { return } - // 2. 使用 Preload 一次性查询所有文章和它们的选项 + // 2. 查询所有文章及关联的选项 var articles []ArticleList if err := databaseInit.UserDB.Model(&ArticleList{}). Preload("Options", func(db *gorm.DB) *gorm.DB { @@ -89,35 +86,57 @@ func ArticleListget(c *gin.Context) { return } - // 3. 一次性查询当前用户的所有投票记录,并构建一个 map 方便查找 - 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 - } - // 投票记录 map:key: articleId, value: []optionId + // 3. 根据uid是否存在(包括空字符串)决定是否查询投票记录 userVotesMap := make(map[int64][]int64) - for _, vote := range userAllVotes { - userVotesMap[vote.VoteArticleID] = append(userVotesMap[vote.VoteArticleID], vote.OptionID) - } + // 判断uid是否有效(非空字符串) + uidValid := req.Uid != "" - // 4. 组装最终响应数据 + if uidValid { + // 3.1 仅当uid有效时查询用户投票记录 + 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) + } + } + // 3.2 当uid为空时,不执行任何投票查询,保持映射为空 + + // 4. 组装响应数据 var responseList []ArticleResponse for _, article := range articles { - votedOptionIDs, userHasVoted := userVotesMap[article.ArticleID] + // 处理投票状态 + var votedOptionIDs []int64 + var userHasVoted bool + if uidValid { + votedOptionIDs, userHasVoted = userVotesMap[article.ArticleID] + } else { + // uid为空时,默认未投票 + votedOptionIDs = []int64{} + userHasVoted = false + } - // 格式化选项数据 + // 处理选项列表 var optionList []ArticleOptionResp for _, opt := range article.Options { isVoted := false - for _, votedID := range votedOptionIDs { - if opt.ID == votedID { - isVoted = true - break + if uidValid { + // 仅在uid有效时检查是否投票 + for _, votedID := range votedOptionIDs { + if opt.ID == votedID { + isVoted = true + break + } } } + // uid为空时isVoted保持false optionList = append(optionList, ArticleOptionResp{ ID: opt.ID, Name: opt.OptionContent, @@ -126,6 +145,7 @@ func ArticleListget(c *gin.Context) { }) } + // 组装文章响应 articleData := ArticleResponse{ ID: article.ArticleID, Title: article.Title, @@ -142,6 +162,7 @@ func ArticleListget(c *gin.Context) { responseList = append(responseList, articleData) } + // 5. 返回响应 c.JSON(http.StatusOK, gin.H{ "success": true, "message": fmt.Sprintf("查询成功,共 %d 篇文章", len(responseList)),