using Microsoft.EntityFrameworkCore; using FutureMailAPI.Data; using FutureMailAPI.Models; using FutureMailAPI.DTOs; namespace FutureMailAPI.Services { public class MailService : IMailService { private readonly FutureMailDbContext _context; public MailService(FutureMailDbContext context) { _context = context; } public async Task> CreateMailAsync(int userId, SentMailCreateDto createDto) { // 检查投递时间是否在未来 if (createDto.DeliveryTime <= DateTime.UtcNow) { return ApiResponse.ErrorResult("投递时间必须是未来时间"); } // 如果是指定用户,检查用户是否存在 int? recipientId = null; if (createDto.RecipientType == 1 && !string.IsNullOrEmpty(createDto.RecipientEmail)) { var recipient = await _context.Users .FirstOrDefaultAsync(u => u.Email == createDto.RecipientEmail); if (recipient == null) { return ApiResponse.ErrorResult("收件人不存在"); } recipientId = recipient.Id; } // 创建邮件 var mail = new SentMail { Title = createDto.Title, Content = createDto.Content, SenderId = userId, RecipientType = createDto.RecipientType, RecipientId = recipientId, DeliveryTime = createDto.DeliveryTime, SentAt = DateTime.UtcNow, // 显式设置发送时间 Status = createDto.DeliveryTime > DateTime.UtcNow ? 1 : 0, // 根据投递时间直接设置状态 TriggerType = createDto.TriggerType, TriggerDetails = createDto.TriggerDetails, Attachments = createDto.Attachments, IsEncrypted = createDto.IsEncrypted, EncryptionKey = createDto.EncryptionKey, Theme = createDto.Theme }; _context.SentMails.Add(mail); await _context.SaveChangesAsync(); // 如果是发送状态(不是草稿),创建时间胶囊 if (mail.Status == 1) // 已发送(待投递) { // 创建时间胶囊 var timeCapsule = new TimeCapsule { UserId = userId, SentMailId = mail.Id, PositionX = 0, PositionY = 0, PositionZ = 0, Status = 1, // 漂浮中 Type = 0 // 普通 }; _context.TimeCapsules.Add(timeCapsule); await _context.SaveChangesAsync(); } var mailResponse = await GetSentMailWithDetailsAsync(mail.Id); return ApiResponse.SuccessResult(mailResponse, "邮件创建成功"); } public async Task>> GetSentMailsAsync(int userId, MailListQueryDto queryDto) { var query = _context.SentMails .Where(m => m.SenderId == userId) .Include(m => m.Sender) .Include(m => m.Recipient) .AsQueryable(); // 应用筛选条件 if (queryDto.Status.HasValue) { query = query.Where(m => m.Status == queryDto.Status.Value); } if (queryDto.RecipientType.HasValue) { query = query.Where(m => m.RecipientType == queryDto.RecipientType.Value); } if (!string.IsNullOrEmpty(queryDto.Keyword)) { query = query.Where(m => m.Title.Contains(queryDto.Keyword) || m.Content.Contains(queryDto.Keyword)); } if (queryDto.StartDate.HasValue) { query = query.Where(m => m.SentAt >= queryDto.StartDate.Value); } if (queryDto.EndDate.HasValue) { query = query.Where(m => m.SentAt <= queryDto.EndDate.Value); } // 排序 query = query.OrderByDescending(m => m.SentAt); // 分页 var totalCount = await query.CountAsync(); var mails = await query .Skip((queryDto.PageIndex - 1) * queryDto.PageSize) .Take(queryDto.PageSize) .ToListAsync(); var mailDtos = mails.Select(MapToSentMailResponseDto).ToList(); var pagedResponse = new PagedResponse( mailDtos, queryDto.PageIndex, queryDto.PageSize, totalCount); return ApiResponse>.SuccessResult(pagedResponse); } public async Task> GetSentMailByIdAsync(int userId, int mailId) { var mail = await _context.SentMails .Include(m => m.Sender) .Include(m => m.Recipient) .FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId); if (mail == null) { return ApiResponse.ErrorResult("邮件不存在"); } var mailDto = MapToSentMailResponseDto(mail); return ApiResponse.SuccessResult(mailDto); } public async Task> UpdateMailAsync(int userId, int mailId, SentMailUpdateDto updateDto) { var mail = await _context.SentMails .FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId); if (mail == null) { return ApiResponse.ErrorResult("邮件不存在"); } // 检查邮件是否已投递,已投递的邮件不能修改 if (mail.Status >= 2) { return ApiResponse.ErrorResult("已投递的邮件不能修改"); } // 更新邮件信息 if (updateDto.Title != null) { mail.Title = updateDto.Title; } if (updateDto.Content != null) { mail.Content = updateDto.Content; } if (updateDto.DeliveryTime.HasValue) { if (updateDto.DeliveryTime.Value <= DateTime.UtcNow) { return ApiResponse.ErrorResult("投递时间必须是未来时间"); } mail.DeliveryTime = updateDto.DeliveryTime.Value; } if (updateDto.TriggerDetails != null) { mail.TriggerDetails = updateDto.TriggerDetails; } if (updateDto.Attachments != null) { mail.Attachments = updateDto.Attachments; } if (updateDto.Theme != null) { mail.Theme = updateDto.Theme; } await _context.SaveChangesAsync(); var mailResponse = await GetSentMailWithDetailsAsync(mail.Id); return ApiResponse.SuccessResult(mailResponse, "邮件更新成功"); } public async Task> DeleteMailAsync(int userId, int mailId) { var mail = await _context.SentMails .FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId); if (mail == null) { return ApiResponse.ErrorResult("邮件不存在"); } // 检查邮件是否已投递,已投递的邮件不能删除 if (mail.Status >= 2) { return ApiResponse.ErrorResult("已投递的邮件不能删除"); } // 删除相关的时间胶囊 var timeCapsule = await _context.TimeCapsules .FirstOrDefaultAsync(tc => tc.SentMailId == mailId); if (timeCapsule != null) { _context.TimeCapsules.Remove(timeCapsule); } // 删除邮件 _context.SentMails.Remove(mail); await _context.SaveChangesAsync(); return ApiResponse.SuccessResult(true, "邮件删除成功"); } public async Task>> GetReceivedMailsAsync(int userId, MailListQueryDto queryDto) { var query = _context.ReceivedMails .Where(r => r.RecipientId == userId) .Include(r => r.SentMail) .ThenInclude(m => m.Sender) .AsQueryable(); // 应用筛选条件 if (queryDto.Status.HasValue) { if (queryDto.Status.Value == 0) // 未读 { query = query.Where(r => !r.IsRead); } else if (queryDto.Status.Value == 1) // 已读 { query = query.Where(r => r.IsRead); } } if (!string.IsNullOrEmpty(queryDto.Keyword)) { query = query.Where(r => r.SentMail.Title.Contains(queryDto.Keyword) || r.SentMail.Content.Contains(queryDto.Keyword)); } if (queryDto.StartDate.HasValue) { query = query.Where(r => r.ReceivedAt >= queryDto.StartDate.Value); } if (queryDto.EndDate.HasValue) { query = query.Where(r => r.ReceivedAt <= queryDto.EndDate.Value); } // 排序 query = query.OrderByDescending(r => r.ReceivedAt); // 分页 var totalCount = await query.CountAsync(); var receivedMails = await query .Skip((queryDto.PageIndex - 1) * queryDto.PageSize) .Take(queryDto.PageSize) .ToListAsync(); var mailDtos = receivedMails.Select(MapToReceivedMailResponseDto).ToList(); var pagedResponse = new PagedResponse( mailDtos, queryDto.PageIndex, queryDto.PageSize, totalCount); return ApiResponse>.SuccessResult(pagedResponse); } public async Task> GetReceivedMailByIdAsync(int userId, int mailId) { var receivedMail = await _context.ReceivedMails .Include(r => r.SentMail) .ThenInclude(m => m.Sender) .FirstOrDefaultAsync(r => r.Id == mailId && r.RecipientId == userId); if (receivedMail == null) { return ApiResponse.ErrorResult("邮件不存在"); } var mailDto = MapToReceivedMailResponseDto(receivedMail); return ApiResponse.SuccessResult(mailDto); } public async Task> MarkReceivedMailAsReadAsync(int userId, int mailId) { var receivedMail = await _context.ReceivedMails .FirstOrDefaultAsync(r => r.Id == mailId && r.RecipientId == userId); if (receivedMail == null) { return ApiResponse.ErrorResult("邮件不存在"); } if (!receivedMail.IsRead) { receivedMail.IsRead = true; receivedMail.ReadAt = DateTime.UtcNow; await _context.SaveChangesAsync(); } return ApiResponse.SuccessResult(true, "邮件已标记为已读"); } public Task> GetMailByIdAsync(int userId, int mailId) { return GetSentMailByIdAsync(userId, mailId); } public Task>> GetMailsAsync(int userId, MailListQueryDto queryDto) { return GetSentMailsAsync(userId, queryDto); } public Task> MarkAsReadAsync(int userId, int mailId) { return MarkReceivedMailAsReadAsync(userId, mailId); } public async Task> RevokeMailAsync(int userId, int mailId) { var mail = await _context.SentMails .FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId); if (mail == null) { return ApiResponse.ErrorResult("邮件不存在"); } // 检查邮件是否已投递,已投递的邮件不能撤销 if (mail.Status >= 2) { return ApiResponse.ErrorResult("已投递的邮件不能撤销"); } // 更新邮件状态为已撤销 mail.Status = 4; // 4-已撤销 await _context.SaveChangesAsync(); // 更新相关的时间胶囊状态 var timeCapsule = await _context.TimeCapsules .FirstOrDefaultAsync(tc => tc.SentMailId == mailId); if (timeCapsule != null) { timeCapsule.Status = 3; // 3-已撤销 await _context.SaveChangesAsync(); } return ApiResponse.SuccessResult(true, "邮件已撤销"); } private async Task GetSentMailWithDetailsAsync(int mailId) { var mail = await _context.SentMails .Include(m => m.Sender) .Include(m => m.Recipient) .FirstOrDefaultAsync(m => m.Id == mailId); return MapToSentMailResponseDto(mail!); } private static SentMailResponseDto MapToSentMailResponseDto(SentMail mail) { return new SentMailResponseDto { Id = mail.Id, Title = mail.Title, Content = mail.Content, SenderId = mail.SenderId, SenderUsername = mail.Sender?.Username ?? "", RecipientType = mail.RecipientType, RecipientId = mail.RecipientId, RecipientUsername = mail.Recipient?.Username ?? "", SentAt = mail.SentAt, DeliveryTime = mail.DeliveryTime, Status = mail.Status, StatusText = GetStatusText(mail.Status), TriggerType = mail.TriggerType, TriggerTypeText = GetTriggerTypeText(mail.TriggerType), TriggerDetails = mail.TriggerDetails, Attachments = mail.Attachments, IsEncrypted = mail.IsEncrypted, Theme = mail.Theme, RecipientTypeText = GetRecipientTypeText(mail.RecipientType), DaysUntilDelivery = (int)(mail.DeliveryTime - DateTime.UtcNow).TotalDays }; } private static ReceivedMailResponseDto MapToReceivedMailResponseDto(ReceivedMail receivedMail) { return new ReceivedMailResponseDto { Id = receivedMail.Id, SentMailId = receivedMail.SentMailId, Title = receivedMail.SentMail.Title, Content = receivedMail.SentMail.Content, SenderUsername = receivedMail.SentMail.Sender?.Username ?? "", SentAt = receivedMail.SentMail.SentAt, ReceivedAt = receivedMail.ReceivedAt, IsRead = receivedMail.IsRead, ReadAt = receivedMail.ReadAt, IsReplied = receivedMail.IsReplied, ReplyMailId = receivedMail.ReplyMailId, Theme = receivedMail.SentMail.Theme }; } private static string GetStatusText(int status) { return status switch { 0 => "草稿", 1 => "已发送(待投递)", 2 => "投递中", 3 => "已送达", _ => "未知" }; } private static string GetRecipientTypeText(int recipientType) { return recipientType switch { 0 => "自己", 1 => "指定用户", 2 => "公开时间胶囊", _ => "未知" }; } private static string GetTriggerTypeText(int triggerType) { return triggerType switch { 0 => "时间", 1 => "地点", 2 => "事件", _ => "未知" }; } } }