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) }