This repository has been archived on 2026-06-21. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MetaLab/internal/controller/reaction_controller.go
Victor_Jay 2b47380ac5 feat: 实现赞/踩系统(P2)
- 新增 PostLike/PostDislike 模型,复合主键 (user_id, post_id)
- Post 表新增 LikesCount/DislikesCount 冗余计数器
- Repository 层:reaction_repo.go,含 WithTx 事务支持
- Service 层:reaction_service.go,赞踩互斥逻辑(6 态切换),事务包裹
- Controller 层:reaction_controller.go,3 个 API(ToggleLike/ToggleDislike/GetReaction)
- 接口定义:controller/interfaces.go 新增 reactionUseCase,service/repository.go 新增 ReactionStore
- 路由注册 + 依赖注入 + AutoMigrate
- 前端:文章详情页赞踩按钮 + 状态查询 + 401 跳转登录
- 样式:posts.css 新增赞踩按钮样式
2026-06-01 15:48:18 +08:00

109 lines
2.6 KiB
Go

package controller
import (
"net/http"
"strconv"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/service"
"github.com/gin-gonic/gin"
)
// ReactionController 赞/踩 API 控制器
type ReactionController struct {
reactionSvc reactionUseCase
}
// NewReactionController 构造函数
func NewReactionController(reactionSvc reactionUseCase) *ReactionController {
return &ReactionController{reactionSvc: reactionSvc}
}
// ToggleLike 切换点赞 POST /api/posts/:id/like
func (rc *ReactionController) ToggleLike(c *gin.Context) {
uid, _, ok := common.GetGinUser(c)
if !ok {
common.Error(c, http.StatusUnauthorized, "请先登录")
return
}
postID, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的文章ID")
return
}
isLiked, err := rc.reactionSvc.ToggleLike(uid, uint(postID))
if err != nil {
common.Error(c, http.StatusInternalServerError, "操作失败")
return
}
// 获取最新点赞数
likesCount, _ := rc.reactionSvc.GetPostLikesCount(uint(postID))
common.Ok(c, gin.H{
"liked": isLiked,
"likes_count": likesCount,
})
}
// ToggleDislike 切换踩 POST /api/posts/:id/dislike
func (rc *ReactionController) ToggleDislike(c *gin.Context) {
uid, _, ok := common.GetGinUser(c)
if !ok {
common.Error(c, http.StatusUnauthorized, "请先登录")
return
}
postID, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的文章ID")
return
}
isDisliked, err := rc.reactionSvc.ToggleDislike(uid, uint(postID))
if err != nil {
common.Error(c, http.StatusInternalServerError, "操作失败")
return
}
common.Ok(c, gin.H{
"disliked": isDisliked,
})
}
// GetReaction 查询当前用户对文章的反应状态 GET /api/posts/:id/reaction
func (rc *ReactionController) GetReaction(c *gin.Context) {
postID, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的文章ID")
return
}
// 未登录用户返回 none + 公开计数
uid, _, ok := common.GetGinUser(c)
if !ok {
likesCount, _ := rc.reactionSvc.GetPostLikesCount(uint(postID))
common.Ok(c, gin.H{
"reaction": string(service.ReactionNone),
"likes_count": likesCount,
})
return
}
reaction, err := rc.reactionSvc.GetReaction(uid, uint(postID))
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
likesCount, _ := rc.reactionSvc.GetPostLikesCount(uint(postID))
common.Ok(c, gin.H{
"reaction": string(reaction),
"likes_count": likesCount,
})
}