Files
wx_service/internal/marketing/handler/template_handler.go
T
nepiedg ac49e1458c feat(marketing): 新增营销图管理模块
- 新增 marketing 模块:model/repository/service/handler 四层架构
- 数据模型:marketing_categories、marketing_templates、marketing_user_downloads
- 小程序端接口:分类列表、模板列表/详情、下载记录、广告回调
- 管理后台接口:分类/模板 CRUD、下载统计(X-Admin-Token 鉴权)
- 路由注册:接入现有 AuthMiddleware,新增 AdminTokenMiddleware
- Web 管理后台:单页面 Vue3 + Element Plus(分类管理、模板管理、数据概览)

Closes #37, #38, #39, #40

Made-with: Cursor
2026-03-06 07:36:05 +00:00

169 lines
4.2 KiB
Go

package handler
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"wx_service/internal/marketing/repository"
"wx_service/internal/marketing/service"
"wx_service/internal/model"
)
type TemplateHandler struct {
svc *service.TemplateService
}
func NewTemplateHandler(svc *service.TemplateService) *TemplateHandler {
return &TemplateHandler{svc: svc}
}
// ListEnabled returns enabled templates for mini-program users.
func (h *TemplateHandler) ListEnabled(c *gin.Context) {
categoryID := parseUintQuery(c, "category_id", 0)
page := parseIntQuery(c, "page", 1)
pageSize := parseIntQuery(c, "page_size", 20)
resp, err := h.svc.List(repository.TemplateListParams{
CategoryID: categoryID,
OnlyEnabled: true,
Page: page,
PageSize: pageSize,
})
if err != nil {
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(resp))
}
// GetDetail returns a single template by ID.
func (h *TemplateHandler) GetDetail(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
tpl, err := h.svc.GetByID(id)
if err != nil {
if service.IsNotFoundError(err) {
c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "模板不存在"))
return
}
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(tpl))
}
// AdminList returns all templates for admin.
func (h *TemplateHandler) AdminList(c *gin.Context) {
categoryID := parseUintQuery(c, "category_id", 0)
page := parseIntQuery(c, "page", 1)
pageSize := parseIntQuery(c, "page_size", 20)
resp, err := h.svc.List(repository.TemplateListParams{
CategoryID: categoryID,
OnlyEnabled: false,
Page: page,
PageSize: pageSize,
})
if err != nil {
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(resp))
}
func (h *TemplateHandler) AdminCreate(c *gin.Context) {
var req service.TemplateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误"))
return
}
tpl, err := h.svc.Create(req)
if err != nil {
if service.IsBadRequestError(err) {
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, err.Error()))
return
}
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(tpl))
}
func (h *TemplateHandler) AdminUpdate(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req service.TemplateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误"))
return
}
tpl, err := h.svc.Update(id, req)
if err != nil {
if service.IsNotFoundError(err) {
c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "模板不存在"))
return
}
if service.IsBadRequestError(err) {
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, err.Error()))
return
}
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(tpl))
}
func (h *TemplateHandler) AdminDelete(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.svc.Delete(id); err != nil {
if service.IsNotFoundError(err) {
c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "模板不存在"))
return
}
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "服务器错误"))
return
}
c.JSON(http.StatusOK, model.Success(nil))
}
func parseIntQuery(c *gin.Context, key string, defaultValue int) int {
v := c.Query(key)
if v == "" {
return defaultValue
}
parsed, err := strconv.Atoi(v)
if err != nil {
return defaultValue
}
return parsed
}
func parseUintQuery(c *gin.Context, key string, defaultValue uint) uint {
v := c.Query(key)
if v == "" {
return defaultValue
}
parsed, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return defaultValue
}
return uint(parsed)
}