package handler import ( "dianshang/internal/model" "dianshang/internal/service" "dianshang/pkg/response" "dianshang/pkg/utils" "fmt" "log" "github.com/gin-gonic/gin" ) // OrderHandler 订单处理器 type OrderHandler struct { orderService *service.OrderService wechatPayService *service.WeChatPayService } // NewOrderHandler 创建订单处理器 func NewOrderHandler(orderService *service.OrderService, wechatPayService *service.WeChatPayService) *OrderHandler { return &OrderHandler{ orderService: orderService, wechatPayService: wechatPayService, } } // CreateOrder 创建订单 func (h *OrderHandler) CreateOrder(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } var req service.CreateOrderRequest if err := c.ShouldBindJSON(&req); err != nil { fmt.Printf("DEBUG: 订单创建请求绑定失败: %v\n", err) fmt.Printf("DEBUG: 请求体内容: %s\n", c.Request.Body) response.BadRequest(c, "鍙傛暟閿欒: "+err.Error()) return } fmt.Printf("DEBUG: 成功绑定的订单请求: AddressID=%d, Items=%+v, Remark=%s\n", req.AddressID, req.Items, req.Remark) order, err := h.orderService.CreateOrder(userID.(uint), &req) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, order) } // GetUserOrders 获取用户订单列表 func (h *OrderHandler) GetUserOrders(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } page := utils.StringToInt(c.DefaultQuery("page", "1")) pageSize := utils.StringToInt(c.DefaultQuery("page_size", "20")) statusStr := c.Query("status") status := 0 if statusStr != "" { frontendStatus := utils.StringToInt(statusStr) // 前端和数据库状态保持一致: // 1=未付款, 2=已付款/待发货, 3=待发货, 4=已发货, 5=待收货, 6=已完成, 7=已取消, 8=退货中, 9=已退款 status = frontendStatus } orders, pagination, err := h.orderService.GetUserOrders(userID.(uint), status, page, pageSize) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } // 格式化订单列表数据 formattedOrders := h.formatOrderList(orders) response.Page(c, formattedOrders, pagination.Total, pagination.Page, pagination.PageSize) } // OrderListResponse 订单列表响应结构 type OrderListResponse struct { ID string `json:"id"` OrderNo string `json:"order_no"` StoreID uint `json:"store_id"` StoreName string `json:"store_name"` Status int `json:"status"` StatusName string `json:"status_name"` TotalAmount float64 `json:"total_amount"` PayAmount float64 `json:"pay_amount"` PayStatus int `json:"pay_status"` ReceiverName string `json:"receiver_name"` ReceiverPhone string `json:"receiver_phone"` ReceiverAddress string `json:"receiver_address"` ExpressCompany string `json:"express_company"` ExpressNo string `json:"express_no"` CreatedAt string `json:"created_at"` Items []OrderItemResponse `json:"items"` } // formatOrderList 格式化订单列表响应 func (h *OrderHandler) formatOrderList(orders []model.Order) []OrderListResponse { result := make([]OrderListResponse, len(orders)) for i, order := range orders { // 获取状态描述 - 使用统一状态机 statusName := "未知状态" switch order.Status { case 1: statusName = "未付款" case 2: statusName = "待发货" // 统一为待发货 case 3: statusName = "待发货" // 统一为待发货 case 4: statusName = "已发货" case 5: statusName = "待收货" case 6: statusName = "已完成" case 7: statusName = "已取消" case 8: statusName = "退货中" case 9: statusName = "已退款" } // 格式化订单项 items := make([]OrderItemResponse, len(order.OrderItems)) for j, item := range order.OrderItems { items[j] = OrderItemResponse{ ID: fmt.Sprintf("%d", item.ID), OrderID: fmt.Sprintf("%d", item.OrderID), ProductID: item.ProductID, SpecID: item.SpecID, SKUID: item.SKUID, Quantity: item.Quantity, Price: item.Price, TotalPrice: item.TotalPrice, ProductName: item.ProductName, ProductImage: item.ProductImage, // 这里包含了商品图片 SpecName: item.SpecName, SpecValue: item.SpecValue, SpecInfo: item.SpecInfo, } } // 获取店铺名称 storeName := "默认店铺" if order.Store.Name != "" { storeName = order.Store.Name } result[i] = OrderListResponse{ ID: fmt.Sprintf("%d", order.ID), OrderNo: order.OrderNo, StoreID: order.StoreID, StoreName: storeName, Status: order.Status, StatusName: statusName, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, PayStatus: order.PayStatus, ReceiverName: order.ReceiverName, ReceiverPhone: order.ReceiverPhone, ReceiverAddress: order.ReceiverAddress, ExpressCompany: order.LogisticsCompany, ExpressNo: order.LogisticsNo, CreatedAt: order.CreatedAt.Format("2006-01-02 15:04:05"), Items: items, } } return result } // OrderDetailResponse 订单详情响应结构 - 匹配前端期望格式 type OrderDetailResponse struct { OrderID string `json:"orderId"` OrderNo string `json:"orderNo"` ParentOrderNo string `json:"parentOrderNo"` StoreID uint `json:"storeId"` StoreName string `json:"storeName"` OrderStatus int `json:"orderStatus"` OrderStatusName string `json:"orderStatusName"` PaymentAmount int64 `json:"paymentAmount"` GoodsAmountApp int64 `json:"goodsAmountApp"` TotalAmount int64 `json:"totalAmount"` PayAmount int64 `json:"payAmount"` CouponAmount int64 `json:"couponAmount"` Status int `json:"status"` PayStatus int `json:"payStatus"` CreatedAt string `json:"createdAt"` LogisticsVO *LogisticsVOResponse `json:"logisticsVO"` OrderItemVOs []OrderItemVOResponse `json:"orderItemVOs"` ButtonVOs []OrderButtonVO `json:"buttonVOs"` } // OrderButtonVO 订单按钮响应结构 type OrderButtonVO struct { Primary bool `json:"is_primary"` Type int `json:"type"` Name string `json:"text"` } // LogisticsVOResponse 物流信息响应结构 type LogisticsVOResponse struct { LogisticsNo string `json:"logisticsNo"` ReceiverProvince string `json:"receiverProvince"` ReceiverCity string `json:"receiverCity"` ReceiverCountry string `json:"receiverCountry"` // 区县 ReceiverAddress string `json:"receiverAddress"` ReceiverName string `json:"receiverName"` ReceiverPhone string `json:"receiverPhone"` } // OrderItemVOResponse 订单项响应结构 type OrderItemVOResponse struct { ID string `json:"id"` GoodsName string `json:"goodsName"` GoodsPictureUrl string `json:"goodsPictureUrl"` ActualPrice int64 `json:"actualPrice"` OriginPrice int64 `json:"originPrice"` BuyQuantity int `json:"buyQuantity"` SkuID uint `json:"skuId"` SpuID uint `json:"spuId"` Specifications []SpecificationResponse `json:"specifications"` ButtonVOs []interface{} `json:"buttonVOs"` } // SpecificationResponse 规格响应结构 type SpecificationResponse struct { SpecTitle string `json:"specTitle"` SpecValue string `json:"specValue"` } // AddressResponse 地址响应结构 type AddressResponse struct { Name string `json:"name"` Phone string `json:"phone"` Province string `json:"province"` City string `json:"city"` District string `json:"district"` Detail string `json:"detail"` FullAddress string `json:"full_address"` } // OrderItemResponse 订单项响应结构 type OrderItemResponse struct { ID string `json:"id"` OrderID string `json:"order_id"` ProductID uint `json:"product_id"` SpecID *uint `json:"spec_id"` SKUID *uint `json:"sku_id"` Quantity int `json:"quantity"` Price float64 `json:"price"` TotalPrice float64 `json:"total_price"` ProductName string `json:"product_name"` ProductImage string `json:"product_image"` SpecName string `json:"spec_name"` SpecValue string `json:"spec_value"` SpecInfo map[string]interface{} `json:"spec_info"` Product *ProductResponse `json:"product,omitempty"` SKU *SKUResponse `json:"sku,omitempty"` } // ProductResponse 商品响应结构 type ProductResponse struct { ID uint `json:"id"` Name string `json:"name"` MainImage string `json:"main_image"` } // SKUResponse SKU响应结构 type SKUResponse struct { ID uint `json:"id"` Name string `json:"name"` Value string `json:"value"` } // StoreResponse 店铺响应结构 type StoreResponse struct { ID uint `json:"id"` Name string `json:"name"` } // GetOrderDetail 获取订单详情(支持订单ID、订单号、微信订单号) // 参数 id 可以是: // 1. 订单ID(纯数字) // 2. 订单号(如:WX20251111134319259VLQCPCC1) // 3. 微信支付订单号(如:wx1234567890abcdef) func (h *OrderHandler) GetOrderDetail(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } idStr := c.Param("id") // 尝试解析为uint,如果失败则当作订单号或微信订单号处理 orderID := utils.StringToUint(idStr) if orderID == 0 { // 当作订单号或微信订单号处理(service层会自动判断) order, err := h.orderService.GetOrderDetailByOrderNo(userID.(uint), idStr) if err != nil { response.ErrorWithMessage(c, response.ERROR_ORDER_NOT_FOUND, err.Error()) return } response.Success(c, h.formatOrderDetail(order)) return } // 当作订单ID处理 order, err := h.orderService.GetOrderDetail(userID.(uint), orderID) if err != nil { response.ErrorWithMessage(c, response.ERROR_ORDER_NOT_FOUND, err.Error()) return } response.Success(c, h.formatOrderDetail(order)) } // formatOrderDetail 格式化订单详情响应 func (h *OrderHandler) formatOrderDetail(order *model.Order) *OrderDetailResponse { // 构建物流信息对象 logisticsVO := &LogisticsVOResponse{ LogisticsNo: order.LogisticsNo, ReceiverProvince: "", // 省份,如果有的话 ReceiverCity: "", // 城市,如果有的话 ReceiverCountry: "", // 区县,如果有的话 ReceiverAddress: order.ReceiverAddress, ReceiverName: order.ReceiverName, ReceiverPhone: order.ReceiverPhone, } // 构建订单项列表 orderItemVOs := make([]OrderItemVOResponse, len(order.OrderItems)) for i, item := range order.OrderItems { // 构建规格信息数组 specifications := []SpecificationResponse{} if item.SpecInfo != nil { // JSONMap 就是 map[string]interface{} for key, value := range item.SpecInfo { if value != nil { specifications = append(specifications, SpecificationResponse{ SpecTitle: key, SpecValue: fmt.Sprintf("%v", value), }) } } } var skuID uint if item.SKUID != nil { skuID = *item.SKUID } orderItemVOs[i] = OrderItemVOResponse{ ID: fmt.Sprintf("%d", item.ID), GoodsName: item.ProductName, GoodsPictureUrl: item.ProductImage, ActualPrice: int64(item.Price), // 数据库已存储元为单位,无需乘100 OriginPrice: int64(item.Price), // 数据库已存储元为单位,无需乘100 BuyQuantity: item.Quantity, SkuID: skuID, SpuID: item.ProductID, Specifications: specifications, ButtonVOs: []interface{}{}, // 空数组 } } // 获取状态描述 - 使用统一状态机 statusName := "未知状态" switch order.Status { case 1: statusName = "未付款" case 2: statusName = "待发货" // 统一为待发货 case 3: statusName = "待发货" // 统一为待发货 case 4: statusName = "已发货" case 5: statusName = "待收货" case 6: statusName = "已完成" case 7: statusName = "已取消" case 8: statusName = "退货中" case 9: statusName = "已退款" } // 生成订单操作按钮 buttonVOs := generateOrderButtons(order.Status, order) return &OrderDetailResponse{ OrderID: fmt.Sprintf("%d", order.ID), OrderNo: order.OrderNo, ParentOrderNo: order.OrderNo, // 如果没有父订单号,使用订单号 StoreID: order.StoreID, StoreName: order.Store.Name, OrderStatus: order.Status, OrderStatusName: statusName, PaymentAmount: int64(order.PayAmount), // 数据库已存储元为单位,无需乘100 GoodsAmountApp: int64(order.TotalAmount), // 数据库已存储元为单位,无需乘100 TotalAmount: int64(order.TotalAmount), // 数据库已存储元为单位,无需乘100 PayAmount: int64(order.PayAmount), // 数据库已存储元为单位,无需乘100 CouponAmount: int64(order.CouponAmount), // 直接返回数据库数据 Status: order.Status, PayStatus: order.PayStatus, CreatedAt: order.CreatedAt.Format("2006-01-02 15:04:05"), LogisticsVO: logisticsVO, OrderItemVOs: orderItemVOs, ButtonVOs: buttonVOs, } } // PayOrder 支付订单 func (h *OrderHandler) PayOrder(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } // 从URL路径参数获取订单号 orderNo := c.Param("id") if orderNo == "" { response.BadRequest(c, "订单号不能为空") return } // 解析请求体获取支付方式 var req struct { PaymentMethod string `json:"payment_method"` } if err := c.ShouldBindJSON(&req); err != nil { // 如果没有提供支付方式,默认使用微信支付 req.PaymentMethod = "wechat" } // 获取订单详情 order, err := h.orderService.GetOrderByOrderNo(orderNo) if err != nil { response.ErrorWithMessage(c, response.ERROR, "订单不存在") return } // 验证订单归属 if order.UserID != userID.(uint) { response.ErrorWithMessage(c, response.ERROR, "无权限操作此订单") return } // 验证订单状态 if order.Status != 1 { // 1 = 待付款 response.ErrorWithMessage(c, response.ERROR, "订单状态不允许支付") return } // 如果是微信支付,返回支付二维码 if req.PaymentMethod == "wechat" { // 调用微信Native扫码支付 if h.wechatPayService != nil { paymentResp, err := h.wechatPayService.CreateNativeOrder(c.Request.Context(), order) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, paymentResp.Data) return } else { // 如果没有微信支付服务,返回模拟数据 response.Success(c, gin.H{ "qrcode_url": "https://api.example.com/qrcode/" + orderNo, "order_no": orderNo, "amount": order.TotalAmount, "sandbox": true, }) return } } // 其他支付方式,直接标记为已支付 if err := h.orderService.PayOrder(userID.(uint), orderNo); err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, nil) } // CancelOrder 取消订单 func (h *OrderHandler) CancelOrder(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } var req struct { OrderNo string `json:"order_no" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "鍙傛暟閿欒: "+err.Error()) return } if err := h.orderService.CancelOrder(userID.(uint), req.OrderNo); err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, nil) } // RemindShip 提醒发货 func (h *OrderHandler) RemindShip(c *gin.Context) { log.Printf("[后端处理] ===== 提醒发货请求开始 =====") userID, exists := c.Get("user_id") if !exists { log.Printf("[后端处理] 提醒发货失败: 用户未认证") response.Unauthorized(c) return } // 从URL路径参数获取订单号 orderNo := c.Param("id") log.Printf("[后端处理] 提醒发货请求参数: userID=%v, orderNo=%s", userID, orderNo) if orderNo == "" { log.Printf("[后端处理] 提醒发货失败: 订单号为空") response.BadRequest(c, "订单号不能为空") return } log.Printf("[后端处理] 调用服务层提醒发货方法...") if err := h.orderService.RemindShip(userID.(uint), orderNo); err != nil { log.Printf("[后端处理] 提醒发货失败: %v", err) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } log.Printf("[后端处理] 提醒发货成功") response.Success(c, gin.H{"message": "提醒发货成功"}) } // ConfirmReceive方法前的注释 func (h *OrderHandler) RefundOrder(c *gin.Context) { log.Printf("[后端处理] ===== 退款申请请求开始 =====") userID, exists := c.Get("user_id") if !exists { log.Printf("[后端处理] 退款申请失败: 用户未认证") response.Unauthorized(c) return } // 从URL路径参数获取订单号 orderNo := c.Param("id") log.Printf("[后端处理] 退款申请请求参数: userID=%v, orderNo=%s", userID, orderNo) if orderNo == "" { log.Printf("[后端处理] 退款申请失败: 订单号为空") response.BadRequest(c, "订单号不能为空") return } log.Printf("[后端处理] 调用服务层退款申请方法...") // 调用服务层的退款方法 if err := h.orderService.RefundOrderDuplicate(userID.(uint), orderNo); err != nil { log.Printf("[后端处理] 退款申请失败: %v", err) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } log.Printf("[后端处理] 退款申请成功") response.Success(c, gin.H{"message": "退款申请已提交"}) } // ConfirmReceive 确认收货 func (h *OrderHandler) ConfirmReceive(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } var req struct { OrderNo string `json:"order_no" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "鍙傛暟閿欒: "+err.Error()) return } if err := h.orderService.ConfirmReceive(userID.(uint), req.OrderNo); err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, nil) } // GetOrderList 获取订单列表(支持条件查询) func (h *OrderHandler) GetOrderList(c *gin.Context) { page := utils.StringToInt(c.DefaultQuery("page", "1")) pageSize := utils.StringToInt(c.DefaultQuery("page_size", "20")) conditions := make(map[string]interface{}) if status := c.Query("status"); status != "" { conditions["status"] = utils.StringToInt(status) } if userID := c.Query("user_id"); userID != "" { conditions["user_id"] = utils.StringToUint(userID) } if orderNo := c.Query("order_no"); orderNo != "" { conditions["order_no"] = orderNo } if startDate := c.Query("start_date"); startDate != "" { conditions["start_date"] = startDate } if endDate := c.Query("end_date"); endDate != "" { conditions["end_date"] = endDate } orders, pagination, err := h.orderService.GetOrderList(page, pageSize, conditions) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Page(c, orders, pagination.Total, pagination.Page, pagination.PageSize) } // ShipOrder 发货 func (h *OrderHandler) ShipOrder(c *gin.Context) { var req struct { OrderNo string `json:"order_no" binding:"required"` LogisticsCompany string `json:"logistics_company" binding:"required"` LogisticsNo string `json:"logistics_no" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "鍙傛暟閿欒: "+err.Error()) return } if err := h.orderService.ShipOrder(req.OrderNo, req.LogisticsCompany, req.LogisticsNo); err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, nil) } // GetOrderStatistics 获取订单统计 func (h *OrderHandler) GetOrderStatistics(c *gin.Context) { statistics, err := h.orderService.GetOrderStatistics() if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, statistics) } // GetDailyOrderStatistics 获取每日订单统计 func (h *OrderHandler) GetDailyOrderStatistics(c *gin.Context) { days := utils.StringToInt(c.DefaultQuery("days", "30")) statistics, err := h.orderService.GetDailyOrderStatistics(days) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, statistics) } // MergeOrders 合并订单 func (h *OrderHandler) MergeOrders(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Unauthorized(c) return } var req service.MergeOrdersRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误: "+err.Error()) return } // 验证订单数量 if len(req.OrderIDs) < 2 { response.BadRequest(c, "至少需要选择2个订单进行合并") return } mergedOrder, err := h.orderService.MergeOrders(userID.(uint), &req) if err != nil { response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, gin.H{ "message": "订单合并成功", "order": mergedOrder, }) } // generateOrderButtons 根据订单状态生成操作按钮 func generateOrderButtons(status int, order *model.Order) []OrderButtonVO { log.Printf("[后端按钮生成] ===== 开始生成按钮 =====") log.Printf("[后端按钮生成] 输入状态: %d", status) var buttons []OrderButtonVO switch status { case 1: // 待付款 log.Printf("[后端按钮生成] 状态1-待付款: 生成取消订单(type=1)和立即付款(type=2)按钮") buttons = []OrderButtonVO{ {Primary: false, Type: 1, Name: "取消订单"}, {Primary: true, Type: 2, Name: "立即付款"}, } case 2: // 已付款/待发货 log.Printf("[后端按钮生成] 状态2-已付款/待发货: 生成申请退款(type=7)和提醒发货(type=3)按钮") buttons = []OrderButtonVO{ {Primary: false, Type: 7, Name: "申请退款"}, {Primary: true, Type: 3, Name: "提醒发货"}, } case 3: // 待发货 log.Printf("[后端按钮生成] 状态3-待发货: 生成申请退款(type=7)和提醒发货(type=3)按钮") buttons = []OrderButtonVO{ {Primary: false, Type: 7, Name: "申请退款"}, {Primary: true, Type: 3, Name: "提醒发货"}, } case 4: // 已发货/待收货 log.Printf("[后端按钮生成] 状态4-已发货/待收货: 生成确认收货(type=4)按钮") buttons = []OrderButtonVO{ {Primary: true, Type: 4, Name: "确认收货"}, } case 5: // 待收货 log.Printf("[后端按钮生成] 状态5-待收货: 生成确认收货(type=4)按钮") buttons = []OrderButtonVO{ {Primary: true, Type: 4, Name: "确认收货"}, } case 6: // 已完成 log.Printf("[后端按钮生成] 状态6-已完成: 检查是否有未评价的订单项") // 检查是否有未评价的订单项 hasUncommentedItems := false for _, item := range order.OrderItems { if !item.IsCommented { hasUncommentedItems = true log.Printf("[后端按钮生成] 发现未评价的订单项: ID=%d, ProductID=%d", item.ID, item.ProductID) break } } if hasUncommentedItems { log.Printf("[后端按钮生成] 状态6-已完成: 有未评价订单项,生成申请售后(type=5)和评价(type=6)按钮") buttons = []OrderButtonVO{ {Primary: false, Type: 5, Name: "申请售后"}, {Primary: true, Type: 6, Name: "评价"}, } } else { log.Printf("[后端按钮生成] 状态6-已完成: 所有订单项已评价,只生成申请售后(type=5)按钮") buttons = []OrderButtonVO{ {Primary: false, Type: 5, Name: "申请售后"}, } } case 7: // 已取消 log.Printf("[后端按钮生成] 状态7-已取消: 不生成任何按钮") buttons = []OrderButtonVO{} case 8: // 退货中 log.Printf("[后端按钮生成] 状态8-退货中: 不生成任何按钮") buttons = []OrderButtonVO{} case 9: // 已退款 log.Printf("[后端按钮生成] 状态9-已退款: 不生成任何按钮") buttons = []OrderButtonVO{} default: log.Printf("[后端按钮生成] 未知状态%d: 不生成任何按钮", status) buttons = []OrderButtonVO{} } log.Printf("[后端按钮生成] ===== 按钮生成完成 =====") log.Printf("[后端按钮生成] 生成的按钮数量: %d", len(buttons)) for i, btn := range buttons { log.Printf("[后端按钮生成] 按钮%d: type=%d, name=%s, primary=%t", i, btn.Type, btn.Name, btn.Primary) } return buttons }