feat: 实现通知管理功能,包括模型、仓库、服务和API处理器。
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user