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 新增赞踩按钮样式
This commit is contained in:
@ -103,3 +103,11 @@ type commentUseCase interface {
|
||||
ListReplies(rootID uint) ([]model.Comment, error)
|
||||
SearchUsers(keyword string) ([]model.UserSearchResult, error)
|
||||
}
|
||||
|
||||
// reactionUseCase ReactionController 对 ReactionService 的最小依赖(ISP:4 个方法)
|
||||
type reactionUseCase interface {
|
||||
ToggleLike(userID, postID uint) (bool, error)
|
||||
ToggleDislike(userID, postID uint) (bool, error)
|
||||
GetReaction(userID, postID uint) (service.ReactionType, error)
|
||||
GetPostLikesCount(postID uint) (int, error)
|
||||
}
|
||||
|
||||
108
internal/controller/reaction_controller.go
Normal file
108
internal/controller/reaction_controller.go
Normal file
@ -0,0 +1,108 @@
|
||||
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,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user