YD_Event.Admin/YD_Event.Application/Event/EventArrangementService.cs

185 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YD_Event.Application.Event.Dtos;
using YD_Event.Core.Entities;
using MiniExcelLibs;
using SqlSugar;
namespace YD_Event.Application.Event;
/// <summary>
/// 赛事编排服务
/// </summary>
public class EventArrangementService : BaseService<YD_Event.Core.Entities.Project>, ITransient
{
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository;
public EventArrangementService(
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
ISqlSugarRepository<ProjectGroup> groupRepository,
ISqlSugarRepository<EventRegistrationPerson> personRepository,
ISqlSugarRepository<EventRegistration> registrationRepository,
ISqlSugarRepository<ProjectType> projectTypeRepository) : base(projectRepository)
{
_projectRepository = projectRepository;
_groupRepository = groupRepository;
_personRepository = personRepository;
_registrationRepository = registrationRepository;
_projectTypeRepository = projectTypeRepository;
}
/// <summary>
/// 获取编排项目列表
/// </summary>
[DisplayName("获取编排项目列表")]
public async Task<List<ArrangementProjectListOutput>> GetList(long eventId)
{
var projects = await _projectRepository.GetListAsync(x => x.EventId == eventId);
projects = projects.OrderBy(x => x.SortIndex).ToList();
var groups = await _groupRepository.GetListAsync(x => projects.Select(p => p.Id).Contains(x.ProjectId));
// 获取项目类型信息
var typeIds = projects.Select(x => x.ProjectTypeId).Distinct().ToList();
var types = await _projectTypeRepository.GetListAsync(x => typeIds.Contains(x.Id));
// 统计各组别报名人数(仅统计已支付或审核通过的)
var counts = await _personRepository.AsQueryable()
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
.Where((p, r) => r.EventId == eventId && (r.PaymentStatus == 1 || r.RegistrationStatus == 2))
.GroupBy(p => new { p.ProjectId, p.GroupName })
.Select(p => new { p.ProjectId, p.GroupName, Count = SqlFunc.AggregateCount(p.Id) })
.ToListAsync();
var result = new List<ArrangementProjectListOutput>();
foreach (var proj in projects)
{
var type = types.FirstOrDefault(x => x.Id == proj.ProjectTypeId);
var dto = new ArrangementProjectListOutput
{
ProjectId = proj.Id,
ProjectName = proj.Name,
ProjectType = type?.Name ?? "未知类型",
DurationSeconds = proj.DurationSeconds,
VenueCount = proj.VenueCount,
SortIndex = proj.SortIndex,
Groups = new List<ArrangementGroupDto>()
};
var projGroups = groups.Where(g => g.ProjectId == proj.Id).ToList();
foreach (var group in projGroups)
{
var countObj = counts.FirstOrDefault(c => c.ProjectId == proj.Id && c.GroupName == group.GroupName);
dto.Groups.Add(new ArrangementGroupDto
{
GroupName = group.GroupName,
ParticipantCount = countObj?.Count ?? 0
});
}
// 估算总时长
int venueCount = proj.VenueCount > 0 ? proj.VenueCount : 1;
int totalParticipants = dto.Groups.Sum(g => g.ParticipantCount);
int rounds = (int)Math.Ceiling((double)totalParticipants / venueCount);
dto.TotalDurationMinutes = (rounds * proj.DurationSeconds) / 60;
result.Add(dto);
}
return result;
}
/// <summary>
/// 更新编排设置
/// </summary>
[UnitOfWork]
[DisplayName("更新编排设置")]
public async Task Update(ArrangementUpdateInput input)
{
foreach (var setting in input.Settings)
{
await _projectRepository.UpdateAsync(x => new YD_Event.Core.Entities.Project
{
VenueCount = setting.VenueCount,
SortIndex = setting.SortIndex,
DurationSeconds = setting.DurationSeconds,
DurationMinutes = setting.DurationSeconds / 60
}, x => x.Id == setting.ProjectId);
}
}
/// <summary>
/// 编排预览
/// </summary>
[DisplayName("编排预览")]
public async Task<List<ArrangementPreviewOutput>> Preview(long eventId)
{
// 1. 获取项目(按顺序)
var projects = await _projectRepository.GetListAsync(x => x.EventId == eventId);
projects = projects.OrderBy(x => x.SortIndex).ToList();
var result = new List<ArrangementPreviewOutput>();
// 2. 生成排期
foreach (var proj in projects)
{
int venueCount = proj.VenueCount > 0 ? proj.VenueCount : 1;
// 获取参赛人员(排序:组别 -> ID)
var persons = await _personRepository.AsQueryable()
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
.Where((p, r) => p.ProjectId == proj.Id && (r.PaymentStatus == 1 || r.RegistrationStatus == 2))
.OrderBy(p => p.GroupName)
.OrderBy(p => p.Id)
.Select((p, r) => new {
p.Name, p.GroupName, r.TeamName,
Duration = proj.DurationSeconds
})
.ToListAsync();
if (!persons.Any()) continue;
// 分组逻辑
int currentRound = 1;
int currentVenue = 1;
foreach (var person in persons)
{
result.Add(new ArrangementPreviewOutput
{
TimeRange = $"{proj.DurationSeconds}''",
ProjectName = proj.Name,
GroupName = person.GroupName,
TeamName = person.TeamName,
AthleteName = person.Name,
SessionIndex = currentRound,
VenueIndex = currentVenue
});
currentVenue++;
if (currentVenue > venueCount)
{
currentVenue = 1;
currentRound++;
}
}
}
return result;
}
/// <summary>
/// 导出编排
/// </summary>
[DisplayName("导出编排")]
public async Task<byte[]> Export(long eventId)
{
var data = await Preview(eventId);
using var stream = new MemoryStream();
stream.SaveAs(data);
return stream.ToArray();
}
}