Files
0451meishi/backend/internal/handlers/stores.go
2026-01-15 11:37:22 +08:00

262 lines
6.7 KiB
Go

package handlers
import (
"net/http"
"strconv"
"strings"
"0451meishiditu/backend/internal/models"
"0451meishiditu/backend/internal/resp"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type storeImageReq struct {
URL string `json:"url" binding:"required"`
SortOrder int `json:"sort_order"`
}
type dishReq struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
ImageURL string `json:"image_url"`
SortOrder int `json:"sort_order"`
}
type storeUpsertReq struct {
Name string `json:"name" binding:"required"`
CategoryID uint `json:"category_id" binding:"required"`
Address string `json:"address" binding:"required"`
Lat *float64 `json:"lat"`
Lng *float64 `json:"lng"`
OpenHours string `json:"open_hours"`
Phone string `json:"phone"`
CoverURL string `json:"cover_url"`
Description string `json:"description"`
Status string `json:"status"`
Images []storeImageReq `json:"images"`
Dishes []dishReq `json:"dishes"`
}
func (h *Handlers) StoreList(c *gin.Context) {
keyword := strings.TrimSpace(c.Query("keyword"))
status := strings.TrimSpace(c.Query("status"))
categoryID, _ := strconv.ParseUint(c.Query("category_id"), 10, 64)
page, pageSize := parsePage(c.Query("page"), c.Query("page_size"))
q := h.db.Model(&models.Store{})
if keyword != "" {
q = q.Where("name LIKE ?", "%"+keyword+"%")
}
if status != "" {
q = q.Where("status = ?", status)
}
if categoryID > 0 {
q = q.Where("category_id = ?", uint(categoryID))
}
var total int64
if err := q.Count(&total).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "db error")
return
}
var items []models.Store
if err := q.Preload("Category").
Order("id desc").
Limit(pageSize).
Offset((page - 1) * pageSize).
Find(&items).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "db error")
return
}
resp.OKMeta(c, items, gin.H{
"page": page,
"page_size": pageSize,
"total": total,
"total_page": calcTotalPage(total, pageSize),
})
}
func (h *Handlers) StoreGet(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
var item models.Store
if err := h.db.
Preload("Images", func(db *gorm.DB) *gorm.DB { return db.Order("sort_order desc, id desc") }).
Preload("Dishes", func(db *gorm.DB) *gorm.DB { return db.Order("sort_order desc, id desc") }).
First(&item, uint(id)).Error; err != nil {
resp.Fail(c, http.StatusNotFound, "not found")
return
}
resp.OK(c, item)
}
func (h *Handlers) StoreCreate(c *gin.Context) {
var req storeUpsertReq
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid payload")
return
}
if req.Status == "" {
req.Status = "active"
}
err := h.db.Transaction(func(tx *gorm.DB) error {
item := models.Store{
Name: req.Name,
CategoryID: req.CategoryID,
Address: req.Address,
Lat: req.Lat,
Lng: req.Lng,
OpenHours: req.OpenHours,
Phone: req.Phone,
CoverURL: req.CoverURL,
Description: req.Description,
Status: req.Status,
}
if err := tx.Create(&item).Error; err != nil {
return err
}
if err := upsertStoreImages(tx, item.ID, req.Images); err != nil {
return err
}
if err := upsertStoreDishes(tx, item.ID, req.Dishes); err != nil {
return err
}
var out models.Store
if err := tx.Preload("Images").Preload("Dishes").First(&out, item.ID).Error; err != nil {
return err
}
resp.OK(c, out)
return nil
})
if err != nil {
resp.Fail(c, http.StatusBadRequest, "create failed")
return
}
}
func (h *Handlers) StoreUpdate(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
var req storeUpsertReq
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid payload")
return
}
err := h.db.Transaction(func(tx *gorm.DB) error {
var item models.Store
if err := tx.First(&item, uint(id)).Error; err != nil {
return err
}
if req.Status == "" {
req.Status = item.Status
}
item.Name = req.Name
item.CategoryID = req.CategoryID
item.Address = req.Address
if req.Lat != nil {
item.Lat = req.Lat
}
if req.Lng != nil {
item.Lng = req.Lng
}
item.OpenHours = req.OpenHours
item.Phone = req.Phone
item.CoverURL = req.CoverURL
item.Description = req.Description
item.Status = req.Status
if err := tx.Save(&item).Error; err != nil {
return err
}
if err := tx.Where("store_id = ?", item.ID).Delete(&models.StoreImage{}).Error; err != nil {
return err
}
if err := tx.Where("store_id = ?", item.ID).Delete(&models.SignatureDish{}).Error; err != nil {
return err
}
if err := upsertStoreImages(tx, item.ID, req.Images); err != nil {
return err
}
if err := upsertStoreDishes(tx, item.ID, req.Dishes); err != nil {
return err
}
var out models.Store
if err := tx.Preload("Images").Preload("Dishes").First(&out, item.ID).Error; err != nil {
return err
}
resp.OK(c, out)
return nil
})
if err != nil {
resp.Fail(c, http.StatusBadRequest, "update failed")
return
}
}
type statusReq struct {
Status string `json:"status" binding:"required"`
}
func (h *Handlers) StoreUpdateStatus(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
var req statusReq
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid payload")
return
}
if req.Status != "active" && req.Status != "inactive" {
resp.Fail(c, http.StatusBadRequest, "invalid status")
return
}
if err := h.db.Model(&models.Store{}).Where("id = ?", uint(id)).Update("status", req.Status).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "update failed")
return
}
resp.OK(c, gin.H{"updated": true})
}
func (h *Handlers) StoreDelete(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
if err := h.db.Delete(&models.Store{}, uint(id)).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "delete failed")
return
}
resp.OK(c, gin.H{"deleted": true})
}
func upsertStoreImages(tx *gorm.DB, storeID uint, imgs []storeImageReq) error {
for _, img := range imgs {
if err := tx.Create(&models.StoreImage{
StoreID: storeID,
URL: img.URL,
SortOrder: img.SortOrder,
}).Error; err != nil {
return err
}
}
return nil
}
func upsertStoreDishes(tx *gorm.DB, storeID uint, dishes []dishReq) error {
for _, d := range dishes {
if err := tx.Create(&models.SignatureDish{
StoreID: storeID,
Name: d.Name,
Description: d.Description,
ImageURL: d.ImageURL,
SortOrder: d.SortOrder,
}).Error; err != nil {
return err
}
}
return nil
}