183 lines
4.7 KiB
Go
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")
|
|
}
|