436 lines
17 KiB
C#
436 lines
17 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using FutureMailAPI.Data;
|
|
using FutureMailAPI.Models;
|
|
using FutureMailAPI.DTOs;
|
|
|
|
namespace FutureMailAPI.Services
|
|
{
|
|
public class TimeCapsuleService : ITimeCapsuleService
|
|
{
|
|
private readonly FutureMailDbContext _context;
|
|
|
|
public TimeCapsuleService(FutureMailDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleResponseDto>> CreateTimeCapsuleAsync(int userId, TimeCapsuleCreateDto createDto)
|
|
{
|
|
// 检查邮件是否存在且属于当前用户
|
|
var mail = await _context.SentMails
|
|
.FirstOrDefaultAsync(m => m.Id == createDto.SentMailId && m.SenderId == userId);
|
|
|
|
if (mail == null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("邮件不存在或无权限");
|
|
}
|
|
|
|
// 检查是否已存在时间胶囊
|
|
var existingCapsule = await _context.TimeCapsules
|
|
.FirstOrDefaultAsync(tc => tc.SentMailId == createDto.SentMailId);
|
|
|
|
if (existingCapsule != null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("该邮件已创建时间胶囊");
|
|
}
|
|
|
|
// 创建时间胶囊
|
|
var timeCapsule = new TimeCapsule
|
|
{
|
|
UserId = userId,
|
|
SentMailId = createDto.SentMailId,
|
|
PositionX = createDto.PositionX,
|
|
PositionY = createDto.PositionY,
|
|
PositionZ = createDto.PositionZ,
|
|
Size = createDto.Size,
|
|
Color = createDto.Color,
|
|
Opacity = createDto.Opacity,
|
|
Rotation = createDto.Rotation,
|
|
Status = 1, // 漂浮中
|
|
Type = createDto.Type
|
|
};
|
|
|
|
_context.TimeCapsules.Add(timeCapsule);
|
|
await _context.SaveChangesAsync();
|
|
|
|
var capsuleResponse = await GetTimeCapsuleWithDetailsAsync(timeCapsule.Id);
|
|
|
|
return ApiResponse<TimeCapsuleResponseDto>.SuccessResult(capsuleResponse, "时间胶囊创建成功");
|
|
}
|
|
|
|
public async Task<ApiResponse<PagedResponse<TimeCapsuleResponseDto>>> GetTimeCapsulesAsync(int userId, TimeCapsuleListQueryDto queryDto)
|
|
{
|
|
var query = _context.TimeCapsules
|
|
.Where(tc => tc.UserId == userId)
|
|
.Include(tc => tc.User)
|
|
.Include(tc => tc.SentMail)
|
|
.AsQueryable();
|
|
|
|
// 应用筛选条件
|
|
if (queryDto.Status.HasValue)
|
|
{
|
|
query = query.Where(tc => tc.Status == queryDto.Status.Value);
|
|
}
|
|
|
|
if (queryDto.Type.HasValue)
|
|
{
|
|
query = query.Where(tc => tc.Type == queryDto.Type.Value);
|
|
}
|
|
|
|
if (queryDto.IncludeExpired.HasValue && !queryDto.IncludeExpired.Value)
|
|
{
|
|
query = query.Where(tc => tc.SentMail.DeliveryTime > DateTime.UtcNow);
|
|
}
|
|
|
|
// 排序
|
|
query = query.OrderByDescending(tc => tc.CreatedAt);
|
|
|
|
// 分页
|
|
var totalCount = await query.CountAsync();
|
|
var capsules = await query
|
|
.Skip((queryDto.PageIndex - 1) * queryDto.PageSize)
|
|
.Take(queryDto.PageSize)
|
|
.ToListAsync();
|
|
|
|
var capsuleDtos = capsules.Select(MapToTimeCapsuleResponseDto).ToList();
|
|
|
|
var pagedResponse = new PagedResponse<TimeCapsuleResponseDto>(
|
|
capsuleDtos, queryDto.PageIndex, queryDto.PageSize, totalCount);
|
|
|
|
return ApiResponse<PagedResponse<TimeCapsuleResponseDto>>.SuccessResult(pagedResponse);
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleResponseDto>> GetTimeCapsuleByIdAsync(int userId, int capsuleId)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.Include(tc => tc.User)
|
|
.Include(tc => tc.SentMail)
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId && tc.UserId == userId);
|
|
|
|
if (timeCapsule == null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("时间胶囊不存在");
|
|
}
|
|
|
|
var capsuleDto = MapToTimeCapsuleResponseDto(timeCapsule);
|
|
|
|
return ApiResponse<TimeCapsuleResponseDto>.SuccessResult(capsuleDto);
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleResponseDto>> UpdateTimeCapsuleAsync(int userId, int capsuleId, TimeCapsuleUpdateDto updateDto)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId && tc.UserId == userId);
|
|
|
|
if (timeCapsule == null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("时间胶囊不存在");
|
|
}
|
|
|
|
// 检查胶囊是否已开启,已开启的胶囊不能修改
|
|
if (timeCapsule.Status >= 3)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("已开启的时间胶囊不能修改");
|
|
}
|
|
|
|
// 更新胶囊信息
|
|
if (updateDto.PositionX.HasValue)
|
|
{
|
|
timeCapsule.PositionX = updateDto.PositionX.Value;
|
|
}
|
|
|
|
if (updateDto.PositionY.HasValue)
|
|
{
|
|
timeCapsule.PositionY = updateDto.PositionY.Value;
|
|
}
|
|
|
|
if (updateDto.PositionZ.HasValue)
|
|
{
|
|
timeCapsule.PositionZ = updateDto.PositionZ.Value;
|
|
}
|
|
|
|
if (updateDto.Size.HasValue)
|
|
{
|
|
timeCapsule.Size = updateDto.Size.Value;
|
|
}
|
|
|
|
if (updateDto.Color != null)
|
|
{
|
|
timeCapsule.Color = updateDto.Color;
|
|
}
|
|
|
|
if (updateDto.Opacity.HasValue)
|
|
{
|
|
timeCapsule.Opacity = updateDto.Opacity.Value;
|
|
}
|
|
|
|
if (updateDto.Rotation.HasValue)
|
|
{
|
|
timeCapsule.Rotation = updateDto.Rotation.Value;
|
|
}
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
var capsuleResponse = await GetTimeCapsuleWithDetailsAsync(timeCapsule.Id);
|
|
|
|
return ApiResponse<TimeCapsuleResponseDto>.SuccessResult(capsuleResponse, "时间胶囊更新成功");
|
|
}
|
|
|
|
public async Task<ApiResponse<bool>> DeleteTimeCapsuleAsync(int userId, int capsuleId)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId && tc.UserId == userId);
|
|
|
|
if (timeCapsule == null)
|
|
{
|
|
return ApiResponse<bool>.ErrorResult("时间胶囊不存在");
|
|
}
|
|
|
|
// 检查胶囊是否已开启,已开启的胶囊不能删除
|
|
if (timeCapsule.Status >= 3)
|
|
{
|
|
return ApiResponse<bool>.ErrorResult("已开启的时间胶囊不能删除");
|
|
}
|
|
|
|
// 删除时间胶囊
|
|
_context.TimeCapsules.Remove(timeCapsule);
|
|
await _context.SaveChangesAsync();
|
|
|
|
return ApiResponse<bool>.SuccessResult(true, "时间胶囊删除成功");
|
|
}
|
|
|
|
public async Task<ApiResponse<PagedResponse<TimeCapsuleResponseDto>>> GetPublicTimeCapsulesAsync(TimeCapsuleListQueryDto queryDto)
|
|
{
|
|
var query = _context.TimeCapsules
|
|
.Where(tc => tc.SentMail.RecipientType == 2) // 公开时间胶囊
|
|
.Include(tc => tc.User)
|
|
.Include(tc => tc.SentMail)
|
|
.AsQueryable();
|
|
|
|
// 应用筛选条件
|
|
if (queryDto.Status.HasValue)
|
|
{
|
|
query = query.Where(tc => tc.Status == queryDto.Status.Value);
|
|
}
|
|
|
|
if (queryDto.Type.HasValue)
|
|
{
|
|
query = query.Where(tc => tc.Type == queryDto.Type.Value);
|
|
}
|
|
|
|
if (queryDto.IncludeExpired.HasValue && !queryDto.IncludeExpired.Value)
|
|
{
|
|
query = query.Where(tc => tc.SentMail.DeliveryTime > DateTime.UtcNow);
|
|
}
|
|
|
|
// 排序
|
|
query = query.OrderByDescending(tc => tc.CreatedAt);
|
|
|
|
// 分页
|
|
var totalCount = await query.CountAsync();
|
|
var capsules = await query
|
|
.Skip((queryDto.PageIndex - 1) * queryDto.PageSize)
|
|
.Take(queryDto.PageSize)
|
|
.ToListAsync();
|
|
|
|
var capsuleDtos = capsules.Select(MapToTimeCapsuleResponseDto).ToList();
|
|
|
|
var pagedResponse = new PagedResponse<TimeCapsuleResponseDto>(
|
|
capsuleDtos, queryDto.PageIndex, queryDto.PageSize, totalCount);
|
|
|
|
return ApiResponse<PagedResponse<TimeCapsuleResponseDto>>.SuccessResult(pagedResponse);
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleResponseDto>> ClaimPublicCapsuleAsync(int userId, int capsuleId)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.Include(tc => tc.SentMail)
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId && tc.SentMail.RecipientType == 2);
|
|
|
|
if (timeCapsule == null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("时间胶囊不存在或不是公开胶囊");
|
|
}
|
|
|
|
// 检查胶囊是否已开启
|
|
if (timeCapsule.Status >= 3)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("时间胶囊已开启");
|
|
}
|
|
|
|
// 检查是否已认领
|
|
var existingReceivedMail = await _context.ReceivedMails
|
|
.FirstOrDefaultAsync(rm => rm.SentMailId == timeCapsule.SentMailId && rm.RecipientId == userId);
|
|
|
|
if (existingReceivedMail != null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("您已认领此时间胶囊");
|
|
}
|
|
|
|
// 创建接收邮件记录
|
|
var receivedMail = new ReceivedMail
|
|
{
|
|
SentMailId = timeCapsule.SentMailId,
|
|
RecipientId = userId,
|
|
ReceivedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_context.ReceivedMails.Add(receivedMail);
|
|
await _context.SaveChangesAsync();
|
|
|
|
var capsuleResponse = await GetTimeCapsuleWithDetailsAsync(timeCapsule.Id);
|
|
|
|
return ApiResponse<TimeCapsuleResponseDto>.SuccessResult(capsuleResponse, "时间胶囊认领成功");
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleViewResponseDto>> GetTimeCapsuleViewAsync(int userId)
|
|
{
|
|
// 获取用户的所有时间胶囊
|
|
var capsules = await _context.TimeCapsules
|
|
.Where(tc => tc.UserId == userId)
|
|
.Include(tc => tc.SentMail)
|
|
.ToListAsync();
|
|
|
|
// 转换为视图DTO
|
|
var capsuleViews = capsules.Select(capsule =>
|
|
{
|
|
var totalDays = (capsule.SentMail.DeliveryTime - capsule.SentMail.SentAt).TotalDays;
|
|
var elapsedDays = (DateTime.UtcNow - capsule.SentMail.SentAt).TotalDays;
|
|
var progress = totalDays > 0 ? Math.Min(1, elapsedDays / totalDays) : 0;
|
|
|
|
return new TimeCapsuleViewDto
|
|
{
|
|
CapsuleId = capsule.Id,
|
|
MailId = capsule.SentMailId,
|
|
Title = capsule.SentMail.Title,
|
|
SendTime = capsule.SentMail.SentAt,
|
|
DeliveryTime = capsule.SentMail.DeliveryTime,
|
|
Progress = progress,
|
|
Position = new TimeCapsulePosition
|
|
{
|
|
X = capsule.PositionX,
|
|
Y = capsule.PositionY,
|
|
Z = capsule.PositionZ
|
|
},
|
|
Style = capsule.Color ?? "#FFFFFF",
|
|
GlowIntensity = capsule.Status == 1 ? 0.8 : 0.3 // 漂浮中的胶囊发光更亮
|
|
};
|
|
}).ToList();
|
|
|
|
// 获取用户偏好设置(如果有)
|
|
var user = await _context.Users.FindAsync(userId);
|
|
var scene = user?.PreferredScene ?? "SPACE";
|
|
var background = user?.PreferredBackground ?? "default";
|
|
|
|
var viewResponse = new TimeCapsuleViewResponseDto
|
|
{
|
|
Capsules = capsuleViews,
|
|
Scene = scene,
|
|
Background = background
|
|
};
|
|
|
|
return ApiResponse<TimeCapsuleViewResponseDto>.SuccessResult(viewResponse);
|
|
}
|
|
|
|
public async Task<ApiResponse<TimeCapsuleResponseDto>> UpdateTimeCapsuleStyleAsync(int userId, int capsuleId, TimeCapsuleStyleUpdateDto updateDto)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId && tc.UserId == userId);
|
|
|
|
if (timeCapsule == null)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("时间胶囊不存在");
|
|
}
|
|
|
|
// 检查胶囊是否已开启,已开启的胶囊不能修改
|
|
if (timeCapsule.Status >= 3)
|
|
{
|
|
return ApiResponse<TimeCapsuleResponseDto>.ErrorResult("已开启的时间胶囊不能修改");
|
|
}
|
|
|
|
// 更新胶囊样式
|
|
timeCapsule.Color = updateDto.Style;
|
|
|
|
if (updateDto.GlowIntensity.HasValue)
|
|
{
|
|
// 将发光强度转换为透明度(反向关系)
|
|
timeCapsule.Opacity = 1.0 - (updateDto.GlowIntensity.Value * 0.5);
|
|
}
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
var capsuleResponse = await GetTimeCapsuleWithDetailsAsync(timeCapsule.Id);
|
|
|
|
return ApiResponse<TimeCapsuleResponseDto>.SuccessResult(capsuleResponse, "时间胶囊样式更新成功");
|
|
}
|
|
|
|
private async Task<TimeCapsuleResponseDto> GetTimeCapsuleWithDetailsAsync(int capsuleId)
|
|
{
|
|
var timeCapsule = await _context.TimeCapsules
|
|
.Include(tc => tc.User)
|
|
.Include(tc => tc.SentMail)
|
|
.FirstOrDefaultAsync(tc => tc.Id == capsuleId);
|
|
|
|
return MapToTimeCapsuleResponseDto(timeCapsule!);
|
|
}
|
|
|
|
private static TimeCapsuleResponseDto MapToTimeCapsuleResponseDto(TimeCapsule timeCapsule)
|
|
{
|
|
var daysUntilDelivery = (int)(timeCapsule.SentMail.DeliveryTime - DateTime.UtcNow).TotalDays;
|
|
var distanceFromNow = CalculateDistanceFromNow(daysUntilDelivery);
|
|
|
|
return new TimeCapsuleResponseDto
|
|
{
|
|
Id = timeCapsule.Id,
|
|
UserId = timeCapsule.UserId,
|
|
SentMailId = timeCapsule.SentMailId,
|
|
MailTitle = timeCapsule.SentMail.Title,
|
|
PositionX = timeCapsule.PositionX,
|
|
PositionY = timeCapsule.PositionY,
|
|
PositionZ = timeCapsule.PositionZ,
|
|
Size = timeCapsule.Size,
|
|
Color = timeCapsule.Color,
|
|
Opacity = timeCapsule.Opacity,
|
|
Rotation = timeCapsule.Rotation,
|
|
Status = timeCapsule.Status,
|
|
StatusText = GetStatusText(timeCapsule.Status),
|
|
Type = timeCapsule.Type,
|
|
TypeText = GetTypeText(timeCapsule.Type),
|
|
CreatedAt = timeCapsule.CreatedAt,
|
|
DeliveryTime = timeCapsule.SentMail.DeliveryTime,
|
|
DaysUntilDelivery = daysUntilDelivery,
|
|
DistanceFromNow = distanceFromNow
|
|
};
|
|
}
|
|
|
|
private static string GetStatusText(int status)
|
|
{
|
|
return status switch
|
|
{
|
|
0 => "未激活",
|
|
1 => "漂浮中",
|
|
2 => "即将到达",
|
|
3 => "已开启",
|
|
_ => "未知"
|
|
};
|
|
}
|
|
|
|
private static string GetTypeText(int type)
|
|
{
|
|
return type switch
|
|
{
|
|
0 => "普通",
|
|
1 => "特殊",
|
|
2 => "限时",
|
|
_ => "未知"
|
|
};
|
|
}
|
|
|
|
private static double CalculateDistanceFromNow(int daysUntilDelivery)
|
|
{
|
|
// 简单的距离计算,可以根据需要调整
|
|
// 距离"现在"越远,距离值越大
|
|
return Math.Max(1, daysUntilDelivery / 30.0); // 以月为单位
|
|
}
|
|
}
|
|
} |