feat: add announcement feature with admin management and home page display
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"sale/internal/models"
|
||||
"sale/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AnnouncementHandler struct{}
|
||||
|
||||
func NewAnnouncementHandler() *AnnouncementHandler {
|
||||
return &AnnouncementHandler{}
|
||||
}
|
||||
|
||||
// List 用户端接口 - 只返回激活的公告
|
||||
func (h *AnnouncementHandler) List(c *gin.Context) {
|
||||
var announcements []models.Announcement
|
||||
utils.DB.Where("is_active = ?", true).
|
||||
Order("sort_order ASC, created_at DESC").
|
||||
Find(&announcements)
|
||||
c.JSON(http.StatusOK, gin.H{"data": announcements})
|
||||
}
|
||||
|
||||
// AdminList 管理端接口 - 返回所有公告
|
||||
func (h *AnnouncementHandler) AdminList(c *gin.Context) {
|
||||
var announcements []models.Announcement
|
||||
utils.DB.Order("sort_order ASC, created_at DESC").Find(&announcements)
|
||||
c.JSON(http.StatusOK, gin.H{"data": announcements})
|
||||
}
|
||||
|
||||
// Create 创建公告
|
||||
func (h *AnnouncementHandler) Create(c *gin.Context) {
|
||||
var req struct {
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "标题不能为空"})
|
||||
return
|
||||
}
|
||||
|
||||
announcement := models.Announcement{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
SortOrder: req.SortOrder,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
utils.DB.Create(&announcement)
|
||||
c.JSON(http.StatusCreated, gin.H{"data": announcement})
|
||||
}
|
||||
|
||||
// Update 更新公告
|
||||
func (h *AnnouncementHandler) Update(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var announcement models.Announcement
|
||||
if err := utils.DB.First(&announcement, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "公告不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
announcement.Title = req.Title
|
||||
announcement.Content = req.Content
|
||||
announcement.SortOrder = req.SortOrder
|
||||
announcement.IsActive = req.IsActive
|
||||
utils.DB.Save(&announcement)
|
||||
c.JSON(http.StatusOK, gin.H{"data": announcement})
|
||||
}
|
||||
|
||||
// Delete 删除公告
|
||||
func (h *AnnouncementHandler) Delete(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的ID"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := utils.DB.Delete(&models.Announcement{}, id).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除失败"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
// ToggleActive 切换激活状态
|
||||
func (h *AnnouncementHandler) ToggleActive(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var announcement models.Announcement
|
||||
if err := utils.DB.First(&announcement, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "公告不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
announcement.IsActive = !announcement.IsActive
|
||||
utils.DB.Save(&announcement)
|
||||
c.JSON(http.StatusOK, gin.H{"data": announcement})
|
||||
}
|
||||
@@ -28,6 +28,7 @@ func SetupRoutes(r *gin.Engine) {
|
||||
logHandler := handlers.NewLogHandler()
|
||||
purchaseGroupHandler := handlers.NewPurchaseGroupHandler()
|
||||
shippingTemplateHandler := handlers.NewShippingTemplateHandler()
|
||||
announcementHandler := handlers.NewAnnouncementHandler()
|
||||
|
||||
r.Use(middlewares.CORSMiddleware())
|
||||
|
||||
@@ -62,6 +63,7 @@ func SetupRoutes(r *gin.Engine) {
|
||||
}
|
||||
|
||||
api.GET("/banners", bannerHandler.List)
|
||||
api.GET("/announcements", announcementHandler.List)
|
||||
|
||||
api.GET("/categories", categoryHandler.List)
|
||||
api.GET("/brands", brandHandler.List)
|
||||
@@ -262,6 +264,15 @@ func SetupRoutes(r *gin.Engine) {
|
||||
adminShippingTemplates.PUT("/:id", shippingTemplateHandler.Update)
|
||||
adminShippingTemplates.DELETE("/:id", shippingTemplateHandler.Delete)
|
||||
}
|
||||
|
||||
adminAnnouncements := admin.Group("/announcements")
|
||||
{
|
||||
adminAnnouncements.GET("", announcementHandler.AdminList)
|
||||
adminAnnouncements.POST("", announcementHandler.Create)
|
||||
adminAnnouncements.PUT("/:id", announcementHandler.Update)
|
||||
adminAnnouncements.DELETE("/:id", announcementHandler.Delete)
|
||||
adminAnnouncements.PUT("/:id/toggle", announcementHandler.ToggleActive)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Announcement struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Title string `gorm:"size:255;not null" json:"title"`
|
||||
Content string `gorm:"type:text" json:"content"`
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
func (Announcement) TableName() string {
|
||||
return "announcements"
|
||||
}
|
||||
@@ -82,6 +82,7 @@ func AutoMigrate() {
|
||||
&models.Article{},
|
||||
&models.Banner{},
|
||||
&models.PaymentChannel{},
|
||||
&models.Announcement{},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to migrate database: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user