diff --git a/YD_Event.Application/Event/Dtos/ArrangementDtos.cs b/YD_Event.Application/Event/Dtos/ArrangementDtos.cs index 16a8e4f..5a3ea17 100644 --- a/YD_Event.Application/Event/Dtos/ArrangementDtos.cs +++ b/YD_Event.Application/Event/Dtos/ArrangementDtos.cs @@ -153,4 +153,14 @@ public class ArrangementPreviewOutput /// 场地索引 /// public int VenueIndex { get; set; } + + /// + /// 项目总时长(秒) + /// + public int ProjectTotalDurationSeconds { get; set; } + + /// + /// 项目总时长(格式化字符串) + /// + public string ProjectTotalDuration { get; set; } } diff --git a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs index c636862..e0c9c3a 100644 --- a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs +++ b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs @@ -753,7 +753,7 @@ public class RegistrationItemDTO public string TeamName { get; set; } /// - /// 综合状态 (0-待付款, 1-已支付, 2-已取消, 3-已退款, 4-已完成) + /// 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消 /// public int Status { get; set; } diff --git a/YD_Event.Application/Event/EventArrangementService.cs b/YD_Event.Application/Event/EventArrangementService.cs index c1624e1..1d37435 100644 --- a/YD_Event.Application/Event/EventArrangementService.cs +++ b/YD_Event.Application/Event/EventArrangementService.cs @@ -38,6 +38,47 @@ public class EventArrangementService : BaseService 0 || seconds > 0) + { + result += $"{minutes}'"; + if (seconds > 0) + { + var paddedSeconds = seconds.ToString().PadLeft(2, '0'); + result += $"{paddedSeconds}\""; + } + } + return result; + } + } + /// /// 获取编排项目列表 /// @@ -196,12 +237,41 @@ public class EventArrangementService : BaseService> Preview(long eventId) { - // 1. 获取项目(按顺序) + // 1. 获取项目列表和统计数据 var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId); var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList(); var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id)); projects = projects.OrderBy(x => x.SortIndex).ToList(); - + var groups = await _groupRepository.GetListAsync(x => projectIds.Contains(x.ProjectId)); + + // 统计各组别报名人数 + var counts = await _personRepository.AsQueryable() + .InnerJoin((p, r) => p.RegistrationId == r.Id) + .Where((p, r) => r.EventId == eventId + && r.PaymentStatus != 4 + && !p.DeleteMark + && p.PersonType == PersonType.Athlete) + .GroupBy((p, r) => new { p.ProjectId, p.GroupName }) + .Select((p, r) => new { p.ProjectId, p.GroupName, Count = SqlFunc.AggregateCount(p.Id) }) + .ToListAsync(); + + // 获取团队数 + var personWithTeam = await _personRepository.AsQueryable() + .InnerJoin((p, r) => p.RegistrationId == r.Id) + .Where((p, r) => r.EventId == eventId + && r.PaymentStatus != 4 + && !p.DeleteMark + && p.PersonType == PersonType.Athlete + && r.TeamName != null) + .Select((p, r) => new { p.ProjectId, p.GroupName, r.TeamName }) + .ToListAsync(); + + var teamCounts = personWithTeam + .GroupBy(x => new { x.ProjectId, x.GroupName, x.TeamName }) + .GroupBy(g => new { g.Key.ProjectId, g.Key.GroupName }) + .Select(g => new { g.Key.ProjectId, g.Key.GroupName, Count = g.Count() }) + .ToList(); + var result = new List(); // 2. 生成排期 @@ -212,8 +282,7 @@ public class EventArrangementService : BaseService 0 ? proj.VenueCount : 1; - // 获取参赛人员(排序:组别 -> ID) - // 查询条件:不是取消状态的报名,并且只统计运动员 + // 获取参赛人员 var persons = await _personRepository.AsQueryable() .InnerJoin((p, r) => p.RegistrationId == r.Id) .Where((p, r) => p.ProjectId == eventProj.Id @@ -230,6 +299,39 @@ public class EventArrangementService : BaseService g.ProjectId == proj.Id).ToList(); + foreach (var group in projGroups) + { + var countObj = counts.FirstOrDefault(c => c.ProjectId == eventProj.Id && c.GroupName == group.GroupName); + totalParticipants += countObj?.Count ?? 0; + } + + int totalTeams = 0; + if (proj.IsTeamProject()) + { + totalTeams = teamCounts + .Where(tc => tc.ProjectId == eventProj.Id) + .Sum(tc => tc.Count); + } + + int projectTotalDurationSeconds; + if (proj.IsTeamProject()) + { + int teamCount = totalTeams > 0 ? totalTeams : 1; + int rounds = (int)Math.Ceiling((double)teamCount / venueCount); + projectTotalDurationSeconds = rounds * proj.DurationSeconds; + } + else + { + int participantCount = totalParticipants > 0 ? totalParticipants : 1; + int rounds = (int)Math.Ceiling((double)participantCount / venueCount); + projectTotalDurationSeconds = rounds * proj.DurationSeconds; + } + + string projectTotalDuration = FormatDurationSymbol(projectTotalDurationSeconds); + // 分组逻辑 int currentRound = 1; int currentVenue = 1; @@ -245,7 +347,9 @@ public class EventArrangementService : BaseService 0 && i - 1 >= 0) + { + int mergeEndRow = (i - 1) + 3; + if (mergeEndRow > projectStartRow) + { + var range = Worksheet.Cells[projectStartRow, 1, mergeEndRow, 1]; + range.Merge = true; + // 设置时间列居中对齐 + for (int r = projectStartRow; r <= mergeEndRow; r++) + { + Worksheet.Cells[r, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; + Worksheet.Cells[r, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; + } + } + } + + currentProjectName = item.ProjectName; + projectStartRow = rowIndex; + + // 设置项目总时长 + Worksheet.Cells[rowIndex, 1].Value = item.ProjectTotalDuration; + } + else + { + // 同一项目的其他行不设置时间值(合并后会自动应用) + } + Worksheet.Cells[rowIndex, 2].Value = item.ProjectName; Worksheet.Cells[rowIndex, 3].Value = item.GroupName; Worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? ""; @@ -318,6 +457,23 @@ public class EventArrangementService : BaseService 0 && _data.Count > 0) + { + int mergeEndRow = (_data.Count - 1) + 3; + if (mergeEndRow > projectStartRow) + { + var range = Worksheet.Cells[projectStartRow, 1, mergeEndRow, 1]; + range.Merge = true; + // 设置时间列居中对齐 + for (int r = projectStartRow; r <= mergeEndRow; r++) + { + Worksheet.Cells[r, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; + Worksheet.Cells[r, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center; + } + } + } + // 设置列宽 var widths = new double[] { 12, 18, 15, 25, 15, 8, 8 }; SetColumnWidths(widths); diff --git a/YD_Event.Application/Event/EventRegistrationService.cs b/YD_Event.Application/Event/EventRegistrationService.cs index 84bdb08..784023e 100644 --- a/YD_Event.Application/Event/EventRegistrationService.cs +++ b/YD_Event.Application/Event/EventRegistrationService.cs @@ -265,11 +265,11 @@ public class EventRegistrationService : BaseService, ITransie }; dto.TeamLeaderInfo = allLeaders.Any() - ? string.Join(",", allLeaders.Select(l => $"{l.Name}({l.Mobile})/{getGenderText(l.Gender)}")) + ? string.Join(",", allLeaders.Select(l => $"{l.Name}/{getGenderText(l.Gender)}/{l.Mobile}")) : null; dto.CoachInfo = allCoaches.Any() - ? string.Join(",", allCoaches.Select(c => $"{c.Name}({c.Mobile})/{getGenderText(c.Gender)}")) + ? string.Join(",", allCoaches.Select(c => $"{c.Name}/{getGenderText(c.Gender)}/{c.Mobile}")) : null; } } diff --git a/YD_Event.Application/Event/UnifiedRegistrationService.cs b/YD_Event.Application/Event/UnifiedRegistrationService.cs index 440fe13..6a56f0b 100644 --- a/YD_Event.Application/Event/UnifiedRegistrationService.cs +++ b/YD_Event.Application/Event/UnifiedRegistrationService.cs @@ -1134,8 +1134,9 @@ public class UnifiedRegistrationService : ITransient var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => x.EventId == input.EventId && !x.DeleteMark); // 先获取所有报名信息,供后续检查使用 + // 只统计已支付的报名记录(PaymentStatus == 1),避免未支付/已取消的报名占用名额 var eventRegistrations = await _registrationRepository.GetListAsync(x => - x.EventId == input.EventId && x.PaymentStatus != 4 && !x.DeleteMark); + x.EventId == input.EventId && x.PaymentStatus == 1 && !x.DeleteMark); var eventRegistrationIds = eventRegistrations.Select(r => r.Id).ToList(); var registrationPersons = await _registrationPersonRepository.GetListAsync(x => eventRegistrationIds.Contains(x.RegistrationId) && !x.DeleteMark); diff --git a/YD_Event.Application/Event/UserEventRecordService.cs b/YD_Event.Application/Event/UserEventRecordService.cs index 22d06d5..4e62ec9 100644 --- a/YD_Event.Application/Event/UserEventRecordService.cs +++ b/YD_Event.Application/Event/UserEventRecordService.cs @@ -112,21 +112,6 @@ public class UserEventRecordService : IDynamicApiController, ITransient .ToPagedListAsync(input); var resultItems = list.Rows.Select(x => { - // 计算综合状态 - int statusValue = 0; - if (x.PaymentStatus == 4) - statusValue = 2; // 已取消 - else if (x.PaymentStatus == 0) - statusValue = 0; // 待付款 - else if (x.PaymentStatus == 1 && string.IsNullOrEmpty(x.MaterialUrl)) - statusValue = 1; // 已支付 - else if (x.PaymentStatus == 1 && !string.IsNullOrEmpty(x.MaterialUrl)) - statusValue = 4; // 已完成/已报名 - else if (x.PaymentStatus == 2) - statusValue = 1; // 审核拒绝 - else if (x.PaymentStatus == 3) - statusValue = 3; // 已退款 - return new RegistrationItemDTO { RegistrationId = x.Id, @@ -141,7 +126,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient MatchStartTime = x.MatchStartTime, MatchEndTime = x.MatchEndTime, TeamName = x.TeamName, - Status = statusValue, + Status = x.PaymentStatus, CreateTime = x.CreatedTime, UpdateTime = x.UpdatedTime, PayStatus = x.PaymentStatus, diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 997abea..8ed6b23 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -4167,6 +4167,16 @@ 场地索引 + + + 项目总时长(秒) + + + + + 项目总时长(格式化字符串) + + 赛事查询输入 @@ -6969,7 +6979,7 @@ - 综合状态 (0-待付款, 1-已支付, 2-已取消, 3-已退款, 4-已完成) + 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消