package controller import ( "fmt" "github.com/gin-gonic/gin" "net/http" "sort" "strconv" "time" "vote-video-api/api/dao" "vote-video-api/api/dto" "vote-video-api/api/model" "vote-video-api/api/requests" "vote-video-api/api/responses" "vote-video-api/api/service" "vote-video-api/consts" "vote-video-api/global" "vote-video-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 // 处理返回值 g := dto.GetArticleDto(article) // 获取排名开关限制 systemConfigDao := dao.SystemConfigDao{} systemConfig, err := systemConfigDao.GetSystemConfigById(1) if err != nil { responses.OkWithData(nil, c) return } if systemConfig.IsDisplayRank == 1 { // 获取大于某一投票数的文章 maps := make(map[string]interface{}) maps["article_status"] = 1 articles, err := articleDao.GetArticleListGtVoteNum(maps, article.VoteNum) if err == nil { rank := len(articles) + 1 // 加载数据-作者排名 g.LoadRank(rank) } } // 加载数据-作者 g.LoadArticleAuthor(article.ArticleAuthor) // 检测用户今日是否投票 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) { // 获取排名开关限制 systemConfigDao := dao.SystemConfigDao{} systemConfig, err := systemConfigDao.GetSystemConfigById(1) if err != nil { responses.OkWithData(nil, c) return } if systemConfig.IsDisplayRank == 0 { 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 } // 处理数据 for i, article := range articles { // 判断最后两位票数是否相同 if i == 14 { maps = make(map[string]interface{}) maps["article_status"] = 1 maps["vote_num"] = article.VoteNum results, err := articleDao.GetArticleList(maps) if err != nil { responses.OkWithData(nil, c) return } for _, result := range results { if result.ArticleId == article.ArticleId { continue } articles = append(articles, result) } } } // 处理返回值 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) } } // 根据 VoteNum 降序排序 sort.SliceStable(g, func(i, j int) bool { return g[i].VoteNum > g[j].VoteNum }) // 计算排名 var currentRank int for k, v := range g { if k == 0 { // 第一个元素,排名设为1 currentRank = 1 } else if g[k].VoteNum < g[k-1].VoteNum { currentRank = k + 1 } // 为当前元素设置 Rank rank := currentRank // 创建一个新的变量来保存排名 v.Rank = &rank // 将新的变量的地址赋给 Rank } 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) }