添加赛事限制的友好提示
This commit is contained in:
parent
41c55fafe0
commit
2a38a5a1aa
@ -82,7 +82,7 @@ public class MyController : IDynamicApiController
|
||||
if (user == null) throw Oops.Bah("用户信息不存在");
|
||||
|
||||
// 统计证书数量
|
||||
var certCount = await _certificateRepository.CountAsync(c => c.CreatedUserId == userId && c.CertificateStatus == 2);
|
||||
var certCount = await _certificateRepository.CountAsync(c => c.UserId == userId && c.CertificateStatus == 2);
|
||||
|
||||
// 积分 (需计算积分总和,PointsRecord 表有 Points 字段,Type 1-加 2-减)
|
||||
// 简单计算:Sum(Type=1) - Sum(Type=2)
|
||||
@ -351,7 +351,7 @@ public class MyController : IDynamicApiController
|
||||
public async Task<MyCertificateOverviewDto> GetCertificatesOverview()
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
var count = await _certificateRepository.CountAsync(c => c.CreatedUserId == userId && c.CertificateStatus == 2 && !c.DeleteMark);
|
||||
var count = await _certificateRepository.CountAsync(c => c.UserId == userId && c.CertificateStatus == 2 && !c.DeleteMark);
|
||||
|
||||
return new MyCertificateOverviewDto
|
||||
{
|
||||
@ -372,7 +372,7 @@ public class MyController : IDynamicApiController
|
||||
var query = _certificateRepository.AsQueryable()
|
||||
.LeftJoin<EventInfo>((c, e) => c.EventId == e.Id)
|
||||
.LeftJoin<ProjectEntity>((c, e, p) => c.ProjectId == p.Id)
|
||||
.Where((c, e, p) => c.CreatedUserId == userId && c.CertificateStatus == 2 && !c.DeleteMark)
|
||||
.Where((c, e, p) => c.UserId == userId && c.CertificateStatus == 2 && !c.DeleteMark)
|
||||
.Select((c, e, p) => new
|
||||
{
|
||||
Id = c.Id,
|
||||
|
||||
@ -193,6 +193,12 @@ public class IssueCertificateInput
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "请选择证书")]
|
||||
public long CertificateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 页面类型:1-运动员页面,2-教练页面,3-领队页面
|
||||
/// 用于明确区分不同角色页面的证书生成逻辑
|
||||
/// </summary>
|
||||
public CertificatePageType PageType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -418,16 +418,66 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
throw Oops.Bah("证书关联的模板不存在或不可用");
|
||||
}
|
||||
|
||||
// 批量预加载所有需要的数据
|
||||
var persons = await _personRepository.GetListAsync(x => input.PersonIds.Contains(x.Id));
|
||||
var personDict = persons.ToDictionary(p => p.Id);
|
||||
// 根据页面类型确定允许的人员类型
|
||||
List<PersonType> allowedPersonTypes = GetAllowedPersonTypes(input.PageType);
|
||||
_logger.LogInformation("发放证书 - 页面类型: {PageType}, 允许的人员类型: {AllowedTypes}",
|
||||
input.PageType, string.Join(", ", allowedPersonTypes));
|
||||
|
||||
var personIds = persons.Select(p => p.Id).ToList();
|
||||
var existingResults = await _resultRepository.GetListAsync(x => personIds.Contains(x.RegistrationPersonId));
|
||||
// 批量预加载所有需要的数据
|
||||
// 先尝试直接从 EventRegistrationPerson 表获取所有人员
|
||||
var directPersons = await _personRepository.GetListAsync(x => input.PersonIds.Contains(x.Id));
|
||||
var directPersonDict = directPersons.ToDictionary(p => p.Id);
|
||||
|
||||
// 找出在 directPersonDict 中找不到的人员ID,这些可能是教练/领队的 AppUser ID
|
||||
var missingPersonIds = input.PersonIds.Where(id => !directPersonDict.ContainsKey(id)).ToList();
|
||||
|
||||
// 构建最终的人员字典
|
||||
var personDict = new Dictionary<long, EventRegistrationPerson>();
|
||||
foreach (var kvp in directPersonDict)
|
||||
{
|
||||
personDict[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
// 对于找不到的人员ID,尝试通过团队关系查找对应的 EventRegistrationPerson 记录
|
||||
if (missingPersonIds.Any())
|
||||
{
|
||||
_logger.LogInformation("查找 {Count} 个缺失的人员ID,尝试通过团队关系获取", missingPersonIds.Count);
|
||||
|
||||
// 获取该赛事的所有 EventRegistrationPerson 记录
|
||||
var allEventPersons = await _personRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||
.Where((p, r) => r.EventId == input.EventId && !p.DeleteMark)
|
||||
.Select((p, r) => p)
|
||||
.ToListAsync();
|
||||
|
||||
// 建立 UserId 到 EventRegistrationPerson 的映射
|
||||
var userToPersonMap = allEventPersons
|
||||
.Where(p => p.UserId > 0)
|
||||
.GroupBy(p => p.UserId)
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
|
||||
// 尝试通过 UserId 匹配
|
||||
foreach (var missingId in missingPersonIds)
|
||||
{
|
||||
if (userToPersonMap.TryGetValue(missingId, out var person))
|
||||
{
|
||||
personDict[missingId] = person;
|
||||
_logger.LogInformation("通过 UserId {UserId} 找到对应的 EventRegistrationPerson: {PersonId}", missingId, person.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("无法找到人员ID: {PersonId}", missingId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用最终找到的人员ID列表
|
||||
var foundPersonIds = personDict.Values.Select(p => p.Id).ToList();
|
||||
var existingResults = await _resultRepository.GetListAsync(x => foundPersonIds.Contains(x.RegistrationPersonId));
|
||||
var resultDict = existingResults.ToDictionary(r => r.RegistrationPersonId);
|
||||
|
||||
var existingCerts = await _certificateRepository.GetListAsync(x =>
|
||||
personIds.Contains(x.ParticipationRecordId));
|
||||
foundPersonIds.Contains(x.ParticipationRecordId));
|
||||
var certDict = existingCerts.ToDictionary(c => c.ParticipationRecordId);
|
||||
|
||||
var certsToInsert = new List<EventCertificate>();
|
||||
@ -442,19 +492,30 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
continue;
|
||||
}
|
||||
|
||||
// 验证人员类型是否与当前页面类型匹配
|
||||
if (!allowedPersonTypes.Contains(person.PersonType))
|
||||
{
|
||||
result.FailCount++;
|
||||
result.FailDetails.Add($"人员 {person.Name} 的类型 ({person.PersonType}) 与当前页面类型不匹配");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取实际的 EventRegistrationPerson ID(如果通过 UserId 映射过来的,需要使用实际的 Id)
|
||||
var actualPersonId = person.Id;
|
||||
|
||||
EventCertificate? cert = null;
|
||||
bool isNewCert = false;
|
||||
|
||||
if (person.PersonType == PersonType.Athlete || person.PersonType == PersonType.User)
|
||||
{
|
||||
if (!resultDict.TryGetValue(person.Id, out var resultRecord))
|
||||
if (!resultDict.TryGetValue(actualPersonId, out var resultRecord))
|
||||
{
|
||||
result.FailCount++;
|
||||
result.FailDetails.Add($"人员 {person.Name} 没有成绩记录");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (certDict.TryGetValue(person.Id, out var existingCert))
|
||||
if (certDict.TryGetValue(actualPersonId, out var existingCert))
|
||||
{
|
||||
cert = existingCert;
|
||||
}
|
||||
@ -466,12 +527,14 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
EventId = input.EventId,
|
||||
ResultId = resultRecord.Id,
|
||||
RegistrationId = person.RegistrationId,
|
||||
ParticipationRecordId = person.Id,
|
||||
ParticipationRecordId = actualPersonId,
|
||||
ProjectId = person.ProjectId,
|
||||
UserId = person.UserId,
|
||||
ParticipantName = person.Name,
|
||||
GroupName = person.GroupName,
|
||||
CertificateStatus = 1,
|
||||
GeneratedTime = now,
|
||||
CertificateNo = $"C{now:yyyyMMdd}{person.Id}",
|
||||
CertificateNo = $"C{now:yyyyMMdd}{actualPersonId}",
|
||||
CreatedTime = now,
|
||||
TemplateId = templateId,
|
||||
CertificateUrl = string.Empty
|
||||
@ -515,7 +578,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
}
|
||||
else
|
||||
{
|
||||
if (certDict.TryGetValue(person.Id, out var existingCert))
|
||||
if (certDict.TryGetValue(actualPersonId, out var existingCert))
|
||||
{
|
||||
cert = existingCert;
|
||||
}
|
||||
@ -526,12 +589,14 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
Id = _idGenerator.NewLong(),
|
||||
EventId = input.EventId,
|
||||
RegistrationId = person.RegistrationId,
|
||||
ParticipationRecordId = person.Id,
|
||||
ParticipationRecordId = actualPersonId,
|
||||
ProjectId = person.ProjectId,
|
||||
UserId = person.UserId,
|
||||
ParticipantName = person.Name,
|
||||
GroupName = person.GroupName,
|
||||
CertificateStatus = 1,
|
||||
GeneratedTime = now,
|
||||
CertificateNo = $"CC{now:yyyyMMdd}{person.Id}",
|
||||
CertificateNo = $"CC{now:yyyyMMdd}{actualPersonId}",
|
||||
CreatedTime = now,
|
||||
TemplateId = templateId,
|
||||
CertificateUrl = string.Empty
|
||||
@ -609,6 +674,22 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据页面类型获取允许的人员类型列表
|
||||
/// </summary>
|
||||
/// <param name="pageType">页面类型</param>
|
||||
/// <returns>允许的人员类型列表</returns>
|
||||
private List<PersonType> GetAllowedPersonTypes(CertificatePageType pageType)
|
||||
{
|
||||
return pageType switch
|
||||
{
|
||||
CertificatePageType.Athlete => new List<PersonType> { PersonType.Athlete, PersonType.User },
|
||||
CertificatePageType.Coach => new List<PersonType> { PersonType.Coach },
|
||||
CertificatePageType.Leader => new List<PersonType> { PersonType.Leader },
|
||||
_ => new List<PersonType> { PersonType.Athlete, PersonType.User, PersonType.Coach, PersonType.Leader }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建运动员占位符数据
|
||||
/// </summary>
|
||||
@ -708,7 +789,8 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
/// <param name="input">输入参数</param>
|
||||
/// <returns>证书详情</returns>
|
||||
[DisplayName("查看证书")]
|
||||
public async Task<object> GetCertificateDetail(YD_Event.Application.Certificate.Dtos.IdInput input)
|
||||
[HttpPost("getcertificatedetail")]
|
||||
public async Task<object> GetCertificateDetail([FromBody] YD_Event.Application.Certificate.Dtos.IdInput input)
|
||||
{
|
||||
if (input.Id <= 0)
|
||||
{
|
||||
@ -727,7 +809,16 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
throw Oops.Bah("未找到对应的证书信息");
|
||||
}
|
||||
|
||||
return new { Url = cert.CertificateUrl };
|
||||
return new
|
||||
{
|
||||
Id = cert.Id,
|
||||
CertificateNo = cert.CertificateNo,
|
||||
CertificateUrl = cert.CertificateUrl,
|
||||
CertificateStatus = cert.CertificateStatus,
|
||||
IssuedTime = cert.IssuedTime,
|
||||
ParticipantName = cert.ParticipantName,
|
||||
GroupName = cert.GroupName
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -817,7 +908,8 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
/// 导出证书
|
||||
/// </summary>
|
||||
[DisplayName("导出证书")]
|
||||
public async Task<string> ExportCertificate(ScoreQueryInput input)
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ExportCertificate([FromQuery] ScoreQueryInput input)
|
||||
{
|
||||
var list = await _certificateRepository.AsQueryable()
|
||||
.LeftJoin<EventResult>((c, r) => c.ResultId == r.Id)
|
||||
@ -845,8 +937,13 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
.ToListAsync();
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
stream.SaveAs(list);
|
||||
return Convert.ToBase64String(stream.ToArray());
|
||||
await stream.SaveAsAsync(list);
|
||||
var bytes = stream.ToArray();
|
||||
|
||||
return new FileContentResult(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = $"证书列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1266,7 +1266,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
0,
|
||||
eventProjectGroup.GroupName ?? "未知组别",
|
||||
"ProjectGroupCapacity",
|
||||
$"项目组别限报设置:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"限报{projectLimit.LimitCount}队,本次提交{submittedTeamCount}队,超出限报配置"));
|
||||
$"{project.Name}项目已达到报名限制"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1286,7 +1286,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
0,
|
||||
eventProjectGroup.GroupName ?? "未知组别",
|
||||
"ProjectGroupCapacity",
|
||||
$"项目组别限报设置:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"限报{projectLimit.LimitCount}人,本次提交{submittedPersonCount}人,超出限报配置"));
|
||||
$"{project.Name}项目已达到报名限制"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1434,7 +1434,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
member.Id,
|
||||
member.Name ?? member.NickName ?? "未知",
|
||||
"IndividualProjectLimit",
|
||||
$"成员项目限报设置:队员\"{member.Name}\"已报名{individualProjectCount}个个人项目,个人项目限报{limit.IndividualProjectLimit}个,请减少个人项目报名数量"));
|
||||
$"{member.Name}队员已达到报名限制"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1459,7 +1459,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
member.Id,
|
||||
member.Name ?? member.NickName ?? "未知",
|
||||
"TeamProjectLimit",
|
||||
$"成员项目限报设置:队员\"{member.Name}\"已参与{teamProjectCount}个团队项目,团队项目限报{limit.TeamProjectLimit}个,请减少团队项目报名数量"));
|
||||
$"{member.Name}队员已达到报名限制"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1632,22 +1632,33 @@ public class UnifiedRegistrationService : ITransient
|
||||
.Distinct()
|
||||
.Count();
|
||||
|
||||
// ==================== 项目组别条件判断逻辑 ====================
|
||||
// 当且仅当某个项目组别中已选择至少一名人员时,才对该项目组别执行后续条件判断流程
|
||||
if (totalAssignedMembers == 0)
|
||||
{
|
||||
// 若项目组别未选择任何人员,直接忽略该项目组别,不进行任何条件判断
|
||||
continue;
|
||||
}
|
||||
|
||||
// ==================== 报名限制验证规则 ====================
|
||||
// 个人项目不进行完成人数限制,仅适用项目报名限制规则
|
||||
if (!isTeamProject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ==================== 项目完成人数验证 ====================
|
||||
// 验证用户选择的参与人数必须与项目的"完成人数"完全一致
|
||||
// 只对团队项目进行完成人数验证
|
||||
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}人,请补充队员";
|
||||
errorMessage = $"{project.Name}参赛人数错误(少{project.CompletionCount - totalAssignedMembers}人)";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = isTeamProject
|
||||
? $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{totalAssignedMembers}人,人数超额,请移除多余队员"
|
||||
: $"项目完成人数限制:项目\"{project.Name}\"的组别\"{eventProjectGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{totalAssignedMembers}人,人数超额,请移除多余队员";
|
||||
errorMessage = $"{project.Name}参赛人数错误(多{totalAssignedMembers - project.CompletionCount}人)";
|
||||
}
|
||||
|
||||
result.HasLimit = true;
|
||||
|
||||
@ -347,10 +347,19 @@ public class UserEventRecordService : IDynamicApiController, ITransient
|
||||
[HttpGet("certificate/{registrationId}")]
|
||||
public async Task<ResponseDTO<CertificateDTO>> GetCertificate([FromRoute] long registrationId)
|
||||
{
|
||||
var userId = _authManager.UserId;
|
||||
|
||||
// 2-已发放
|
||||
var cert = await _certificateRepository.GetFirstAsync(x => x.RegistrationId == registrationId && x.CertificateStatus == 2);
|
||||
if (cert == null) return new ResponseDTO<CertificateDTO> { Code = 404, Message = "证书未颁发", Success = false };
|
||||
|
||||
// 权限验证
|
||||
bool hasPermission = await CheckCertificatePermissionAsync(userId, cert);
|
||||
if (!hasPermission)
|
||||
{
|
||||
return new ResponseDTO<CertificateDTO> { Code = 403, Message = "无权查看该证书", Success = false };
|
||||
}
|
||||
|
||||
return new ResponseDTO<CertificateDTO>
|
||||
{
|
||||
Code = 200, Success = true,
|
||||
@ -364,6 +373,44 @@ public class UserEventRecordService : IDynamicApiController, ITransient
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查证书查看权限
|
||||
/// </summary>
|
||||
private async Task<bool> CheckCertificatePermissionAsync(long currentUserId, EventCertificate cert)
|
||||
{
|
||||
// 如果是自己的证书,直接允许
|
||||
if (cert.UserId == currentUserId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查当前用户是否是单位用户,且该证书属于其管理的团队成员
|
||||
var currentUser = await _userRepository.GetByIdAsync(currentUserId);
|
||||
if (currentUser == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果当前用户有单位认证
|
||||
if (currentUser.MerchantCertificationId.HasValue)
|
||||
{
|
||||
// 查询当前用户管理的团队成员
|
||||
var teamMemberUserIds = await _db.Queryable<YD_Event.Core.Entities.Team>()
|
||||
.InnerJoin<TeamMember>((t, tm) => t.Id == tm.TeamId)
|
||||
.Where((t, tm) => t.CreatedUserId == currentUserId && !t.DeleteMark && !tm.DeleteMark)
|
||||
.Select((t, tm) => tm.UserId)
|
||||
.ToListAsync();
|
||||
|
||||
// 检查证书用户是否在团队成员列表中
|
||||
if (teamMemberUserIds.Contains(cert.UserId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 7. 取消报名预览
|
||||
/// </summary>
|
||||
|
||||
@ -1141,35 +1141,43 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
||||
// 计算该组别的分配人数(不跨组别,也不跨项目去重)
|
||||
var assignedCount = groupMemberAssignment.MemberIds?.Distinct().Count() ?? 0;
|
||||
|
||||
if (project.CompletionCount > 0)
|
||||
// ==================== 项目组别条件判断逻辑 ====================
|
||||
// 当且仅当某个项目组别中已选择至少一名人员时,才对该项目组别执行后续条件判断流程
|
||||
if (assignedCount == 0)
|
||||
{
|
||||
// 若项目组别未选择任何人员,直接忽略该项目组别,不进行任何条件判断
|
||||
continue;
|
||||
}
|
||||
|
||||
// ==================== 报名限制验证规则 ====================
|
||||
// 个人项目不进行完成人数限制,仅适用项目报名限制规则
|
||||
if (!isTeamProject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ==================== 项目完成人数验证 ====================
|
||||
// 只对团队项目进行完成人数验证
|
||||
if (project.CompletionCount > 0 && assignedCount != project.CompletionCount)
|
||||
{
|
||||
string errorMessage;
|
||||
if (assignedCount < project.CompletionCount)
|
||||
{
|
||||
result.HasError = true;
|
||||
result.Errors.Add(new ProjectCompletionError
|
||||
{
|
||||
ProjectId = eventProject.Id,
|
||||
ProjectName = project.Name ?? "未知项目",
|
||||
ErrorType = "Insufficient",
|
||||
ErrorMessage = isTeamProject
|
||||
? $"项目\"{project.Name}\"的组别\"{assignedGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前只分配了{assignedCount}人,请补充队员"
|
||||
: $"项目\"{project.Name}\"的组别\"{assignedGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前只分配了{assignedCount}人,请补充队员"
|
||||
});
|
||||
errorMessage = $"{project.Name}参赛人数错误(少{project.CompletionCount - assignedCount}人)";
|
||||
}
|
||||
else if (assignedCount > project.CompletionCount)
|
||||
else
|
||||
{
|
||||
// 只要达到或超过完成人数就提示超限(特别是个人项目)
|
||||
result.HasError = true;
|
||||
result.Errors.Add(new ProjectCompletionError
|
||||
{
|
||||
ProjectId = eventProject.Id,
|
||||
ProjectName = project.Name ?? "未知项目",
|
||||
ErrorType = "Excessive",
|
||||
ErrorMessage = isTeamProject
|
||||
? $"项目\"{project.Name}\"的组别\"{assignedGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{assignedCount}人,人数超额,请移除多余队员"
|
||||
: $"项目\"{project.Name}\"的组别\"{assignedGroup.GroupName}\"要求完成人数为{project.CompletionCount}人,当前分配了{assignedCount}人,人数超额,请移除多余队员"
|
||||
});
|
||||
errorMessage = $"{project.Name}参赛人数错误(多{assignedCount - project.CompletionCount}人)";
|
||||
}
|
||||
|
||||
result.HasError = true;
|
||||
result.Errors.Add(new ProjectCompletionError
|
||||
{
|
||||
ProjectId = eventProject.Id,
|
||||
ProjectName = project.Name ?? "未知项目",
|
||||
ErrorType = assignedCount < project.CompletionCount ? "Insufficient" : "Excessive",
|
||||
ErrorMessage = errorMessage
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5895,6 +5895,12 @@
|
||||
证书ID(必选)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.IssueCertificateInput.PageType">
|
||||
<summary>
|
||||
页面类型:1-运动员页面,2-教练页面,3-领队页面
|
||||
用于明确区分不同角色页面的证书生成逻辑
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.IssueCertificateResult">
|
||||
<summary>
|
||||
发放证书结果
|
||||
@ -7749,6 +7755,13 @@
|
||||
发放证书(支持模板选择和批量发放)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.GetAllowedPersonTypes(YD_Event.Core.Enum.CertificatePageType)">
|
||||
<summary>
|
||||
根据页面类型获取允许的人员类型列表
|
||||
</summary>
|
||||
<param name="pageType">页面类型</param>
|
||||
<returns>允许的人员类型列表</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventScoreService.BuildPlaceholderData(YD_Event.Core.Entities.EventRegistrationPerson,YD_Event.Core.Entities.EventResult)">
|
||||
<summary>
|
||||
构建运动员占位符数据
|
||||
@ -8289,6 +8302,11 @@
|
||||
6. 查看证书
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.UserEventRecordService.CheckCertificatePermissionAsync(System.Int64,YD_Event.Core.Entities.EventCertificate)">
|
||||
<summary>
|
||||
检查证书查看权限
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.UserEventRecordService.CancelPreview(System.Int64)">
|
||||
<summary>
|
||||
7. 取消报名预览
|
||||
|
||||
@ -33,6 +33,11 @@ public class EventCertificate : Entity<long>, ISoftDelete, ICreatedUserId, ICrea
|
||||
/// </summary>
|
||||
public long ProjectId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的用户ID
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参赛选手姓名
|
||||
/// </summary>
|
||||
|
||||
33
YD_Event.Core/Enum/CertificatePageType.cs
Normal file
33
YD_Event.Core/Enum/CertificatePageType.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace YD_Event.Core.Enum;
|
||||
|
||||
/// <summary>
|
||||
/// 证书页面类型
|
||||
/// </summary>
|
||||
public enum CertificatePageType
|
||||
{
|
||||
/// <summary>
|
||||
/// 未指定(向后兼容)
|
||||
/// </summary>
|
||||
[Description("未指定")]
|
||||
Unspecified = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 运动员页面
|
||||
/// </summary>
|
||||
[Description("运动员页面")]
|
||||
Athlete = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 教练页面
|
||||
/// </summary>
|
||||
[Description("教练页面")]
|
||||
Coach = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 领队页面
|
||||
/// </summary>
|
||||
[Description("领队页面")]
|
||||
Leader = 3
|
||||
}
|
||||
@ -1142,6 +1142,11 @@
|
||||
赛事项目ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventCertificate.UserId">
|
||||
<summary>
|
||||
关联的用户ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventCertificate.ParticipantName">
|
||||
<summary>
|
||||
参赛选手姓名
|
||||
@ -4290,6 +4295,31 @@
|
||||
禁用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Core.Enum.CertificatePageType">
|
||||
<summary>
|
||||
证书页面类型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:YD_Event.Core.Enum.CertificatePageType.Unspecified">
|
||||
<summary>
|
||||
未指定(向后兼容)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:YD_Event.Core.Enum.CertificatePageType.Athlete">
|
||||
<summary>
|
||||
运动员页面
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:YD_Event.Core.Enum.CertificatePageType.Coach">
|
||||
<summary>
|
||||
教练页面
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:YD_Event.Core.Enum.CertificatePageType.Leader">
|
||||
<summary>
|
||||
领队页面
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Core.Enum.ChargeMode">
|
||||
<summary>
|
||||
收费模式枚举
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user