Files
2025-11-17 13:32:54 +08:00

464 lines
12 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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