package handlers import ( "fmt" "log" "net/http" "net/url" "strings" "github.com/gin-gonic/gin" "mengyastore-backend/internal/auth" "mengyastore-backend/internal/models" "mengyastore-backend/internal/storage" ) const qrSize = "320x320" type OrderHandler struct { productStore *storage.JSONStore orderStore *storage.OrderStore authClient *auth.SproutGateClient } type checkoutPayload struct { ProductID string `json:"productId"` Quantity int `json:"quantity"` } func NewOrderHandler(productStore *storage.JSONStore, orderStore *storage.OrderStore, authClient *auth.SproutGateClient) *OrderHandler { return &OrderHandler{productStore: productStore, orderStore: orderStore, authClient: authClient} } func (h *OrderHandler) tryExtractUser(c *gin.Context) (string, string) { authHeader := c.GetHeader("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { log.Println("[Order] 无 Authorization header,匿名下单") return "", "" } userToken := strings.TrimPrefix(authHeader, "Bearer ") log.Printf("[Order] 检测到用户 token,正在验证 (长度=%d)", len(userToken)) result, err := h.authClient.VerifyToken(userToken) if err != nil { log.Printf("[Order] 验证 token 失败: %v", err) return "", "" } if !result.Valid { log.Println("[Order] token 验证返回 valid=false") return "", "" } if result.User == nil { log.Println("[Order] token 验证成功但 user 为空") return "", "" } log.Printf("[Order] 用户身份验证成功: account=%s username=%s", result.User.Account, result.User.Username) return result.User.Account, result.User.Username } func (h *OrderHandler) CreateOrder(c *gin.Context) { userAccount, userName := h.tryExtractUser(c) var payload checkoutPayload if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"}) return } payload.ProductID = strings.TrimSpace(payload.ProductID) if payload.ProductID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "missing required fields"}) return } if payload.Quantity <= 0 { payload.Quantity = 1 } product, err := h.productStore.GetByID(payload.ProductID) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } if !product.Active { c.JSON(http.StatusBadRequest, gin.H{"error": "product is not available"}) return } if product.Quantity < payload.Quantity { c.JSON(http.StatusBadRequest, gin.H{"error": "库存不足"}) return } deliveredCodes, ok := extractCodes(&product, payload.Quantity) if !ok { c.JSON(http.StatusBadRequest, gin.H{"error": "卡密不足"}) return } product.Quantity = len(product.Codes) updatedProduct, err := h.productStore.Update(product.ID, product) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } order := models.Order{ ProductID: updatedProduct.ID, ProductName: updatedProduct.Name, UserAccount: userAccount, UserName: userName, Quantity: payload.Quantity, DeliveredCodes: deliveredCodes, Status: "pending", } created, err := h.orderStore.Create(order) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } qrPayload := fmt.Sprintf("order:%s:%s", created.ID, created.ProductID) qrURL := fmt.Sprintf("https://api.qrserver.com/v1/create-qr-code/?size=%s&data=%s", qrSize, url.QueryEscape(qrPayload)) c.JSON(http.StatusOK, gin.H{ "data": gin.H{ "orderId": created.ID, "qrCodeUrl": qrURL, "productId": created.ProductID, "productQty": created.Quantity, "viewCount": updatedProduct.ViewCount, "status": created.Status, }, }) } func (h *OrderHandler) ConfirmOrder(c *gin.Context) { orderID := c.Param("id") order, err := h.orderStore.Confirm(orderID) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "data": gin.H{ "orderId": order.ID, "status": order.Status, "deliveredCodes": order.DeliveredCodes, }, }) } func (h *OrderHandler) ListMyOrders(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) return } userToken := strings.TrimPrefix(authHeader, "Bearer ") result, err := h.authClient.VerifyToken(userToken) if err != nil || !result.Valid || result.User == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期,请重新登录"}) return } orders, err := h.orderStore.ListByAccount(result.User.Account) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"data": orders}) } func extractCodes(product *models.Product, count int) ([]string, bool) { if count <= 0 { return nil, false } if len(product.Codes) < count { return nil, false } delivered := make([]string, count) copy(delivered, product.Codes[:count]) product.Codes = product.Codes[count:] return delivered, true }