Files
wx_service/internal/marketing/handler/ad_placement_handler.go
T
nepiedg 1c0aeb152a feat(marketing): user profile update, ad placement management, logo limits
- 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
2026-04-04 04:02:06 +08:00

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 != "",
}))
}