262 lines
6.7 KiB
Go
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
|
|
}
|