YD_Event.Admin/YD_Event.Application/Client/CheckinScheduleService.cs
ltx 25830581d2 feat(api): 完善小程序赛事角色与秩序册检录接口
新增成绩查询、裁判认证及检录员账号管理接口,并统一小程序角色登录与个人中心数据。

检录任务绑定赛事秩序册场次,按项目、组别、场地和场次顺序执行;支持最多三名检录员、分配检录轮次及前序检录校验。

补充检录任务、检录记录、裁判申请实体及四份数据库迁移,包含表字段备注、秩序册绑定和检录序号。
2026-08-07 14:59:15 +08:00

120 lines
5.2 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.Client.Dtos;
using YD_Event.Application.Event;
namespace YD_Event.Application.Client;
/// <summary>从秩序册实时生成检录项目、组别和列对象。</summary>
public class CheckinScheduleService : ITransient
{
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
private readonly EventArrangementService _arrangementService;
public CheckinScheduleService(
ISqlSugarRepository<EventInfo> eventRepository,
ISqlSugarRepository<EventRegistrationPerson> personRepository,
EventArrangementService arrangementService)
{
_eventRepository = eventRepository;
_personRepository = personRepository;
_arrangementService = arrangementService;
}
public async Task<CheckinEventOptionsDto> GetOptionsAsync(long eventId)
{
var evt = await _eventRepository.GetFirstAsync(x =>
x.Id == eventId && !x.DeleteMark && x.Status == AvailabilityStatus.Enable);
if (evt == null) throw Oops.Bah("赛事不存在或已停用");
// Preview 的每一行就是秩序册中的一列:个人项目一人,团队项目可以多人。
var rows = await _arrangementService.Preview(eventId);
if (rows.Count == 0) throw Oops.Bah("当前赛事尚未生成有效秩序册,不能创建检录任务");
var personIds = rows.SelectMany(x => x.RegistrationPersonIds).Distinct().ToList();
var persons = personIds.Count == 0
? new List<EventRegistrationPerson>()
: await _personRepository.AsQueryable()
.Where(x => personIds.Contains(x.Id) && !x.DeleteMark && x.PersonType == PersonType.Athlete)
.ToListAsync();
var personMap = persons.ToDictionary(x => x.Id);
var units = rows.Select((row, index) => new CheckinOrderBookUnitDto
{
UnitKey = BuildUnitKey(row.EventProjectId, row.RegistrationItemId),
Order = index + 1,
SessionIndex = row.SessionIndex,
VenueIndex = row.VenueIndex,
VenueName = $"{row.VenueIndex}号场地",
EventProjectId = row.EventProjectId,
ProjectId = row.ProjectId,
ProjectName = row.ProjectName,
GroupId = row.EventProjectGroupId,
GroupName = row.GroupName,
RegistrationItemId = row.RegistrationItemId,
TeamName = row.TeamName ?? string.Empty,
UnitName = row.UnitName ?? string.Empty,
RegistrationPersonIds = row.RegistrationPersonIds.Distinct().ToList(),
Athletes = row.RegistrationPersonIds.Distinct()
.Where(personMap.ContainsKey)
.Select(personId =>
{
var person = personMap[personId];
return new CheckinAthleteDto
{
Id = person.Id,
UserId = person.UserId,
BibNo = FormatBibNo(person.Id),
Name = person.Name,
TeamName = row.TeamName ?? string.Empty
};
}).ToList()
}).ToList();
var projects = units.GroupBy(x => new { x.EventProjectId, x.ProjectId, x.ProjectName })
.Select((project, projectIndex) => new CheckinProjectOptionDto
{
EventProjectId = project.Key.EventProjectId,
ProjectId = project.Key.ProjectId,
ProjectName = project.Key.ProjectName,
Order = projectIndex + 1,
Groups = project.Where(x => x.GroupId.HasValue)
.GroupBy(x => new { Id = x.GroupId!.Value, x.GroupName })
.Select((group, groupIndex) => new CheckinGroupOptionDto
{
Id = group.Key.Id,
EventProjectId = project.Key.EventProjectId,
ProjectId = project.Key.ProjectId,
ProjectName = project.Key.ProjectName,
GroupName = group.Key.GroupName,
Order = groupIndex + 1
}).ToList()
}).ToList();
return new CheckinEventOptionsDto
{
EventId = evt.Id,
EventName = evt.EventName,
Projects = projects,
Units = units,
// 兼容旧调用方:Sessions 不再是检录对象。
Sessions = new List<CheckinSessionOptionDto>(),
Rounds = new List<CheckinRoundOptionDto>()
};
}
public static CheckinOrderBookUnitDto ResolveUnit(CheckinEventOptionsDto options, string unitKey)
{
var unit = options.Units.FirstOrDefault(x => x.UnitKey == unitKey);
return unit ?? throw Oops.Bah("所选检录对象不属于当前赛事秩序册");
}
public static string BuildUnitKey(long eventProjectId, long registrationItemId) =>
$"EP{eventProjectId}-RI{registrationItemId}";
private static string FormatBibNo(long personId)
{
var value = personId.ToString();
return value.Length > 6 ? value[^6..] : value.PadLeft(6, '0');
}
}