419 lines
17 KiB
C#
419 lines
17 KiB
C#
using Microsoft.EntityFrameworkCore;
|
||
using FutureMailAPI.Data;
|
||
using FutureMailAPI.Models;
|
||
using FutureMailAPI.DTOs;
|
||
using System.Text.Json;
|
||
|
||
namespace FutureMailAPI.Services
|
||
{
|
||
public class PersonalSpaceService : IPersonalSpaceService
|
||
{
|
||
private readonly FutureMailDbContext _context;
|
||
private readonly ILogger<PersonalSpaceService> _logger;
|
||
|
||
public PersonalSpaceService(FutureMailDbContext context, ILogger<PersonalSpaceService> logger)
|
||
{
|
||
_context = context;
|
||
_logger = logger;
|
||
}
|
||
|
||
public async Task<ApiResponse<TimelineResponseDto>> GetTimelineAsync(int userId, TimelineQueryDto query)
|
||
{
|
||
try
|
||
{
|
||
var response = new TimelineResponseDto();
|
||
var timelineDict = new Dictionary<string, TimelineDateDto>();
|
||
|
||
// 获取发送的邮件
|
||
if (query.Type == TimelineType.ALL || query.Type == TimelineType.SENT)
|
||
{
|
||
var sentMailsQuery = _context.SentMails
|
||
.Where(m => m.SenderId == userId)
|
||
.Include(m => m.Recipient)
|
||
.AsQueryable();
|
||
|
||
if (query.StartDate.HasValue)
|
||
{
|
||
sentMailsQuery = sentMailsQuery.Where(m => m.SentAt >= query.StartDate.Value);
|
||
}
|
||
|
||
if (query.EndDate.HasValue)
|
||
{
|
||
sentMailsQuery = sentMailsQuery.Where(m => m.SentAt <= query.EndDate.Value);
|
||
}
|
||
|
||
var sentMails = await sentMailsQuery
|
||
.OrderBy(m => m.SentAt)
|
||
.ToListAsync();
|
||
|
||
foreach (var mail in sentMails)
|
||
{
|
||
var dateKey = mail.SentAt.ToString("yyyy-MM-dd");
|
||
|
||
if (!timelineDict.ContainsKey(dateKey))
|
||
{
|
||
timelineDict[dateKey] = new TimelineDateDto
|
||
{
|
||
Date = dateKey,
|
||
Events = new List<TimelineEventDto>()
|
||
};
|
||
}
|
||
|
||
var recipientName = mail.Recipient?.Username ?? "自己";
|
||
var recipientAvatar = mail.Recipient?.Avatar;
|
||
|
||
timelineDict[dateKey].Events.Add(new TimelineEventDto
|
||
{
|
||
Type = TimelineEventType.SENT,
|
||
MailId = mail.Id,
|
||
Title = mail.Title,
|
||
Time = mail.SentAt.ToString("HH:mm"),
|
||
WithUser = new UserInfoDto
|
||
{
|
||
UserId = mail.RecipientId ?? 0,
|
||
Username = recipientName,
|
||
Avatar = recipientAvatar
|
||
},
|
||
Emotion = AnalyzeMailEmotion(mail.Content)
|
||
});
|
||
}
|
||
}
|
||
|
||
// 获取接收的邮件
|
||
if (query.Type == TimelineType.ALL || query.Type == TimelineType.RECEIVED)
|
||
{
|
||
var receivedMailsQuery = _context.ReceivedMails
|
||
.Where(r => r.RecipientId == userId)
|
||
.Include(r => r.SentMail)
|
||
.ThenInclude(m => m.Sender)
|
||
.AsQueryable();
|
||
|
||
if (query.StartDate.HasValue)
|
||
{
|
||
receivedMailsQuery = receivedMailsQuery.Where(r => r.ReceivedAt >= query.StartDate.Value);
|
||
}
|
||
|
||
if (query.EndDate.HasValue)
|
||
{
|
||
receivedMailsQuery = receivedMailsQuery.Where(r => r.ReceivedAt <= query.EndDate.Value);
|
||
}
|
||
|
||
var receivedMails = await receivedMailsQuery
|
||
.OrderBy(r => r.ReceivedAt)
|
||
.ToListAsync();
|
||
|
||
foreach (var receivedMail in receivedMails)
|
||
{
|
||
var dateKey = receivedMail.ReceivedAt.ToString("yyyy-MM-dd");
|
||
|
||
if (!timelineDict.ContainsKey(dateKey))
|
||
{
|
||
timelineDict[dateKey] = new TimelineDateDto
|
||
{
|
||
Date = dateKey,
|
||
Events = new List<TimelineEventDto>()
|
||
};
|
||
}
|
||
|
||
var senderName = receivedMail.SentMail.Sender.Username;
|
||
var senderAvatar = receivedMail.SentMail.Sender.Avatar;
|
||
|
||
timelineDict[dateKey].Events.Add(new TimelineEventDto
|
||
{
|
||
Type = TimelineEventType.RECEIVED,
|
||
MailId = receivedMail.SentMailId,
|
||
Title = receivedMail.SentMail.Title,
|
||
Time = receivedMail.ReceivedAt.ToString("HH:mm"),
|
||
WithUser = new UserInfoDto
|
||
{
|
||
UserId = receivedMail.SentMail.SenderId,
|
||
Username = senderName,
|
||
Avatar = senderAvatar
|
||
},
|
||
Emotion = AnalyzeMailEmotion(receivedMail.SentMail.Content)
|
||
});
|
||
}
|
||
}
|
||
|
||
// 对每个日期的事件按时间排序
|
||
foreach (var dateEntry in timelineDict)
|
||
{
|
||
dateEntry.Value.Events = dateEntry.Value.Events
|
||
.OrderBy(e => e.Time)
|
||
.ToList();
|
||
}
|
||
|
||
// 按日期排序
|
||
response.Timeline = timelineDict
|
||
.OrderBy(kvp => kvp.Key)
|
||
.Select(kvp => kvp.Value)
|
||
.ToList();
|
||
|
||
return ApiResponse<TimelineResponseDto>.SuccessResult(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "获取时间线时发生错误");
|
||
return ApiResponse<TimelineResponseDto>.ErrorResult("获取时间线失败");
|
||
}
|
||
}
|
||
|
||
public async Task<ApiResponse<StatisticsResponseDto>> GetStatisticsAsync(int userId)
|
||
{
|
||
try
|
||
{
|
||
var response = new StatisticsResponseDto();
|
||
|
||
// 获取发送的邮件统计
|
||
var sentMails = await _context.SentMails
|
||
.Where(m => m.SenderId == userId)
|
||
.ToListAsync();
|
||
|
||
response.TotalSent = sentMails.Count;
|
||
|
||
// 获取接收的邮件统计
|
||
var receivedMails = await _context.ReceivedMails
|
||
.Where(r => r.RecipientId == userId)
|
||
.Include(r => r.SentMail)
|
||
.ThenInclude(m => m.Sender)
|
||
.ToListAsync();
|
||
|
||
response.TotalReceived = receivedMails.Count;
|
||
|
||
// 计算时间旅行时长(天)
|
||
if (sentMails.Any())
|
||
{
|
||
var earliestDelivery = sentMails.Min(m => m.DeliveryTime);
|
||
var latestDelivery = sentMails.Max(m => m.DeliveryTime);
|
||
response.TimeTravelDuration = (latestDelivery - earliestDelivery).Days;
|
||
}
|
||
|
||
// 找出最频繁的收件人
|
||
var recipientCounts = sentMails
|
||
.Where(m => m.RecipientId.HasValue)
|
||
.GroupBy(m => m.RecipientId)
|
||
.Select(g => new { RecipientId = g.Key, Count = g.Count() })
|
||
.OrderByDescending(g => g.Count)
|
||
.FirstOrDefault();
|
||
|
||
if (recipientCounts != null)
|
||
{
|
||
var recipient = await _context.Users
|
||
.FirstOrDefaultAsync(u => u.Id == recipientCounts.RecipientId);
|
||
|
||
response.MostFrequentRecipient = recipient?.Username ?? "未知用户";
|
||
}
|
||
|
||
// 找出最常见的年份(投递年份)
|
||
if (sentMails.Any())
|
||
{
|
||
var yearCounts = sentMails
|
||
.GroupBy(m => m.DeliveryTime.Year)
|
||
.Select(g => new { Year = g.Key, Count = g.Count() })
|
||
.OrderByDescending(g => g.Count)
|
||
.FirstOrDefault();
|
||
|
||
response.MostCommonYear = yearCounts?.Year ?? DateTime.Now.Year;
|
||
}
|
||
|
||
// 生成关键词云
|
||
var allContents = sentMails.Select(m => m.Content).ToList();
|
||
allContents.AddRange(receivedMails.Select(r => r.SentMail.Content));
|
||
|
||
response.KeywordCloud = GenerateKeywordCloud(allContents);
|
||
|
||
// 生成月度统计
|
||
response.MonthlyStats = GenerateMonthlyStats(sentMails, receivedMails);
|
||
|
||
return ApiResponse<StatisticsResponseDto>.SuccessResult(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "获取统计数据时发生错误");
|
||
return ApiResponse<StatisticsResponseDto>.ErrorResult("获取统计数据失败");
|
||
}
|
||
}
|
||
|
||
public async Task<ApiResponse<SubscriptionResponseDto>> GetSubscriptionAsync(int userId)
|
||
{
|
||
try
|
||
{
|
||
// 在实际应用中,这里会从数据库或订阅服务中获取用户的订阅信息
|
||
// 目前我们使用模拟数据
|
||
|
||
var user = await _context.Users
|
||
.FirstOrDefaultAsync(u => u.Id == userId);
|
||
|
||
if (user == null)
|
||
{
|
||
return ApiResponse<SubscriptionResponseDto>.ErrorResult("用户不存在");
|
||
}
|
||
|
||
// 模拟订阅数据
|
||
var response = new SubscriptionResponseDto
|
||
{
|
||
Plan = SubscriptionPlan.FREE, // 默认为免费计划
|
||
RemainingMails = 10 - await _context.SentMails.CountAsync(m => m.SenderId == userId && m.SentAt.Month == DateTime.Now.Month),
|
||
MaxAttachmentSize = 5 * 1024 * 1024, // 5MB
|
||
Features = new SubscriptionFeaturesDto
|
||
{
|
||
AdvancedTriggers = false,
|
||
CustomCapsules = false,
|
||
AIAssistant = true,
|
||
UnlimitedStorage = false,
|
||
PriorityDelivery = false
|
||
},
|
||
ExpireDate = null // 免费计划没有过期时间
|
||
};
|
||
|
||
// 如果用户创建时间超过30天,可以升级为高级用户(模拟)
|
||
if (user.CreatedAt.AddDays(30) < DateTime.UtcNow)
|
||
{
|
||
response.Plan = SubscriptionPlan.PREMIUM;
|
||
response.RemainingMails = 100;
|
||
response.MaxAttachmentSize = 50 * 1024 * 1024; // 50MB
|
||
response.Features.AdvancedTriggers = true;
|
||
response.Features.CustomCapsules = true;
|
||
response.Features.UnlimitedStorage = true;
|
||
response.ExpireDate = DateTime.UtcNow.AddMonths(1);
|
||
}
|
||
|
||
return ApiResponse<SubscriptionResponseDto>.SuccessResult(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "获取订阅信息时发生错误");
|
||
return ApiResponse<SubscriptionResponseDto>.ErrorResult("获取订阅信息失败");
|
||
}
|
||
}
|
||
|
||
public async Task<ApiResponse<UserProfileResponseDto>> GetUserProfileAsync(int userId)
|
||
{
|
||
try
|
||
{
|
||
var user = await _context.Users
|
||
.FirstOrDefaultAsync(u => u.Id == userId);
|
||
|
||
if (user == null)
|
||
{
|
||
return ApiResponse<UserProfileResponseDto>.ErrorResult("用户不存在");
|
||
}
|
||
|
||
// 获取订阅信息
|
||
var subscriptionResult = await GetSubscriptionAsync(userId);
|
||
|
||
var response = new UserProfileResponseDto
|
||
{
|
||
Id = user.Id,
|
||
Username = user.Username,
|
||
Email = user.Email,
|
||
Nickname = user.Nickname,
|
||
Avatar = user.Avatar,
|
||
CreatedAt = user.CreatedAt,
|
||
LastLoginAt = user.LastLoginAt,
|
||
Subscription = subscriptionResult.Data ?? new SubscriptionResponseDto()
|
||
};
|
||
|
||
return ApiResponse<UserProfileResponseDto>.SuccessResult(response);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "获取用户资料时发生错误");
|
||
return ApiResponse<UserProfileResponseDto>.ErrorResult("获取用户资料失败");
|
||
}
|
||
}
|
||
|
||
private string AnalyzeMailEmotion(string content)
|
||
{
|
||
// 简单的情感分析
|
||
var positiveKeywords = new[] { "开心", "快乐", "爱", "美好", "成功", "希望", "感谢", "幸福" };
|
||
var negativeKeywords = new[] { "悲伤", "难过", "失败", "痛苦", "失望", "愤怒", "焦虑", "恐惧" };
|
||
|
||
var positiveCount = positiveKeywords.Count(keyword => content.Contains(keyword));
|
||
var negativeCount = negativeKeywords.Count(keyword => content.Contains(keyword));
|
||
|
||
if (positiveCount > negativeCount)
|
||
return "积极";
|
||
else if (negativeCount > positiveCount)
|
||
return "消极";
|
||
else
|
||
return "中性";
|
||
}
|
||
|
||
private List<KeywordCloudDto> GenerateKeywordCloud(List<string> contents)
|
||
{
|
||
// 简单的关键词提取
|
||
var allWords = new List<string>();
|
||
|
||
foreach (var content in contents)
|
||
{
|
||
var words = content.Split(new[] { ' ', ',', '.', '!', '?', ';', ':', ',', '。', '!', '?', ';', ':' }, StringSplitOptions.RemoveEmptyEntries);
|
||
allWords.AddRange(words.Where(word => word.Length > 3));
|
||
}
|
||
|
||
var wordCounts = allWords
|
||
.GroupBy(word => word)
|
||
.Select(g => new { Word = g.Key, Count = g.Count() })
|
||
.OrderByDescending(g => g.Count)
|
||
.Take(20)
|
||
.ToList();
|
||
|
||
var maxCount = wordCounts.FirstOrDefault()?.Count ?? 1;
|
||
|
||
return wordCounts.Select(w => new KeywordCloudDto
|
||
{
|
||
Word = w.Word,
|
||
Count = w.Count,
|
||
Size = (int)((double)w.Count / maxCount * 10) + 1 // 1-10的大小
|
||
}).ToList();
|
||
}
|
||
|
||
private List<MonthlyStatsDto> GenerateMonthlyStats(List<SentMail> sentMails, List<ReceivedMail> receivedMails)
|
||
{
|
||
var monthlyStats = new Dictionary<string, MonthlyStatsDto>();
|
||
|
||
// 处理发送的邮件
|
||
foreach (var mail in sentMails)
|
||
{
|
||
var monthKey = mail.SentAt.ToString("yyyy-MM");
|
||
|
||
if (!monthlyStats.ContainsKey(monthKey))
|
||
{
|
||
monthlyStats[monthKey] = new MonthlyStatsDto
|
||
{
|
||
Month = monthKey,
|
||
Sent = 0,
|
||
Received = 0
|
||
};
|
||
}
|
||
|
||
monthlyStats[monthKey].Sent++;
|
||
}
|
||
|
||
// 处理接收的邮件
|
||
foreach (var receivedMail in receivedMails)
|
||
{
|
||
var monthKey = receivedMail.ReceivedAt.ToString("yyyy-MM");
|
||
|
||
if (!monthlyStats.ContainsKey(monthKey))
|
||
{
|
||
monthlyStats[monthKey] = new MonthlyStatsDto
|
||
{
|
||
Month = monthKey,
|
||
Sent = 0,
|
||
Received = 0
|
||
};
|
||
}
|
||
|
||
monthlyStats[monthKey].Received++;
|
||
}
|
||
|
||
// 按月份排序,只返回最近12个月的数据
|
||
return monthlyStats
|
||
.OrderBy(kvp => kvp.Key)
|
||
.TakeLast(12)
|
||
.Select(kvp => kvp.Value)
|
||
.ToList();
|
||
}
|
||
}
|
||
} |