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

183 lines
4.7 KiB
Go

package handlers
import (
"encoding/json"
"net/http"
"strconv"
"time"
"0451meishiditu/backend/internal/models"
"0451meishiditu/backend/internal/resp"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type merchantApplyReq struct {
StoreName string `json:"store_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"`
ImageURLs []string `json:"image_urls"`
Description string `json:"description"`
ContactName string `json:"contact_name" binding:"required"`
ContactPhone string `json:"contact_phone" binding:"required"`
}
func (h *Handlers) MerchantApply(c *gin.Context) {
var req merchantApplyReq
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid payload")
return
}
imgs, _ := json.Marshal(req.ImageURLs)
app := models.MerchantApplication{
StoreName: req.StoreName,
CategoryID: req.CategoryID,
Address: req.Address,
Lat: req.Lat,
Lng: req.Lng,
OpenHours: req.OpenHours,
Phone: req.Phone,
CoverURL: req.CoverURL,
ImageURLs: imgs,
Description: req.Description,
ContactName: req.ContactName,
ContactPhone: req.ContactPhone,
Status: "pending",
RejectReason: "",
ReviewedAt: nil,
ReviewerID: nil,
}
if err := h.db.Create(&app).Error; err != nil {
resp.Fail(c, http.StatusBadRequest, "submit failed")
return
}
resp.OK(c, gin.H{"id": app.ID, "status": app.Status})
}
func (h *Handlers) AdminMerchantApplyList(c *gin.Context) {
status := c.Query("status")
page, pageSize := parsePage(c.Query("page"), c.Query("page_size"))
q := h.db.Model(&models.MerchantApplication{})
if status != "" {
q = q.Where("status = ?", status)
}
var total int64
if err := q.Count(&total).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "db error")
return
}
var items []models.MerchantApplication
if err := q.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),
})
}
type applyReviewReq struct {
Action string `json:"action" binding:"required"` // approve/reject
RejectReason string `json:"reject_reason"`
}
func (h *Handlers) AdminMerchantApplyReview(c *gin.Context) {
id64, _ := strconv.ParseUint(c.Param("id"), 10, 64)
var req applyReviewReq
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid payload")
return
}
var app models.MerchantApplication
if err := h.db.First(&app, uint(id64)).Error; err != nil {
resp.Fail(c, http.StatusNotFound, "not found")
return
}
if app.Status != "pending" {
resp.Fail(c, http.StatusBadRequest, "already reviewed")
return
}
now := time.Now()
adminID := c.GetUint("admin_id")
if req.Action == "approve" {
err := h.db.Transaction(func(tx *gorm.DB) error {
// create store
store := models.Store{
Name: app.StoreName,
CategoryID: app.CategoryID,
Address: app.Address,
Lat: app.Lat,
Lng: app.Lng,
OpenHours: app.OpenHours,
Phone: app.Phone,
CoverURL: app.CoverURL,
Description: app.Description,
Status: "active",
}
if err := tx.Create(&store).Error; err != nil {
return err
}
// images
var urls []string
_ = json.Unmarshal([]byte(app.ImageURLs), &urls)
for i, u := range urls {
if u == "" {
continue
}
if err := tx.Create(&models.StoreImage{StoreID: store.ID, URL: u, SortOrder: i}).Error; err != nil {
return err
}
}
return tx.Model(&models.MerchantApplication{}).Where("id = ?", app.ID).Updates(map[string]any{
"status": "approved",
"reject_reason": "",
"reviewed_at": &now,
"reviewer_id": &adminID,
}).Error
})
if err != nil {
resp.Fail(c, http.StatusInternalServerError, "approve failed")
return
}
resp.OK(c, gin.H{"approved": true})
return
}
if req.Action == "reject" {
if err := h.db.Model(&models.MerchantApplication{}).Where("id = ?", app.ID).Updates(map[string]any{
"status": "rejected",
"reject_reason": req.RejectReason,
"reviewed_at": &now,
"reviewer_id": &adminID,
}).Error; err != nil {
resp.Fail(c, http.StatusInternalServerError, "reject failed")
return
}
resp.OK(c, gin.H{"rejected": true})
return
}
resp.Fail(c, http.StatusBadRequest, "invalid action")
}