MilliSim/backend/MilliSim.Api/Services/NotificationService.cs

173 lines
5.9 KiB
C#

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;
}
/// <summary>
/// 将通知类型枚举转为中文名称
/// </summary>
private static string GetTypeName(NotificationType type) => type switch
{
NotificationType.System => "系统",
NotificationType.Project => "项目",
NotificationType.Account => "账号",
NotificationType.Authorization => "授权",
_ => "通知"
};
public async Task<ApiResponse<PagedResult<NotificationDto>>> 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<PagedResult<NotificationDto>>.Success(
PagedResult<NotificationDto>.Create(items, total, request.PageIndex, request.PageSize));
}
public async Task<ApiResponse<int>> 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<int>.Success(count);
}
public async Task<ApiResponse> 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<ApiResponse> 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<ApiResponse> 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<ApiResponse<NotificationDto>> 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<NotificationDto>.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<NotificationDto>.Success(new NotificationDto
{
Id = notification.Id,
Type = notification.Type,
TypeName = GetTypeName(notification.Type),
Title = notification.Title,
Content = notification.Content,
IsRead = false,
CreatedAt = notification.CreatedAt
});
}
}