package handlers import ( "net/http" "strings" "github.com/gin-gonic/gin" "mengyastore-backend/internal/auth" "mengyastore-backend/internal/storage" ) type WishlistHandler struct { wishlistStore *storage.WishlistStore authClient *auth.SproutGateClient } func NewWishlistHandler(wishlistStore *storage.WishlistStore, authClient *auth.SproutGateClient) *WishlistHandler { return &WishlistHandler{wishlistStore: wishlistStore, authClient: authClient} } func (h *WishlistHandler) requireUser(c *gin.Context) (string, bool) { authHeader := c.GetHeader("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) return "", false } token := strings.TrimPrefix(authHeader, "Bearer ") result, err := h.authClient.VerifyToken(token) if err != nil || !result.Valid || result.User == nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期,请重新登录"}) return "", false } return result.User.Account, true } // GetWishlist 当前用户收藏的商品 ID 列表。 // @Summary 获取当前用户收藏列表 // @Description 需 Bearer 登录。返回该账号已收藏的商品 ID 数组(顺序由存储实现决定)。 // @Tags 收藏 // @Produce json // @Security BearerAuth // @Success 200 {object} SwaggerWishlistWrap // @Failure 401 {object} SwaggerErrorBody // @Failure 500 {object} SwaggerErrorBody // @Router /api/wishlist [get] func (h *WishlistHandler) GetWishlist(c *gin.Context) { account, ok := h.requireUser(c) if !ok { return } ids, err := h.wishlistStore.Get(account) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"data": gin.H{"items": ids}}) } // WishlistItemPayload 添加收藏请求体。 type WishlistItemPayload struct { ProductID string `json:"productId"` } // AddToWishlist 添加收藏。 // @Summary 添加商品到收藏 // @Description 需 Bearer。请求体为 `{ "productId": "..." }`;幂等语义由存储层实现(重复添加可忽略或报错以实际为准)。 // @Tags 收藏 // @Accept json // @Produce json // @Security BearerAuth // @Param body body WishlistItemPayload true "包含 productId 的 JSON" // @Success 200 {object} SwaggerWishlistWrap // @Failure 400 {object} SwaggerErrorBody // @Failure 401 {object} SwaggerErrorBody // @Failure 500 {object} SwaggerErrorBody // @Router /api/wishlist [post] func (h *WishlistHandler) AddToWishlist(c *gin.Context) { account, ok := h.requireUser(c) if !ok { return } var payload WishlistItemPayload if err := c.ShouldBindJSON(&payload); err != nil || payload.ProductID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"}) return } if err := h.wishlistStore.Add(account, payload.ProductID); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ids, _ := h.wishlistStore.Get(account) c.JSON(http.StatusOK, gin.H{"data": gin.H{"items": ids}}) } // RemoveFromWishlist 按商品 ID 移除收藏。 // @Summary 从收藏中移除商品 // @Description 需 Bearer。路径参数为要移除的商品 ID。 // @Tags 收藏 // @Produce json // @Security BearerAuth // @Param id path string true "商品ID(路径)" // @Success 200 {object} SwaggerWishlistWrap // @Failure 400 {object} SwaggerErrorBody // @Failure 401 {object} SwaggerErrorBody // @Failure 500 {object} SwaggerErrorBody // @Router /api/wishlist/{id} [delete] func (h *WishlistHandler) RemoveFromWishlist(c *gin.Context) { account, ok := h.requireUser(c) if !ok { return } productID := c.Param("id") if productID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "缺少商品 ID"}) return } if err := h.wishlistStore.Remove(account, productID); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ids, _ := h.wishlistStore.Get(account) c.JSON(http.StatusOK, gin.H{"data": gin.H{"items": ids}}) }