using Microsoft.EntityFrameworkCore; using MilliSim.Common.Dtos; using MilliSim.Common.Entities; using MilliSim.Common.Models; using MilliSim.Data; using MilliSim.Services.Infrastructure; namespace MilliSim.Services; public class NotificationService : INotificationService { private readonly MilliSimDbContext _db; private readonly ICurrentUserService _currentUser; public NotificationService(MilliSimDbContext db, ICurrentUserService currentUser) { _db = db; _currentUser = currentUser; } /// /// 将通知类型枚举转为中文名称 /// private static string GetTypeName(NotificationType type) => type switch { NotificationType.System => "系统", NotificationType.Project => "项目", NotificationType.Account => "账号", NotificationType.Authorization => "授权", _ => "通知" }; public async Task>> GetNotificationsAsync(NotificationType? type, PageRequest request) { var userId = _currentUser.UserId; var query = _db.Notifications .Where(n => n.UserId == null || n.UserId == userId); if (type.HasValue) query = query.Where(n => n.Type == type.Value); if (!string.IsNullOrEmpty(request.Keyword)) query = query.Where(n => n.Title.Contains(request.Keyword) || n.Content.Contains(request.Keyword)); var total = await query.CountAsync(); var items = await query .OrderByDescending(n => n.CreatedAt) .Skip((request.PageIndex - 1) * request.PageSize) .Take(request.PageSize) .Select(n => new NotificationDto { Id = n.Id, Type = n.Type, Title = n.Title, Content = n.Content, IsRead = _db.NotificationReads.Any(r => r.NotificationId == n.Id && r.UserId == userId), CreatedAt = n.CreatedAt }) .ToListAsync(); // 在内存中设置中文类型名(避免 EF 翻译 switch 表达式) foreach (var item in items) item.TypeName = GetTypeName(item.Type); return ApiResponse>.Success( PagedResult.Create(items, total, request.PageIndex, request.PageSize)); } public async Task> GetUnreadCountAsync() { var userId = _currentUser.UserId; var count = await _db.Notifications .Where(n => n.UserId == null || n.UserId == userId) .Where(n => !_db.NotificationReads.Any(r => r.NotificationId == n.Id && r.UserId == userId)) .CountAsync(); return ApiResponse.Success(count); } public async Task MarkAsReadAsync(long id) { var userId = _currentUser.UserId; var notification = await _db.Notifications .FirstOrDefaultAsync(n => n.Id == id && (n.UserId == null || n.UserId == userId)); if (notification == null) return ApiResponse.Fail("通知不存在", 404); var exists = await _db.NotificationReads .AnyAsync(r => r.NotificationId == id && r.UserId == userId); if (!exists) { _db.NotificationReads.Add(new NotificationRead { UserId = userId, NotificationId = id }); await _db.SaveChangesAsync(); } return ApiResponse.Success("已标记为已读"); } public async Task MarkAllAsReadAsync() { var userId = _currentUser.UserId; var unreadIds = await _db.Notifications .Where(n => n.UserId == null || n.UserId == userId) .Where(n => !_db.NotificationReads.Any(r => r.NotificationId == n.Id && r.UserId == userId)) .Select(n => n.Id) .ToListAsync(); foreach (var nid in unreadIds) { _db.NotificationReads.Add(new NotificationRead { UserId = userId, NotificationId = nid }); } await _db.SaveChangesAsync(); return ApiResponse.Success($"已将 {unreadIds.Count} 条通知标记为已读"); } public async Task DeleteNotificationAsync(long id) { var userId = _currentUser.UserId; var notification = await _db.Notifications .FirstOrDefaultAsync(n => n.Id == id && (n.UserId == null || n.UserId == userId)); if (notification == null) return ApiResponse.Fail("通知不存在", 404); notification.IsDeleted = true; notification.UpdatedAt = DateTime.Now; await _db.SaveChangesAsync(); return ApiResponse.Success("通知已删除"); } public async Task> CreateNotificationAsync(NotificationType type, string title, string content, long? userId = null, string? eventId = null) { // 根据 eventId 防重复 if (!string.IsNullOrEmpty(eventId)) { var exists = await _db.Notifications.AnyAsync(n => n.EventId == eventId); if (exists) return ApiResponse.Fail("通知已存在", 409); } var notification = new Notification { Type = type, Title = title, Content = content, UserId = userId, EventId = eventId }; _db.Notifications.Add(notification); await _db.SaveChangesAsync(); return ApiResponse.Success(new NotificationDto { Id = notification.Id, Type = notification.Type, TypeName = GetTypeName(notification.Type), Title = notification.Title, Content = notification.Content, IsRead = false, CreatedAt = notification.CreatedAt }); } }