diff --git a/YD_Event.Application/Certificate/CertificateTemplateService.cs b/YD_Event.Application/Certificate/CertificateTemplateService.cs
index f24dc10..a4027dd 100644
--- a/YD_Event.Application/Certificate/CertificateTemplateService.cs
+++ b/YD_Event.Application/Certificate/CertificateTemplateService.cs
@@ -16,7 +16,7 @@ namespace YD_Event.Application.Certificate;
///
/// 证书模板管理服务
///
-public class CertificateTemplateService : BaseService, ITransient
+public class CertificateTemplateService : BaseService, IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository _templateRepository;
private readonly ISqlSugarRepository _placeholderRepository;
diff --git a/YD_Event.Application/Event/EventScoreService.cs b/YD_Event.Application/Event/EventScoreService.cs
index 17c2012..d6f0a98 100644
--- a/YD_Event.Application/Event/EventScoreService.cs
+++ b/YD_Event.Application/Event/EventScoreService.cs
@@ -95,16 +95,42 @@ public class EventScoreService : BaseService, ITransient
[DisplayName("运动员成绩列表")]
public async Task> PageAthlete(ScoreQueryInput input)
{
- var pageResult = await _personRepository.AsQueryable()
+ _logger.LogInformation("开始查询运动员成绩列表,赛事ID={EventId}, 项目ID={ProjectId}, 组别={GroupName}",
+ input.EventId, input.ProjectId, input.GroupName);
+
+ var query = _personRepository.AsQueryable()
.LeftJoin((p, r) => p.RegistrationId == r.Id)
.LeftJoin((p, r, res) => p.Id == res.RegistrationPersonId)
.LeftJoin((p, r, res, c) => res.Id == c.ResultId)
- .Where((p, r, res, c) => r.EventId == input.EventId && (p.PersonType == PersonType.Athlete || p.PersonType == PersonType.User))
- .WhereIF(input.ProjectId.HasValue, p => p.ProjectId == input.ProjectId)
- .WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), p => p.GroupName == input.GroupName)
- .WhereIF(!string.IsNullOrWhiteSpace(input.Name), p => p.Name.Contains(input.Name))
- .WhereIF(!string.IsNullOrWhiteSpace(input.UnitName), (p, r) => r.TeamName.Contains(input.UnitName))
- .WhereIF(input.Gender.HasValue, p => p.Gender == input.Gender.Value)
+ .Where((p, r, res, c) => r.EventId == input.EventId && (p.PersonType == PersonType.Athlete || p.PersonType == PersonType.User));
+
+ // 应用筛选条件
+ if (input.ProjectId.HasValue)
+ {
+ query = query.Where(p => p.ProjectId == input.ProjectId.Value);
+ }
+
+ if (!string.IsNullOrWhiteSpace(input.GroupName))
+ {
+ query = query.Where(p => p.GroupName == input.GroupName);
+ }
+
+ if (!string.IsNullOrWhiteSpace(input.Name))
+ {
+ query = query.Where(p => p.Name.Contains(input.Name));
+ }
+
+ if (!string.IsNullOrWhiteSpace(input.UnitName))
+ {
+ query = query.Where((p, r) => r.TeamName.Contains(input.UnitName));
+ }
+
+ if (input.Gender.HasValue)
+ {
+ query = query.Where(p => p.Gender == input.Gender.Value);
+ }
+
+ var pageResult = await query
.Select((p, r, res, c) => new ScoreListOutput
{
Id = p.Id,
@@ -123,6 +149,7 @@ public class EventScoreService : BaseService, ITransient
item.RankText = ConvertRankToChinese(item.Rank);
}
+ _logger.LogInformation("查询运动员成绩列表完成,共{Count}条记录", pageResult.Total);
return pageResult;
}
diff --git a/YD_Event.Application/Event/UnifiedRegistrationService.cs b/YD_Event.Application/Event/UnifiedRegistrationService.cs
index 1ebff60..8cab486 100644
--- a/YD_Event.Application/Event/UnifiedRegistrationService.cs
+++ b/YD_Event.Application/Event/UnifiedRegistrationService.cs
@@ -1154,11 +1154,33 @@ public class UnifiedRegistrationService : ITransient
_logger.LogInformation("获取到赛事报名记录: {RegistrationCount},报名人员: {PersonCount},报名项目: {ItemCount}",
eventRegistrations.Count, registrationPersons.Count, allRegistrationItems.Count);
- // 检查各类型限制
+ // ==================== 报名限制检查流程 ====================
+ // 检查顺序说明:
+ // 1. 先检查团队组别容量限制 - 检查是否超过组别限报的团队数量
+ // 2. 再检查成员项目限报 - 检查队员是否超过个人/团队项目的限报数量
+ // 3. 然后检查人员项目组别重复 - 检查同一人员是否在同一项目的多个组别中重复报名
+ // 4. 再检查人员是否已报名 - 检查人员是否已在其他报名记录中报过同一项目组别
+ // 5. 最后检查项目完成人数 - 确保人数与项目的完成人数完全一致
+
+ // 检查1:团队组别容量限制
+ // 验证是否有组别超过了限报的团队数量(例如:某组别限报2队,但本次报了3队)
CheckTeamGroupCapacityLimitAsync(input, result, projectLimits, eventProjects, projects, eventProjectGroups);
+
+ // 检查2:成员项目限报
+ // 验证队员是否超过了个人项目或团队项目的限报数量(例如:某队员已报2个个人项目,限报2个,又报第3个)
await CheckMemberProjectLimitAsync(input, result, limit, eventProjects, projects, registrationPersons, allRegistrationItems);
+
+ // 检查3:人员项目组别重复
+ // 验证同一人员是否在本次报名中重复选择了同一项目的多个组别(例如:同一队员在同一项目的男子组和女子组都报了名)
CheckPersonProjectDuplicateAsync(input, result, eventProjects, projects, eventProjectGroups);
+
+ // 检查4:人员是否已在其他报名中报名
+ // 验证人员是否已在其他已支付的报名记录中报过同一项目组别(避免重复占用名额)
CheckPersonAlreadyRegisteredAsync(input, result, eventProjects, projects, eventProjectGroups, registrationPersons, allRegistrationItems, eventRegistrationIds);
+
+ // 检查5:项目完成人数验证
+ // 验证用户选择的参与人数必须与项目的"完成人数"完全一致(例如:项目要求完成3人,但只选了2人或选了4人)
+ CheckProjectCompletionAsync(input, result, eventProjects, projects, eventProjectGroups);
_logger.LogInformation("报名限制检查完成,是否存在限制: {HasLimit}, 限制详情数: {LimitCount}",
result.HasLimit, result.LimitDetails.Count);
@@ -1194,7 +1216,7 @@ public class UnifiedRegistrationService : ITransient
}
///
- /// 检查团队组别容量限制
+ /// 检查团队组别容量限制(项目组别限报设置)
///
private void CheckTeamGroupCapacityLimitAsync(
UnifiedRegistrationInput input,
@@ -1204,59 +1226,69 @@ public class UnifiedRegistrationService : ITransient
List projects,
List eventProjectGroups)
{
- var teamGroupCountDict = new Dictionary();
-
foreach (var item in input.Items)
{
if (!item.GroupId.HasValue) continue;
- var teams = GetTeamsFromItem(item);
- var teamCountForItem = teams.Count;
-
- if (teamCountForItem > 0)
- {
- if (teamGroupCountDict.ContainsKey(item.GroupId.Value))
- {
- teamGroupCountDict[item.GroupId.Value] += teamCountForItem;
- }
- else
- {
- teamGroupCountDict[item.GroupId.Value] = teamCountForItem;
- }
- }
- }
-
- if (!teamGroupCountDict.Any())
- {
- return;
- }
-
- foreach (var groupId in teamGroupCountDict.Keys)
- {
- var eventProjectGroup = eventProjectGroups.FirstOrDefault(epg => epg.Id == groupId);
+ // 获取组别信息
+ var eventProjectGroup = eventProjectGroups.FirstOrDefault(epg => epg.Id == item.GroupId.Value);
if (eventProjectGroup == null) continue;
-
+
+ // 获取赛事项目信息
var eventProject = eventProjects.FirstOrDefault(ep => ep.Id == eventProjectGroup.EventProjectId);
if (eventProject == null) continue;
-
+
+ // 获取基础项目信息
+ var project = projects.FirstOrDefault(p => p.Id == eventProject.ProjectId);
+ if (project == null) continue;
+
+ // 判断是否为团队项目
+ var isTeamProject = project.IsTeamProject();
+
+ // 获取项目限报配置
var projectLimit = projectLimits.FirstOrDefault(pl => pl.ProjectId == eventProject.Id);
if (projectLimit == null) continue;
-
- var submittedTeamCount = teamGroupCountDict[groupId];
- if (submittedTeamCount <= projectLimit.LimitCount) continue;
-
- var project = projects.FirstOrDefault(p => p.Id == eventProject.ProjectId);
- var projectName = project?.Name ?? "未知项目";
- _logger.LogWarning("组别容量超限,项目: {ProjectName},组别: {GroupName},限报: {LimitCount},提交: {SubmittedCount}",
- projectName, eventProjectGroup.GroupName, projectLimit.LimitCount, submittedTeamCount);
-
- result.HasLimit = true;
- result.LimitDetails.Add(CreateLimitDetail(
- 0,
- eventProjectGroup.GroupName ?? "未知组别",
- "ProjectGroupCapacity",
- $"项目\"{projectName}\"的组别\"{eventProjectGroup.GroupName}\"限报{projectLimit.LimitCount}队,本次提交{submittedTeamCount}队,超出限报配置"));
+ if (isTeamProject)
+ {
+ // ==================== 团队项目验证 ====================
+ // 检查该组别申报的团队数量是否超过限报配置
+ var teams = GetTeamsFromItem(item);
+ var submittedTeamCount = teams.Count;
+
+ if (submittedTeamCount > projectLimit.LimitCount)
+ {
+ _logger.LogWarning("团队项目组别容量超限,项目: {ProjectName},组别: {GroupName},限报: {LimitCount}队,提交: {SubmittedCount}队",
+ project.Name, eventProjectGroup.GroupName, projectLimit.LimitCount, submittedTeamCount);
+
+ result.HasLimit = true;
+ result.LimitDetails.Add(CreateLimitDetail(
+ 0,
+ eventProjectGroup.GroupName ?? "未知组别",
+ "ProjectGroupCapacity",
+ $"项目组别限报设置:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"限报{projectLimit.LimitCount}队,本次提交{submittedTeamCount}队,超出限报配置"));
+ }
+ }
+ else
+ {
+ // ==================== 个人项目验证 ====================
+ // 检查该组别申报的人员数量是否超过限报配置
+ var persons = GetAllPersonsFromItem(item);
+ var submittedPersonCount = persons.Count;
+
+ if (submittedPersonCount > projectLimit.LimitCount)
+ {
+ _logger.LogWarning("个人项目组别容量超限,项目: {ProjectName},组别: {GroupName},限报: {LimitCount}人,提交: {SubmittedCount}人",
+ project.Name, eventProjectGroup.GroupName, projectLimit.LimitCount, submittedPersonCount);
+
+ result.HasLimit = true;
+ result.LimitDetails.Add(CreateLimitDetail(
+ 0,
+ eventProjectGroup.GroupName ?? "未知组别",
+ "ProjectGroupCapacity",
+ $"项目组别限报设置:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"限报{projectLimit.LimitCount}人,本次提交{submittedPersonCount}人,超出限报配置"));
+ }
+ }
}
}
@@ -1402,7 +1434,7 @@ public class UnifiedRegistrationService : ITransient
member.Id,
member.Name ?? member.NickName ?? "未知",
"IndividualProjectLimit",
- $"队员{member.Name}已报名{individualProjectCount}个个人项目,达到个人项目限报{limit.IndividualProjectLimit}个"));
+ $"成员项目限报设置:队员\"{member.Name}\"已报名{individualProjectCount}个个人项目,个人项目限报{limit.IndividualProjectLimit}个,请减少个人项目报名数量"));
}
///
@@ -1427,7 +1459,7 @@ public class UnifiedRegistrationService : ITransient
member.Id,
member.Name ?? member.NickName ?? "未知",
"TeamProjectLimit",
- $"队员{member.Name}已参与{teamProjectCount}个团队项目,达到团队项目限报{limit.TeamProjectLimit}个"));
+ $"成员项目限报设置:队员\"{member.Name}\"已参与{teamProjectCount}个团队项目,团队项目限报{limit.TeamProjectLimit}个,请减少团队项目报名数量"));
}
///
@@ -1499,7 +1531,7 @@ public class UnifiedRegistrationService : ITransient
0,
personName,
"PersonProjectDuplicate",
- $"人员\"{personName}\"在项目\"{groupInfo.ProjectName}\"的组别\"{groupInfo.GroupName}\"中重复出现,同一人员只能在一个团队中报名同一项目组别"));
+ $"人员项目重复检测:人员\"{personName}\"在项目\"{groupInfo.ProjectName}\"的组别\"{groupInfo.GroupName}\"中重复出现,同一人员只能在一个团队中报名同一项目组别"));
}
}
}
@@ -1558,7 +1590,72 @@ public class UnifiedRegistrationService : ITransient
0,
person.Name,
"PersonAlreadyRegistered",
- $"人员\"{person.Name}\"已在项目\"{projectName}\"的组别\"{eventProjectGroup.GroupName}\"中报名过,不能重复报名"));
+ $"人员已报名检测:人员\"{person.Name}\"已在项目\"{projectName}\"的组别\"{eventProjectGroup.GroupName}\"中报名过,不能重复报名,避免占用多个名额"));
+ }
+ }
+ }
+
+ ///
+ /// 检查项目完成人数
+ ///
+ private void CheckProjectCompletionAsync(
+ UnifiedRegistrationInput input,
+ RegistrationLimitCheckOutput result,
+ List eventProjects,
+ List projects,
+ List eventProjectGroups)
+ {
+ foreach (var item in input.Items)
+ {
+ if (!item.GroupId.HasValue) continue;
+
+ // 获取组别信息
+ var eventProjectGroup = eventProjectGroups.FirstOrDefault(epg => epg.Id == item.GroupId.Value);
+ if (eventProjectGroup == null) continue;
+
+ // 获取赛事项目信息
+ var eventProject = eventProjects.FirstOrDefault(ep => ep.Id == eventProjectGroup.EventProjectId);
+ if (eventProject == null) continue;
+
+ // 获取基础项目信息
+ var project = projects.FirstOrDefault(p => p.Id == eventProject.ProjectId);
+ if (project == null) continue;
+
+ // 判断是否为团队项目
+ var isTeamProject = project.IsTeamProject();
+
+ // 计算分配的人数(去重)
+ var assignedPersons = GetAllPersonsFromItem(item);
+ var totalAssignedMembers = assignedPersons
+ .Where(p => p.UserId.HasValue)
+ .Select(p => p.UserId.Value)
+ .Distinct()
+ .Count();
+
+ // ==================== 项目完成人数验证 ====================
+ // 验证用户选择的参与人数必须与项目的"完成人数"完全一致
+ if (project.CompletionCount > 0 && totalAssignedMembers != project.CompletionCount)
+ {
+ string errorMessage;
+ if (totalAssignedMembers < project.CompletionCount)
+ {
+ errorMessage = isTeamProject
+ ? $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前只分配了{totalAssignedMembers}人,请补充队员"
+ : $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前只分配了{totalAssignedMembers}人,请补充队员";
+ }
+ else
+ {
+ errorMessage = isTeamProject
+ ? $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{totalAssignedMembers}人,人数超额,请移除多余队员"
+ : $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{totalAssignedMembers}人,人数超额,请移除多余队员";
+ }
+
+ result.HasLimit = true;
+ result.LimitDetails.Add(CreateLimitDetail(
+ 0,
+ eventProjectGroup.GroupName ?? "未知组别",
+ "ProjectCompletion",
+ errorMessage));
}
}
}