ac49e1458c
- 新增 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
121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package repository
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"wx_service/internal/marketing/model"
|
|
)
|
|
|
|
var ErrTemplateNotFound = errors.New("marketing template not found")
|
|
|
|
type TemplateRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewTemplateRepository(db *gorm.DB) *TemplateRepository {
|
|
return &TemplateRepository{db: db}
|
|
}
|
|
|
|
func (r *TemplateRepository) Create(tpl *model.MarketingTemplate) error {
|
|
if err := r.db.Create(tpl).Error; err != nil {
|
|
return fmt.Errorf("create marketing template: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *TemplateRepository) Update(tpl *model.MarketingTemplate) error {
|
|
tx := r.db.Model(tpl).Updates(map[string]interface{}{
|
|
"category_id": tpl.CategoryID,
|
|
"title": tpl.Title,
|
|
"image_url": tpl.ImageURL,
|
|
"thumbnail_url": tpl.ThumbnailURL,
|
|
"width": tpl.Width,
|
|
"height": tpl.Height,
|
|
"sort_order": tpl.SortOrder,
|
|
"status": tpl.Status,
|
|
})
|
|
if tx.Error != nil {
|
|
return fmt.Errorf("update marketing template: %w", tx.Error)
|
|
}
|
|
if tx.RowsAffected == 0 {
|
|
return ErrTemplateNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *TemplateRepository) Delete(id uint) error {
|
|
tx := r.db.Delete(&model.MarketingTemplate{}, id)
|
|
if tx.Error != nil {
|
|
return fmt.Errorf("delete marketing template: %w", tx.Error)
|
|
}
|
|
if tx.RowsAffected == 0 {
|
|
return ErrTemplateNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *TemplateRepository) FindByID(id uint) (*model.MarketingTemplate, error) {
|
|
var tpl model.MarketingTemplate
|
|
err := r.db.Preload("Category").First(&tpl, id).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
return nil, fmt.Errorf("find marketing template: %w", err)
|
|
}
|
|
return &tpl, nil
|
|
}
|
|
|
|
type TemplateListParams struct {
|
|
CategoryID uint
|
|
OnlyEnabled bool
|
|
Page int
|
|
PageSize int
|
|
}
|
|
|
|
func (r *TemplateRepository) FindList(params TemplateListParams) ([]model.MarketingTemplate, int64, error) {
|
|
if params.Page <= 0 {
|
|
params.Page = 1
|
|
}
|
|
if params.PageSize <= 0 {
|
|
params.PageSize = 20
|
|
}
|
|
if params.PageSize > 100 {
|
|
params.PageSize = 100
|
|
}
|
|
|
|
query := r.db.Model(&model.MarketingTemplate{})
|
|
if params.CategoryID > 0 {
|
|
query = query.Where("category_id = ?", params.CategoryID)
|
|
}
|
|
if params.OnlyEnabled {
|
|
query = query.Where("status = ?", 1)
|
|
}
|
|
query = query.Order("sort_order DESC, id DESC")
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("count marketing templates: %w", err)
|
|
}
|
|
|
|
var templates []model.MarketingTemplate
|
|
offset := (params.Page - 1) * params.PageSize
|
|
if err := query.Preload("Category").Offset(offset).Limit(params.PageSize).Find(&templates).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("list marketing templates: %w", err)
|
|
}
|
|
|
|
return templates, total, nil
|
|
}
|
|
|
|
func (r *TemplateRepository) IncrementDownloadCount(id uint) error {
|
|
tx := r.db.Model(&model.MarketingTemplate{}).Where("id = ?", id).
|
|
UpdateColumn("download_count", gorm.Expr("download_count + 1"))
|
|
if tx.Error != nil {
|
|
return fmt.Errorf("increment download count: %w", tx.Error)
|
|
}
|
|
return nil
|
|
}
|