feat: 实现通知管理功能,包括模型、仓库、服务和API处理器。

This commit is contained in:
2026-01-29 13:53:52 +08:00
parent 0a6c9d7d43
commit 734ff85185
4 changed files with 99 additions and 1 deletions

View File

@@ -233,6 +233,24 @@ func (h *NotificationHandler) BroadcastNotification(c *gin.Context) {
api.Success(c, gin.H{"message": "Notification broadcast started"})
}
// GetBroadcastHistory handles GET /api/v1/notifications/announcements
// Returns a list of system broadcast history
func (h *NotificationHandler) GetBroadcastHistory(c *gin.Context) {
limitStr := c.DefaultQuery("limit", "10")
offsetStr := c.DefaultQuery("offset", "0")
limit, _ := strconv.Atoi(limitStr)
offset, _ := strconv.Atoi(offsetStr)
result, err := h.notificationService.ListAnnouncements(limit, offset)
if err != nil {
api.InternalError(c, "Failed to get broadcast history: "+err.Error())
return
}
api.Success(c, result)
}
// RegisterUserRoutes registers notification routes for regular users
func (h *NotificationHandler) RegisterUserRoutes(rg *gin.RouterGroup) {
notifications := rg.Group("/notifications")
@@ -251,5 +269,6 @@ func (h *NotificationHandler) RegisterAdminRoutes(rg *gin.RouterGroup) {
{
notifications.POST("", h.CreateNotification)
notifications.POST("/broadcast", h.BroadcastNotification)
notifications.GET("/announcements", h.GetBroadcastHistory)
}
}

View File

@@ -37,3 +37,17 @@ type Notification struct {
func (Notification) TableName() string {
return "notifications"
}
// SystemAnnouncement represents a broadcast sent to all users
type SystemAnnouncement struct {
BaseModel
Title string `gorm:"size:200;not null" json:"title"`
Content string `gorm:"type:text;not null" json:"content"`
Type NotificationType `gorm:"size:30;not null;default:'system'" json:"type"`
SentCount int `gorm:"default:0" json:"sent_count"`
}
// TableName specifies the table name for SystemAnnouncement
func (SystemAnnouncement) TableName() string {
return "system_announcements"
}

View File

@@ -150,3 +150,30 @@ func (r *NotificationRepository) GetUnreadCount(userID uint) (int64, error) {
}
return count, nil
}
// CreateAnnouncement creates a new system announcement in the database
func (r *NotificationRepository) CreateAnnouncement(announcement *models.SystemAnnouncement) error {
if err := r.db.Create(announcement).Error; err != nil {
return fmt.Errorf("failed to create announcement: %w", err)
}
return nil
}
// ListAnnouncements retrieves system announcements with pagination
func (r *NotificationRepository) ListAnnouncements(limit, offset int) ([]models.SystemAnnouncement, int64, error) {
var announcements []models.SystemAnnouncement
var total int64
if err := r.db.Model(&models.SystemAnnouncement{}).Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count announcements: %w", err)
}
if err := r.db.Order("created_at DESC").
Limit(limit).
Offset(offset).
Find(&announcements).Error; err != nil {
return nil, 0, fmt.Errorf("failed to list announcements: %w", err)
}
return announcements, total, nil
}

View File

@@ -167,13 +167,26 @@ type BroadcastNotificationInput struct {
Content string `json:"content" binding:"required"`
}
// BroadcastNotification sends a notification to all active users
// BroadcastNotification sends a notification to all active users and saves to history
func (s *NotificationService) BroadcastNotification(input BroadcastNotificationInput) error {
userIDs, err := s.userRepo.GetAllActiveUserIDs()
if err != nil {
return fmt.Errorf("failed to get active user IDs: %w", err)
}
// Create announcement record
announcement := &models.SystemAnnouncement{
Title: input.Title,
Content: input.Content,
Type: input.Type,
SentCount: len(userIDs),
}
if err := s.repo.CreateAnnouncement(announcement); err != nil {
// Log error but continue with broadcasting if possible?
// Actually, better to store the history first.
return fmt.Errorf("failed to save announcement history: %w", err)
}
for _, userID := range userIDs {
// Ignore errors for individual users to ensure best-effort delivery
_, _ = s.CreateNotification(CreateNotificationInput{
@@ -186,3 +199,28 @@ func (s *NotificationService) BroadcastNotification(input BroadcastNotificationI
return nil
}
// AnnouncementListResult represents the result of a paginated announcement list query
type AnnouncementListResult struct {
Announcements []models.SystemAnnouncement `json:"announcements"`
Total int64 `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// ListAnnouncements retrieves system announcements with pagination
func (s *NotificationService) ListAnnouncements(limit, offset int) (*AnnouncementListResult, error) {
if limit <= 0 {
limit = 10
}
announcements, total, err := s.repo.ListAnnouncements(limit, offset)
if err != nil {
return nil, err
}
return &AnnouncementListResult{
Announcements: announcements,
Total: total,
Limit: limit,
Offset: offset,
}, nil
}