464 lines
12 KiB
Go
464 lines
12 KiB
Go
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)
|
||
} |