package controller import ( "fmt" "github.com/gin-gonic/gin" "net/http" "strconv" "time" "vote-api/api/dao" "vote-api/api/dto" "vote-api/api/model" "vote-api/api/requests" "vote-api/api/responses" "vote-api/api/service" "vote-api/consts" "vote-api/global" "vote-api/utils" ) type Article struct{} // GetArticlePage 获取图文列表-分页 func (r *Article) GetArticlePage(c *gin.Context) { articleRequest := requests.ArticleRequest{} req := articleRequest.GetArticlePage if err := c.ShouldBind(&req); err != nil { responses.FailWithMessage(err.Error(), c) return } // 参数验证 if err := global.Validate.Struct(req); err != nil { responses.FailWithMessage(utils.Translate(err), c) return } if req.Page == 0 { req.Page = 1 } if req.PageSize == 0 { req.PageSize = 20 } // 获取数据 articleDao := dao.ArticleDao{} articles, total, err := articleDao.GetArticlePageSearch(req, req.Page, req.PageSize) if err != nil { responses.FailWithMessage(err.Error(), c) return } // 处理返回值 g := dto.GetArticleListDto(articles) // 检测用户今日是否投票 userId := c.GetInt64("UserId") if userId != 0 { userService := service.UserService{} for _, articleDto := range g { articleId, err := strconv.ParseInt(articleDto.ArticleId, 10, 64) if err != nil { continue } articleDto.IsVote = userService.CheckUserVoteDay(userId, articleId, 1) } } result := make(map[string]interface{}) result["page"] = req.Page result["page_size"] = req.PageSize result["total"] = total result["data"] = g responses.OkWithData(result, c) } // GetArticle 获取图文详情 func (r *Article) GetArticle(c *gin.Context) { id := c.Param("article_id") if id == "" { responses.FailWithMessage("缺少参数", c) return } // 将 id 转换为 int64 类型 articleId, err := strconv.ParseInt(id, 10, 64) if err != nil { responses.Fail(c) return } // 获取数据 articleDao := dao.ArticleDao{} article, err := articleDao.GetArticleById(articleId) if err != nil { responses.FailWithMessage("文章错误", c) return } // 获取文章作者 articleAuthorDao := dao.ArticleAuthorDao{} articleAuthors, err := articleAuthorDao.GetArticleAuthorListPreloadByAuthorId(articleId) if err != nil { responses.FailWithMessage("文章错误", c) return } article.ArticleAuthor = articleAuthors // 获取排名 rank, _ := articleDao.GetArticleRank(article.ArticleId) // 处理返回值 g := dto.GetArticleDto(article) // 加载数据-作者 g.LoadArticleAuthor(article.ArticleAuthor) // 加载数据-作者排名 g.LoadRank(rank) // 检测用户今日是否投票 userId := c.GetInt64("UserId") if userId != 0 { userService := service.UserService{} isVote := userService.CheckUserVoteDay(userId, articleId, 1) // 加载数据-投票状态 g.LoadVoteStatus(isVote) } responses.OkWithData(g, c) } // GetArticleRankList 获取文章排名列表 func (r *Article) GetArticleRankList(c *gin.Context) { // 检测投票有效期 systemTimeService := service.SystemTimeService{} isValid := systemTimeService.CheckVoteValidStatus() if isValid == false { responses.OkWithData(nil, c) return } // 获取数据 articleDao := dao.ArticleDao{} maps := make(map[string]interface{}) maps["article_status"] = 1 articles, err := articleDao.GetArticleRankList(maps, "vote_num desc", 15) if err != nil { responses.OkWithData(nil, c) return } // 处理返回值 g := dto.GetArticleListDto(articles) // 检测用户今日是否投票 userId := c.GetInt64("UserId") if userId != 0 { userService := service.UserService{} for _, articleDto := range g { articleId, err := strconv.ParseInt(articleDto.ArticleId, 10, 64) if err != nil { continue } articleDto.IsVote = userService.CheckUserVoteDay(userId, articleId, 1) } } responses.OkWithData(g, c) } // AddArticleVote 文章投票 func (r *Article) AddArticleVote(c *gin.Context) { id := c.Param("article_id") if id == "" { responses.FailWithMessage("缺少参数", c) return } // 将 id 转换为 int64 类型 articleId, err := strconv.ParseInt(id, 10, 64) if err != nil { responses.Fail(c) return } userId := c.GetInt64("UserId") if userId == 0 { c.JSON(http.StatusUnauthorized, gin.H{ "message": "请登录后投票", "code": consts.TokenError, "data": "", }) return } // 检测并发请求 redisKey := "AddArticleVote" + fmt.Sprintf("%d", userId) + fmt.Sprintf("%d", articleId) res, _ := global.Redis.Get(c, redisKey).Result() if res != "" { responses.FailWithMessage("请勿重复操作", c) return } defer func(redisKey string) { global.Redis.Del(c, redisKey) }(redisKey) // 添加缓存 _, err = global.Redis.Set(c, redisKey, "1", (1)*time.Second).Result() if err != nil { responses.FailWithMessage("投票失败", c) return } // 获取数据 articleDao := dao.ArticleDao{} article, err := articleDao.GetArticleById(articleId) if err != nil || article == nil { responses.FailWithMessage("非法数据", c) return } // 检测投票有效期 systemTimeService := service.SystemTimeService{} isValid := systemTimeService.CheckVoteValidStatus() if isValid == false { responses.FailWithMessage("投票已结束", c) return } // 检测用户今日是否投票 userService := service.UserService{} isVote := userService.CheckUserVoteDay(userId, articleId, 1) if isVote == true { responses.FailWithMessage("请勿重复投票", c) return } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() utils.LogJsonErr("投票失败", r) responses.FailWithMessage("投票失败", c) return } }() // 增加投票数 err = articleDao.Inc(tx, articleId, "vote_num", 1) if err != nil { tx.Rollback() responses.FailWithMessage("投票失败", c) return } // 增加投票记录 nowDay, _ := time.Parse("2006-01-02", time.Now().Format("2006-01-02")) votedAt := model.LocalTime(nowDay) articleVoteDay := &model.ArticleVoteDay{ ArticleId: articleId, UserId: userId, VotedAt: &votedAt, } articleVoteDayDao := dao.ArticleVoteDayDao{} articleVoteDay, err = articleVoteDayDao.AddArticleVoteDay(tx, articleVoteDay) if err != nil { tx.Rollback() responses.FailWithMessage("投票失败", c) return } // 增加数据表-投票数量 dataDao := dao.DataDao{} err = dataDao.Inc(tx, 1, "vote_num", 1) if err != nil { tx.Rollback() responses.FailWithMessage("投票失败", c) return } // 新增投票缓存 result := userService.AddUserVoteDayCache(userId, articleId, 1) if result == false { tx.Rollback() responses.FailWithMessage("投票失败", c) return } tx.Commit() responses.Ok(c) }