-feat 修复部分bug
This commit is contained in:
160
internal/service/notification_service.go
Normal file
160
internal/service/notification_service.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"accounting-app/internal/models"
|
||||
"accounting-app/internal/repository"
|
||||
)
|
||||
|
||||
// Notification service errors
|
||||
var (
|
||||
ErrNotificationNotFound = errors.New("notification not found")
|
||||
)
|
||||
|
||||
// NotificationService handles business logic for notifications
|
||||
type NotificationService struct {
|
||||
repo *repository.NotificationRepository
|
||||
}
|
||||
|
||||
// NewNotificationService creates a new NotificationService instance
|
||||
func NewNotificationService(repo *repository.NotificationRepository) *NotificationService {
|
||||
return &NotificationService{repo: repo}
|
||||
}
|
||||
|
||||
// CreateNotificationInput represents input for creating a notification
|
||||
type CreateNotificationInput struct {
|
||||
UserID uint
|
||||
Type models.NotificationType
|
||||
Title string
|
||||
Content string
|
||||
RelatedID *uint
|
||||
}
|
||||
|
||||
// CreateNotification creates a new notification
|
||||
func (s *NotificationService) CreateNotification(input CreateNotificationInput) (*models.Notification, error) {
|
||||
notification := &models.Notification{
|
||||
UserID: input.UserID,
|
||||
Type: input.Type,
|
||||
Title: input.Title,
|
||||
Content: input.Content,
|
||||
RelatedID: input.RelatedID,
|
||||
IsRead: false,
|
||||
}
|
||||
|
||||
if err := s.repo.Create(notification); err != nil {
|
||||
return nil, fmt.Errorf("failed to create notification: %w", err)
|
||||
}
|
||||
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
// GetNotification retrieves a notification by ID
|
||||
func (s *NotificationService) GetNotification(userID, id uint) (*models.Notification, error) {
|
||||
notification, err := s.repo.GetByID(userID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrNotificationNotFound) {
|
||||
return nil, ErrNotificationNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
// NotificationListInput represents input for listing notifications
|
||||
type NotificationListInput struct {
|
||||
Type *models.NotificationType
|
||||
IsRead *bool
|
||||
Offset int
|
||||
Limit int
|
||||
}
|
||||
|
||||
// ListNotifications retrieves notifications with pagination
|
||||
func (s *NotificationService) ListNotifications(userID uint, input NotificationListInput) (*repository.NotificationListResult, error) {
|
||||
limit := input.Limit
|
||||
if limit <= 0 {
|
||||
limit = 20
|
||||
}
|
||||
|
||||
options := repository.NotificationListOptions{
|
||||
Type: input.Type,
|
||||
IsRead: input.IsRead,
|
||||
Offset: input.Offset,
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
return s.repo.List(userID, options)
|
||||
}
|
||||
|
||||
// MarkAsRead marks a notification as read
|
||||
func (s *NotificationService) MarkAsRead(userID, id uint) error {
|
||||
err := s.repo.MarkAsRead(userID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrNotificationNotFound) {
|
||||
return ErrNotificationNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarkAllAsRead marks all notifications as read
|
||||
func (s *NotificationService) MarkAllAsRead(userID uint) error {
|
||||
return s.repo.MarkAllAsRead(userID)
|
||||
}
|
||||
|
||||
// DeleteNotification deletes a notification
|
||||
func (s *NotificationService) DeleteNotification(userID, id uint) error {
|
||||
err := s.repo.Delete(userID, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrNotificationNotFound) {
|
||||
return ErrNotificationNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUnreadCount returns the count of unread notifications
|
||||
func (s *NotificationService) GetUnreadCount(userID uint) (int64, error) {
|
||||
return s.repo.GetUnreadCount(userID)
|
||||
}
|
||||
|
||||
// SendBudgetAlert creates a budget alert notification
|
||||
func (s *NotificationService) SendBudgetAlert(userID uint, budgetName string, usedPercentage float64, budgetID uint) (*models.Notification, error) {
|
||||
title := fmt.Sprintf("预算提醒: %s", budgetName)
|
||||
content := fmt.Sprintf("您的「%s」预算已使用 %.1f%%,请注意控制支出。", budgetName, usedPercentage)
|
||||
|
||||
return s.CreateNotification(CreateNotificationInput{
|
||||
UserID: userID,
|
||||
Type: models.NotificationTypeBudgetAlert,
|
||||
Title: title,
|
||||
Content: content,
|
||||
RelatedID: &budgetID,
|
||||
})
|
||||
}
|
||||
|
||||
// SendRecurringReminder creates a recurring transaction reminder
|
||||
func (s *NotificationService) SendRecurringReminder(userID uint, recurringName string, amount float64, recurringID uint) (*models.Notification, error) {
|
||||
title := fmt.Sprintf("周期交易提醒: %s", recurringName)
|
||||
content := fmt.Sprintf("您的周期交易「%s」(¥%.2f) 已自动执行。", recurringName, amount)
|
||||
|
||||
return s.CreateNotification(CreateNotificationInput{
|
||||
UserID: userID,
|
||||
Type: models.NotificationTypeRecurring,
|
||||
Title: title,
|
||||
Content: content,
|
||||
RelatedID: &recurringID,
|
||||
})
|
||||
}
|
||||
|
||||
// SendSystemNotification creates a system notification
|
||||
func (s *NotificationService) SendSystemNotification(userID uint, title, content string) (*models.Notification, error) {
|
||||
return s.CreateNotification(CreateNotificationInput{
|
||||
UserID: userID,
|
||||
Type: models.NotificationTypeSystem,
|
||||
Title: title,
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user