Files
ai_english/serve/internal/services/notification_service.go

164 lines
4.4 KiB
Go
Raw Normal View History

2025-11-17 13:39:05 +08:00
package services
import (
"fmt"
"time"
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/models"
"gorm.io/gorm"
)
// NotificationService 通知服务
type NotificationService struct {
db *gorm.DB
}
// NewNotificationService 创建通知服务实例
func NewNotificationService(db *gorm.DB) *NotificationService {
return &NotificationService{db: db}
}
// GetUserNotifications 获取用户通知列表
func (s *NotificationService) GetUserNotifications(userID int64, page, limit int, onlyUnread bool) ([]models.Notification, int64, error) {
var notifications []models.Notification
var total int64
query := s.db.Model(&models.Notification{}).Where("user_id = ?", userID)
// 只查询未读通知
if onlyUnread {
query = query.Where("is_read = ?", false)
}
// 获取总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("统计通知数量失败: %w", err)
}
// 分页查询
offset := (page - 1) * limit
if err := query.Order("priority DESC, created_at DESC").
Offset(offset).
Limit(limit).
Find(&notifications).Error; err != nil {
return nil, 0, fmt.Errorf("查询通知列表失败: %w", err)
}
return notifications, total, nil
}
// GetUnreadCount 获取未读通知数量
func (s *NotificationService) GetUnreadCount(userID int64) (int64, error) {
var count int64
if err := s.db.Model(&models.Notification{}).
Where("user_id = ? AND is_read = ?", userID, false).
Count(&count).Error; err != nil {
return 0, fmt.Errorf("统计未读通知失败: %w", err)
}
return count, nil
}
// MarkAsRead 标记通知为已读
func (s *NotificationService) MarkAsRead(userID, notificationID int64) error {
now := time.Now()
result := s.db.Model(&models.Notification{}).
Where("id = ? AND user_id = ?", notificationID, userID).
Updates(map[string]interface{}{
"is_read": true,
"read_at": now,
})
if result.Error != nil {
return fmt.Errorf("标记通知已读失败: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("通知不存在或无权限")
}
return nil
}
// MarkAllAsRead 标记所有通知为已读
func (s *NotificationService) MarkAllAsRead(userID int64) error {
now := time.Now()
result := s.db.Model(&models.Notification{}).
Where("user_id = ? AND is_read = ?", userID, false).
Updates(map[string]interface{}{
"is_read": true,
"read_at": now,
})
if result.Error != nil {
return fmt.Errorf("标记所有通知已读失败: %w", result.Error)
}
return nil
}
// DeleteNotification 删除通知
func (s *NotificationService) DeleteNotification(userID, notificationID int64) error {
result := s.db.Where("id = ? AND user_id = ?", notificationID, userID).
Delete(&models.Notification{})
if result.Error != nil {
return fmt.Errorf("删除通知失败: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("通知不存在或无权限")
}
return nil
}
// CreateNotification 创建通知(内部使用)
func (s *NotificationService) CreateNotification(notification *models.Notification) error {
if err := s.db.Create(notification).Error; err != nil {
return fmt.Errorf("创建通知失败: %w", err)
}
return nil
}
// SendSystemNotification 发送系统通知
func (s *NotificationService) SendSystemNotification(userID int64, title, content string, link *string, priority int) error {
notification := &models.Notification{
UserID: userID,
Type: models.NotificationTypeSystem,
Title: title,
Content: content,
Link: link,
Priority: priority,
IsRead: false,
}
return s.CreateNotification(notification)
}
// SendLearningReminder 发送学习提醒
func (s *NotificationService) SendLearningReminder(userID int64, title, content string, link *string) error {
notification := &models.Notification{
UserID: userID,
Type: models.NotificationTypeLearning,
Title: title,
Content: content,
Link: link,
Priority: models.NotificationPriorityNormal,
IsRead: false,
}
return s.CreateNotification(notification)
}
// SendAchievementNotification 发送成就通知
func (s *NotificationService) SendAchievementNotification(userID int64, title, content string, link *string) error {
notification := &models.Notification{
UserID: userID,
Type: models.NotificationTypeAchievement,
Title: title,
Content: content,
Link: link,
Priority: models.NotificationPriorityImportant,
IsRead: false,
}
return s.CreateNotification(notification)
}