Files

464 lines
12 KiB
Go
Raw Permalink Normal View History

2025-11-17 13:32:54 +08:00
package handler
import (
"dianshang/internal/model"
"dianshang/internal/service"
"dianshang/pkg/response"
"dianshang/pkg/utils"
"encoding/json"
"strconv"
"github.com/gin-gonic/gin"
)
type CommentHandler struct {
commentService *service.CommentService
}
// CommentResponse 评论响应结构
type CommentResponse struct {
ID uint `json:"id"`
UserID uint `json:"user_id"`
ProductID uint `json:"product_id"`
OrderID uint `json:"order_id"`
OrderItemID uint `json:"order_item_id"`
Rating int `json:"rating"`
Content string `json:"content"`
Images []string `json:"images"`
IsAnonymous bool `json:"is_anonymous"`
Status int `json:"status"`
ReplyCount int `json:"reply_count"`
LikeCount int `json:"like_count"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
UserName string `json:"user_name"` // 映射字段
OrderNo string `json:"order_no"` // 映射字段
User *model.User `json:"user,omitempty"`
Product *model.Product `json:"product,omitempty"`
Order *model.Order `json:"order,omitempty"`
OrderItem *model.OrderItem `json:"order_item,omitempty"`
Replies []model.CommentReply `json:"replies,omitempty"`
AdminReply *AdminReplyResponse `json:"admin_reply,omitempty"`
}
// AdminReplyResponse 管理员回复响应结构
type AdminReplyResponse struct {
Content string `json:"content"`
AdminName string `json:"admin_name"`
CreatedAt string `json:"created_at"`
}
func NewCommentHandler(commentService *service.CommentService) *CommentHandler {
return &CommentHandler{
commentService: commentService,
}
}
// CreateComment 创建评论
func (h *CommentHandler) CreateComment(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
var req service.CreateCommentRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, err.Error())
return
}
comment, err := h.commentService.CreateComment(userID.(uint), &req)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, comment)
}
// GetProductComments 获取商品评论列表
func (h *CommentHandler) GetProductComments(c *gin.Context) {
productIDStr := c.Param("product_id")
productID := utils.StringToUint(productIDStr)
if productID == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "商品ID无效")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
rating, _ := strconv.Atoi(c.DefaultQuery("rating", "0"))
comments, total, err := h.commentService.GetProductComments(productID, page, pageSize, rating)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Page(c, comments, total, page, pageSize)
}
// GetUserComments 获取用户评论列表
func (h *CommentHandler) GetUserComments(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
comments, total, err := h.commentService.GetUserComments(userID.(uint), page, pageSize)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Page(c, comments, total, page, pageSize)
}
// GetCommentStats 获取商品评论统计
func (h *CommentHandler) GetCommentStats(c *gin.Context) {
productIDStr := c.Param("product_id")
productID := utils.StringToUint(productIDStr)
if productID == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "商品ID无效")
return
}
stats, err := h.commentService.GetCommentStats(productID)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, stats)
}
// GetCommentDetail 获取评论详情
func (h *CommentHandler) GetCommentDetail(c *gin.Context) {
idStr := c.Param("id")
id := utils.StringToUint(idStr)
if id == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "评论ID无效")
return
}
comment, err := h.commentService.GetCommentByID(id)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
// 转换为响应格式
commentResponse := h.convertToResponse(*comment)
response.Success(c, commentResponse)
}
// CreateReply 创建评论回复
func (h *CommentHandler) CreateReply(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
var req service.CreateReplyRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, err.Error())
return
}
reply, err := h.commentService.CreateReply(userID.(uint), &req, false)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, reply)
}
// convertToResponse 转换评论为响应格式
func (h *CommentHandler) convertToResponse(comment model.Comment) CommentResponse {
// 解析图片数组
var images []string
if comment.Images != "" {
if err := json.Unmarshal([]byte(comment.Images), &images); err != nil {
// 如果解析失败,返回空数组
images = []string{}
}
} else {
images = []string{}
}
result := CommentResponse{
ID: comment.ID,
UserID: comment.UserID,
ProductID: comment.ProductID,
OrderID: comment.OrderID,
OrderItemID: comment.OrderItemID,
Rating: comment.Rating,
Content: comment.Content,
Images: images,
IsAnonymous: comment.IsAnonymous,
Status: comment.Status,
ReplyCount: comment.ReplyCount,
LikeCount: comment.LikeCount,
CreatedAt: comment.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: comment.UpdatedAt.Format("2006-01-02 15:04:05"),
User: &comment.User,
Product: &comment.Product,
Order: &comment.Order,
OrderItem: &comment.OrderItem,
Replies: comment.Replies,
}
// 映射用户名字段
if comment.User.ID > 0 {
result.UserName = comment.User.Nickname
}
// 映射订单号字段
if comment.Order.ID > 0 {
result.OrderNo = comment.Order.OrderNo
}
// 提取管理员回复
for _, reply := range comment.Replies {
if reply.IsAdmin && reply.Status == 1 { // 只取正常状态的管理员回复
adminName := "管理员"
if reply.User.ID > 0 && reply.User.Nickname != "" {
adminName = reply.User.Nickname
}
result.AdminReply = &AdminReplyResponse{
Content: reply.Content,
AdminName: adminName,
CreatedAt: reply.CreatedAt.Format("2006-01-02 15:04:05"),
}
break // 只取第一个管理员回复
}
}
return result
}
// convertToResponseList 转换评论列表为响应格式
func (h *CommentHandler) convertToResponseList(comments []model.Comment) []CommentResponse {
result := make([]CommentResponse, len(comments))
for i, comment := range comments {
result[i] = h.convertToResponse(comment)
}
return result
}
// LikeComment 点赞评论
func (h *CommentHandler) LikeComment(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
idStr := c.Param("id")
commentID := utils.StringToUint(idStr)
if commentID == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "评论ID无效")
return
}
err := h.commentService.LikeComment(commentID, userID.(uint))
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, nil)
}
// UnlikeComment 取消点赞评论
func (h *CommentHandler) UnlikeComment(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
idStr := c.Param("id")
commentID := utils.StringToUint(idStr)
if commentID == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "评论ID无效")
return
}
err := h.commentService.UnlikeComment(commentID, userID.(uint))
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, nil)
}
// GetUncommentedOrderItems 获取用户未评论的订单项
func (h *CommentHandler) GetUncommentedOrderItems(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
orderItems, err := h.commentService.GetUncommentedOrderItems(userID.(uint))
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, orderItems)
}
// ===== 管理端接口 =====
// GetCommentListForAdmin 获取评论列表(管理端)
func (h *CommentHandler) GetCommentListForAdmin(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
conditions := make(map[string]interface{})
if productID := c.Query("product_id"); productID != "" {
conditions["product_id"] = utils.StringToUint(productID)
}
if userID := c.Query("user_id"); userID != "" {
conditions["user_id"] = utils.StringToUint(userID)
}
if rating := c.Query("rating"); rating != "" {
conditions["rating"] = utils.StringToUint(rating)
}
if status := c.Query("status"); status != "" {
conditions["status"] = utils.StringToUint(status)
}
if keyword := c.Query("keyword"); keyword != "" {
conditions["keyword"] = keyword
}
comments, total, err := h.commentService.GetCommentList(page, pageSize, conditions)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
// 转换为响应格式
commentsResponse := h.convertToResponseList(comments)
response.Page(c, commentsResponse, total, page, pageSize)
}
// UpdateCommentStatus 更新评论状态(管理端)
func (h *CommentHandler) UpdateCommentStatus(c *gin.Context) {
idStr := c.Param("id")
id := utils.StringToUint(idStr)
if id == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "评论ID无效")
return
}
var req struct {
Status int `json:"status" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, err.Error())
return
}
err := h.commentService.UpdateCommentStatus(id, req.Status)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, nil)
}
// DeleteComment 删除评论(管理端)
func (h *CommentHandler) DeleteComment(c *gin.Context) {
idStr := c.Param("id")
id := utils.StringToUint(idStr)
if id == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "评论ID无效")
return
}
err := h.commentService.DeleteComment(id)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, nil)
}
// CreateAdminReply 管理员回复评论
func (h *CommentHandler) CreateAdminReply(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
var req service.CreateReplyRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, err.Error())
return
}
reply, err := h.commentService.CreateReply(userID.(uint), &req, true)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, reply)
}
// CreateAdminReplyForComment 管理员回复指定评论
func (h *CommentHandler) CreateAdminReplyForComment(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c)
return
}
// 从URL参数获取评论ID
commentIDStr := c.Param("id")
commentID := utils.StringToUint(commentIDStr)
if commentID == 0 {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的评论ID")
return
}
// 定义请求结构只需要content字段
var reqBody struct {
Content string `json:"content" binding:"required"`
}
if err := c.ShouldBindJSON(&reqBody); err != nil {
response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, err.Error())
return
}
// 构造CreateReplyRequest
req := service.CreateReplyRequest{
CommentID: commentID,
Content: reqBody.Content,
}
reply, err := h.commentService.CreateReply(userID.(uint), &req, true)
if err != nil {
response.ErrorWithMessage(c, response.ERROR, err.Error())
return
}
response.Success(c, reply)
}