package handler import ( "fmt" "image" _ "image/jpeg" _ "image/png" "net/http" "os" "path/filepath" "github.com/disintegration/imaging" "github.com/gin-gonic/gin" "gorm.io/gorm" "github.com/wangjia/jiu/backend/config" "github.com/wangjia/jiu/backend/internal/middleware" "github.com/wangjia/jiu/backend/internal/model" ) type ShopHandler struct { db *gorm.DB } func NewShopHandler(db *gorm.DB) *ShopHandler { return &ShopHandler{db: db} } // GetInfo GET /api/v1/shop/info func (h *ShopHandler) GetInfo(c *gin.Context) { shopID := middleware.GetShopID(c) var shop model.Shop if err := h.db.First(&shop, shopID).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "shop not found"}) return } c.JSON(http.StatusOK, shop) } // UpdateInfo PUT /api/v1/shop/info (admin only) func (h *ShopHandler) UpdateInfo(c *gin.Context) { shopID := middleware.GetShopID(c) var req struct { Name string `json:"name"` Address string `json:"address"` Phone string `json:"phone"` ManagerName string `json:"manager_name"` LogoURL string `json:"logo_url"` WechatID string `json:"wechat_id"` CustomFields map[string]interface{} `json:"custom_fields"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } updates := map[string]interface{}{ "name": req.Name, "address": req.Address, "phone": req.Phone, "manager_name": req.ManagerName, "wechat_id": req.WechatID, } if req.LogoURL != "" { updates["logo_url"] = req.LogoURL } // custom_fields 增量 merge:保留已有键(如其它店级配置),只覆盖本次传入的键。 if req.CustomFields != nil { var cur model.Shop h.db.Select("custom_fields").Where("id = ?", shopID).First(&cur) merged := model.JSON{} for k, v := range cur.CustomFields { merged[k] = v } for k, v := range req.CustomFields { merged[k] = v } updates["custom_fields"] = merged } if err := h.db.Model(&model.Shop{}).Where("id = ?", shopID).Updates(updates).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } var shop model.Shop h.db.First(&shop, shopID) c.JSON(http.StatusOK, shop) } // UploadLogo POST /api/v1/shop/logo (admin only) func (h *ShopHandler) UploadLogo(c *gin.Context) { shopID := middleware.GetShopID(c) if err := c.Request.ParseMultipartForm(2 << 20); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "文件超过 2MB 限制"}) return } file, _, err := c.Request.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请上传文件(field: file)"}) return } defer file.Close() img, _, err := image.Decode(file) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "仅支持 JPEG/PNG 图片"}) return } // 裁剪为正方形后缩放到 256×256 resized := imaging.Fill(img, 256, 256, imaging.Center, imaging.Lanczos) subdir := filepath.Join(config.C.Storage.UploadDir, "shops", fmt.Sprintf("%d", shopID)) if err := os.MkdirAll(subdir, 0755); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "存储目录创建失败"}) return } fullPath := filepath.Join(subdir, "logo.jpg") if err := imaging.Save(resized, fullPath, imaging.JPEGQuality(90)); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "图片保存失败"}) return } logoURL := fmt.Sprintf("/images/shops/%d/logo.jpg", shopID) if err := h.db.Model(&model.Shop{}).Where("id = ?", shopID).Update("logo_url", logoURL).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"logo_url": logoURL}) }