1c0aeb152a
- Add PUT /auth/profile endpoint for nickname and avatar updates - Add ad_placements table and CRUD admin API for managing ad units - Add GET /marketing/ad-config public API for mini-program to fetch ad config - Reduce logo limit from 10 to 3 per user, add 2MB file size validation Made-with: Cursor
158 lines
4.5 KiB
Go
158 lines
4.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"wx_service/internal/marketing/model"
|
|
"wx_service/internal/marketing/repository"
|
|
commonmodel "wx_service/internal/model"
|
|
)
|
|
|
|
type AdPlacementHandler struct {
|
|
repo *repository.AdPlacementRepository
|
|
}
|
|
|
|
func NewAdPlacementHandler(repo *repository.AdPlacementRepository) *AdPlacementHandler {
|
|
return &AdPlacementHandler{repo: repo}
|
|
}
|
|
|
|
func (h *AdPlacementHandler) AdminList(c *gin.Context) {
|
|
list, err := h.repo.ListAll()
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "获取广告位列表失败"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, commonmodel.Success(list))
|
|
}
|
|
|
|
type adPlacementCreateReq struct {
|
|
MiniProgramID uint `json:"mini_program_id" binding:"required"`
|
|
Name string `json:"name" binding:"required"`
|
|
AdType string `json:"ad_type" binding:"required"`
|
|
AdUnitID string `json:"ad_unit_id"`
|
|
Status *int `json:"status"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
func (h *AdPlacementHandler) AdminCreate(c *gin.Context) {
|
|
var req adPlacementCreateReq
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, commonmodel.Error(http.StatusBadRequest, "参数错误"))
|
|
return
|
|
}
|
|
|
|
p := &model.AdPlacement{
|
|
MiniProgramID: req.MiniProgramID,
|
|
Name: req.Name,
|
|
AdType: req.AdType,
|
|
AdUnitID: req.AdUnitID,
|
|
Description: req.Description,
|
|
Status: 1,
|
|
}
|
|
if req.Status != nil {
|
|
p.Status = *req.Status
|
|
}
|
|
|
|
if err := h.repo.Create(p); err != nil {
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "创建失败"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, commonmodel.Success(p))
|
|
}
|
|
|
|
type adPlacementUpdateReq struct {
|
|
Name *string `json:"name"`
|
|
AdUnitID *string `json:"ad_unit_id"`
|
|
Status *int `json:"status"`
|
|
Description *string `json:"description"`
|
|
}
|
|
|
|
func (h *AdPlacementHandler) AdminUpdate(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil || id == 0 {
|
|
c.JSON(http.StatusBadRequest, commonmodel.Error(http.StatusBadRequest, "无效 ID"))
|
|
return
|
|
}
|
|
|
|
p, err := h.repo.FindByID(uint(id))
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrAdPlacementNotFound) {
|
|
c.JSON(http.StatusNotFound, commonmodel.Error(http.StatusNotFound, "广告位不存在"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "查询失败"))
|
|
return
|
|
}
|
|
|
|
var req adPlacementUpdateReq
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, commonmodel.Error(http.StatusBadRequest, "参数错误"))
|
|
return
|
|
}
|
|
|
|
if req.Name != nil {
|
|
p.Name = *req.Name
|
|
}
|
|
if req.AdUnitID != nil {
|
|
p.AdUnitID = *req.AdUnitID
|
|
}
|
|
if req.Status != nil {
|
|
p.Status = *req.Status
|
|
}
|
|
if req.Description != nil {
|
|
p.Description = *req.Description
|
|
}
|
|
|
|
if err := h.repo.Update(p); err != nil {
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "更新失败"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, commonmodel.Success(p))
|
|
}
|
|
|
|
func (h *AdPlacementHandler) AdminDelete(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil || id == 0 {
|
|
c.JSON(http.StatusBadRequest, commonmodel.Error(http.StatusBadRequest, "无效 ID"))
|
|
return
|
|
}
|
|
|
|
if err := h.repo.Delete(uint(id)); err != nil {
|
|
if errors.Is(err, repository.ErrAdPlacementNotFound) {
|
|
c.JSON(http.StatusNotFound, commonmodel.Error(http.StatusNotFound, "广告位不存在"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "删除失败"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, commonmodel.Success(nil))
|
|
}
|
|
|
|
func (h *AdPlacementHandler) GetAdConfig(c *gin.Context) {
|
|
miniProgramIDStr := c.Query("mini_program_id")
|
|
miniProgramID, _ := strconv.ParseUint(miniProgramIDStr, 10, 64)
|
|
if miniProgramID == 0 {
|
|
c.JSON(http.StatusBadRequest, commonmodel.Error(http.StatusBadRequest, "缺少 mini_program_id"))
|
|
return
|
|
}
|
|
|
|
p, err := h.repo.FindByMiniProgramAndType(uint(miniProgramID), "rewarded_video")
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrAdPlacementNotFound) {
|
|
c.JSON(http.StatusOK, commonmodel.Success(gin.H{"ad_unit_id": "", "enabled": false}))
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, commonmodel.Error(http.StatusInternalServerError, "查询失败"))
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, commonmodel.Success(gin.H{
|
|
"ad_unit_id": p.AdUnitID,
|
|
"enabled": p.Status == 1 && p.AdUnitID != "",
|
|
}))
|
|
}
|