using YD_Event.Application.Event.Dtos; using YD_Event.Core.Entities; using YD_Event.Core.Enum; using AppUserEntity = YD_Event.Core.Entities.AppUser; using SysUserEntity = YD_Event.Core.Entities.SysUser; using MerchantEntity = YD_Event.Core.Entities.Merchant; namespace YD_Event.Application.Event; /// /// 参赛记录管理 /// public class EventRecordService : BaseService, ITransient { private static readonly string[] ChineseNumbers = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" }; /// /// 将数字名次转换为汉字形式(与成绩与证书页面保持一致) /// private static string ConvertRankToChinese(int rank) { if (rank <= 0) return string.Empty; if (rank <= 10) return $"第{ChineseNumbers[rank]}名"; if (rank < 20) return $"第十{ChineseNumbers[rank % 10]}名"; if (rank % 10 == 0) return $"第{ChineseNumbers[rank / 10]}十名"; return $"第{ChineseNumbers[rank / 10]}十{ChineseNumbers[rank % 10]}名"; } private readonly ISqlSugarRepository _registrationRep; private readonly ISqlSugarRepository _eventRep; private readonly ISqlSugarRepository _certificateRep; private readonly ISqlSugarRepository _appUserRep; private readonly ISqlSugarRepository _sysUserRep; private readonly ISqlSugarRepository _merchantRep; private readonly ISqlSugarRepository _registrationItemRep; private readonly ISqlSugarRepository _resultRep; private readonly ISqlSugarRepository _registrationPersonRep; private readonly ISqlSugarRepository _eventProjectRep; private readonly ISqlSugarRepository _projectRep; public EventRecordService(ISqlSugarRepository registrationRep, ISqlSugarRepository eventRep, ISqlSugarRepository certificateRep, ISqlSugarRepository appUserRep, ISqlSugarRepository sysUserRep, ISqlSugarRepository merchantRep, ISqlSugarRepository registrationItemRep, ISqlSugarRepository resultRep, ISqlSugarRepository registrationPersonRep, ISqlSugarRepository eventProjectRep, ISqlSugarRepository projectRep) : base(registrationRep) { _registrationRep = registrationRep; _eventRep = eventRep; _certificateRep = certificateRep; _appUserRep = appUserRep; _sysUserRep = sysUserRep; _merchantRep = merchantRep; _registrationItemRep = registrationItemRep; _resultRep = resultRep; _registrationPersonRep = registrationPersonRep; _eventProjectRep = eventProjectRep; _projectRep = projectRep; } /// /// 分页查询参赛记录 /// [HttpGet("page")] public async Task> Page([FromQuery] EventRecordPageInput input) { // 参数验证 ValidateInput(input); // 第一步:查询用户报名过的所有赛事(去重,按赛事分组) var eventsQuery = _registrationRep.AsQueryable() .LeftJoin((r, e) => r.EventId == e.Id) .LeftJoin((r, e, u) => r.CreatedUserId == u.Id) .LeftJoin((r, e, u, s) => r.CreatedUserId == s.Id) .LeftJoin((r, e, u, s, m) => r.CreatedUserId == m.CreatedUserId) .WhereIF(!string.IsNullOrWhiteSpace(input.EventName), (r, e, u, s, m) => e.EventName.Contains(input.EventName)) .WhereIF(input.StartTime.HasValue, (r, e, u, s, m) => e.MatchStartTime >= input.StartTime) .WhereIF(input.EndTime.HasValue, (r, e, u, s, m) => e.MatchStartTime <= input.EndTime) .WhereIF(input.PaymentStatus.HasValue, (r, e, u, s, m) => r.PaymentStatus == input.PaymentStatus) // Filter by User ID (AppUser, SysUser, or Merchant) .WhereIF(input.AppUserId.HasValue, (r, e, u, s, m) => u.Id == input.AppUserId) .WhereIF(input.SysUserId.HasValue, (r, e, u, s, m) => s.Id == input.SysUserId) .WhereIF(input.MerchantId.HasValue, (r, e, u, s, m) => m.CreatedUserId == input.MerchantId) .OrderByDescending((r, e, u, s, m) => e.CreatedTime) .Select((r, e, u, s, m) => new { RegistrationId = r.Id, EventId = e.Id, EventName = e.EventName, EventType = e.EventType.ToString(), StartTime = e.MatchStartTime, EndTime = e.MatchEndTime, PaymentStatus = r.PaymentStatus, ContactName = r.ContactName, ContactPhone = r.ContactPhone, TeamName = r.TeamName, CreatedTime = r.CreatedTime, EventCreatedTime = e.CreatedTime }); var allEventRecords = await eventsQuery.ToListAsync(); // 第二步:按赛事分组并聚合 var groupedEvents = allEventRecords .GroupBy(x => x.EventId) .Select(g => { // 获取该赛事最早的报名记录作为主记录 var firstRecord = g.OrderBy(x => x.CreatedTime).First(); // 收集该赛事的所有报名记录ID(去重) var registrationIds = g.Select(x => x.RegistrationId).Distinct().ToList(); return new EventRecordOutput { // 用赛事ID作为主要ID(避免分页问题) Id = firstRecord.EventId, EventName = firstRecord.EventName, EventType = firstRecord.EventType, StartTime = firstRecord.StartTime, EndTime = firstRecord.EndTime, PaymentStatus = firstRecord.PaymentStatus, EventId = firstRecord.EventId, ContactName = firstRecord.ContactName, ContactPhone = firstRecord.ContactPhone, TeamName = firstRecord.TeamName, RegistrationIds = registrationIds, // 保存所有报名ID用于查询证书 // 保存赛事创建时间用于排序 EventCreatedTime = g.First().EventCreatedTime }; }) .OrderByDescending(x => x.EventCreatedTime) .ToList(); // 第三步:手动分页 var pageIndex = input.PageNo; var pageSize = input.PageSize; var total = groupedEvents.Count; var pages = (int)Math.Ceiling((double)total / pageSize); var pagedEvents = groupedEvents .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .ToList(); // 第四步:获取所有需要的报名记录ID(包括所有页面的,避免数据不完整) var allRegistrationIds = groupedEvents.SelectMany(x => x.RegistrationIds).Distinct().ToList(); // 第五步:获取所有证书 var certificates = await _certificateRep.GetListAsync(x => allRegistrationIds.Contains(x.RegistrationId) && x.CertificateStatus == 2); // 按赛事ID和报名ID分组证书 var certsByRegistration = certificates.GroupBy(x => x.RegistrationId).ToDictionary(g => g.Key, g => g.ToList()); // 第六步:获取所有相关数据用于补充证书信息 var allCertIds = certificates.Select(x => x.Id).Distinct().ToList(); var registrationItems = await _registrationItemRep.GetListAsync(x => allRegistrationIds.Contains(x.RegistrationId)); var registrationItemDict = registrationItems.GroupBy(x => x.RegistrationId).ToDictionary(g => g.Key, g => g.ToList()); var registrationPersons = await _registrationPersonRep.GetListAsync(x => allRegistrationIds.Contains(x.RegistrationId)); var registrationPersonDict = registrationPersons.ToDictionary(x => x.Id, x => x); var results = await _resultRep.GetListAsync(x => allRegistrationIds.Contains(x.RegistrationId)); var resultDict = results.GroupBy(x => x.RegistrationPersonId).ToDictionary(g => g.Key, g => g.ToList()); var allEventProjectIds = registrationItems.Select(x => x.ProjectId).Distinct().ToList(); var eventProjects = await _eventProjectRep.GetListAsync(x => allEventProjectIds.Contains(x.Id)); var allProjectCoreIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList(); var projects = await _projectRep.GetListAsync(x => allProjectCoreIds.Contains(x.Id)); var eventProjectDict = eventProjects.ToDictionary(x => x.Id, x => x.ProjectId); var projectDict = projects.ToDictionary(x => x.Id, x => x); // 第七步:为每个赛事填充证书列表 foreach (var eventRecord in pagedEvents) { // 获取该赛事所有报名记录的证书 var allCerts = new List(); foreach (var regId in eventRecord.RegistrationIds) { if (certsByRegistration.TryGetValue(regId, out var certs)) { allCerts.AddRange(certs); } } // 构造证书输出列表 foreach (var cert in allCerts) { var certOutput = new EventCertificateItemOutput { Id = cert.Id, ParticipantName = cert.ParticipantName ?? string.Empty, ProjectName = string.Empty, GroupName = cert.GroupName ?? string.Empty, Role = "运动员", CertificateUrl = cert.CertificateUrl?.Trim() ?? string.Empty, CertificateNo = cert.CertificateNo ?? string.Empty, CertificateType = cert.CertificateType, IssuedTime = cert.IssuedTime ?? DateTime.MinValue }; // 获取项目名称 if (cert.ProjectId > 0) { // 查找对应的报名项目 if (registrationItemDict.TryGetValue(cert.RegistrationId, out var items)) { var item = items.FirstOrDefault(i => i.ProjectId == cert.ProjectId); if (item != null) { certOutput.ProjectName = item.ProjectName ?? string.Empty; // 查找项目信息 if (eventProjectDict.TryGetValue(item.ProjectId, out var coreProjectId) && projectDict.TryGetValue(coreProjectId, out var coreProject)) { certOutput.ProjectName = coreProject.Name ?? item.ProjectName ?? string.Empty; } } } } // 获取角色信息 if (cert.ParticipationRecordId > 0 && registrationPersonDict.TryGetValue(cert.ParticipationRecordId, out var person)) { certOutput.Role = person.PersonType switch { PersonType.Coach => "教练", PersonType.Leader => "领队", _ => "运动员" }; } // 获取成绩和名次 if (cert.ResultId > 0) { var result = results.FirstOrDefault(r => r.Id == cert.ResultId); if (result != null) { certOutput.Score = result.Score; certOutput.Rank = result.Rank; } } else if (cert.ParticipationRecordId > 0 && resultDict.TryGetValue(cert.ParticipationRecordId, out var personResults)) { var result = personResults.FirstOrDefault(); if (result != null) { certOutput.Score = result.Score; certOutput.Rank = result.Rank; } } eventRecord.Items.Add(certOutput); } } // 第八步:构造分页结果 var pageResult = new PageResult { Total = total, PageNo = pageIndex, PageSize = pageSize, Pages = pages, Rows = pagedEvents }; return pageResult; } /// /// 验证输入参数 /// private void ValidateInput(EventRecordPageInput input) { // 检查是否同时提供了多个用户ID类型 var userTypeCount = 0; if (input.AppUserId.HasValue) userTypeCount++; if (input.SysUserId.HasValue) userTypeCount++; if (input.MerchantId.HasValue) userTypeCount++; if (userTypeCount > 1) { throw Oops.Bah("只能提供一种用户类型ID参数(AppUserId、SysUserId或MerchantId)"); } // 验证用户ID有效性 if (input.AppUserId.HasValue && input.AppUserId.Value <= 0) { throw Oops.Bah("普通用户ID无效"); } if (input.SysUserId.HasValue && input.SysUserId.Value <= 0) { throw Oops.Bah("系统用户ID无效"); } if (input.MerchantId.HasValue && input.MerchantId.Value <= 0) { throw Oops.Bah("商户ID无效"); } } /// /// 获取证书列表 /// [HttpGet("certificates")] public async Task> GetCertificates([FromQuery] List registrationIds) { var certs = await _certificateRep.AsQueryable() .Where(c => registrationIds.Contains(c.RegistrationId)) .ToListAsync(); return certs.Select(c => new CertificateOutput { Id = c.Id, Name = c.ParticipantName, AwardLevel = GetAwardLevelName(c.AwardLevel), CertificateType = GetCertificateTypeName(c.CertificateType), ImageUrl = c.CertificateUrl }).ToList(); } private string GetAwardLevelName(int level) { return level switch { 1 => "特等奖", 2 => "一等奖", 3 => "二等奖", 4 => "三等奖", 5 => "优秀奖", _ => "未知" }; } private string GetCertificateTypeName(int type) { return type switch { 1 => "冠军证书", 2 => "亚军证书", 3 => "季军证书", 4 => "优胜证书", 5 => "参与证书", _ => "未知" }; } }