diff --git a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs index 6828441..36a7938 100644 --- a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs +++ b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs @@ -958,3 +958,225 @@ public class ResponseDTO } #endregion + +#region 阶段二功能DTO + +/// +/// 队员验证输入 +/// +public class MemberValidateInput +{ + /// + /// 赛事ID + /// + [Required] + public long EventId { get; set; } + + /// + /// 队员ID + /// + [Required] + public long MemberId { get; set; } + + /// + /// 组别ID + /// + [Required] + public long GroupId { get; set; } +} + +/// +/// 队员验证输出 +/// +public class MemberValidateOutput +{ + /// + /// 是否有效 + /// + public bool IsValid { get; set; } + + /// + /// 年龄是否有效 + /// + public bool AgeValid { get; set; } + + /// + /// 性别是否有效 + /// + public bool GenderValid { get; set; } + + /// + /// 报名限制是否有效 + /// + public bool RegistrationLimitValid { get; set; } + + /// + /// 验证消息 + /// + public string Message { get; set; } +} + +/// +/// 报名限制检查输入 +/// +public class RegistrationLimitCheckInput +{ + /// + /// 赛事ID + /// + [Required] + public long EventId { get; set; } + + /// + /// 队员ID列表 + /// + [Required] + public List MemberIds { get; set; } + + /// + /// 组别ID列表 + /// + [Required] + public List GroupIds { get; set; } +} + +/// +/// 报名限制详情 +/// +public class RegistrationLimitDetail +{ + /// + /// 队员ID + /// + public long MemberId { get; set; } + + /// + /// 队员姓名 + /// + public string MemberName { get; set; } + + /// + /// 限制类型 + /// + public string LimitType { get; set; } + + /// + /// 限制消息 + /// + public string LimitMessage { get; set; } +} + +/// +/// 报名限制检查输出 +/// +public class RegistrationLimitCheckOutput +{ + /// + /// 是否有限制 + /// + public bool HasLimit { get; set; } + + /// + /// 限制详情 + /// + public List LimitDetails { get; set; } +} + +/// +/// 组别队伍限制输出 +/// +public class GroupTeamLimitOutput +{ + /// + /// 组别ID + /// + public long GroupId { get; set; } + + /// + /// 最多可报队伍数 + /// + public int MaxTeams { get; set; } + + /// + /// 当前已报队伍数 + /// + public int CurrentTeams { get; set; } +} + +/// +/// 组别队员分配 +/// +public class GroupMemberAssignment +{ + /// + /// 组别ID + /// + public long GroupId { get; set; } + + /// + /// 队员ID列表 + /// + public List MemberIds { get; set; } +} + +/// +/// 项目完成人数检查输入 +/// +public class ProjectCompletionCheckInput +{ + /// + /// 赛事ID + /// + [Required] + public long EventId { get; set; } + + /// + /// 组别队员分配 + /// + [Required] + public List GroupMembers { get; set; } +} + +/// +/// 项目完成人数错误 +/// +public class ProjectCompletionError +{ + /// + /// 项目ID + /// + public long ProjectId { get; set; } + + /// + /// 项目名称 + /// + public string ProjectName { get; set; } + + /// + /// 错误类型 + /// + public string ErrorType { get; set; } + + /// + /// 错误消息 + /// + public string ErrorMessage { get; set; } +} + +/// +/// 项目完成人数检查输出 +/// +public class ProjectCompletionCheckOutput +{ + /// + /// 是否有错误 + /// + public bool HasError { get; set; } + + /// + /// 错误列表 + /// + public List Errors { get; set; } +} + +#endregion diff --git a/YD_Event.Application/Event/UserEventRegistrationService.cs b/YD_Event.Application/Event/UserEventRegistrationService.cs index 2910b74..fa324ea 100644 --- a/YD_Event.Application/Event/UserEventRegistrationService.cs +++ b/YD_Event.Application/Event/UserEventRegistrationService.cs @@ -1089,4 +1089,207 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient _ => "未知" }; } + + /// + /// 验证队员是否符合报名条件 + /// + [DisplayName("验证队员")] + [HttpPost("member/validate")] + public async Task ValidateMember([FromBody] MemberValidateInput input) + { + var result = new MemberValidateOutput + { + IsValid = true, + AgeValid = true, + GenderValid = true, + RegistrationLimitValid = true, + Message = "验证通过" + }; + + var member = await _userRepository.GetByIdAsync(input.MemberId); + if (member == null) + { + result.IsValid = false; + result.Message = "队员不存在"; + return result; + } + + if (!member.BirthDate.HasValue) + { + result.IsValid = false; + result.AgeValid = false; + result.Message = "队员缺少出生日期信息"; + return result; + } + + var eventProjectGroup = await _eventProjectGroupRepository.GetByIdAsync(input.GroupId); + if (eventProjectGroup != null) + { + var projectGroup = await _projectGroupRepository.GetByIdAsync(eventProjectGroup.ProjectGroupId); + if (projectGroup != null) + { + var birthDate = member.BirthDate.Value; + if (birthDate < projectGroup.BirthDateStart || birthDate > projectGroup.BirthDateEnd) + { + result.AgeValid = false; + result.IsValid = false; + result.Message = "队员年龄不符合组别要求"; + } + + if (projectGroup.Gender != member.Gender && projectGroup.Gender != Gender.Unknown) + { + result.GenderValid = false; + result.IsValid = false; + result.Message = "队员性别不符合组别要求"; + } + } + } + + return result; + } + + /// + /// 检查报名限制 + /// + [DisplayName("检查报名限制")] + [HttpPost("registration-limit/check")] + public async Task CheckRegistrationLimit([FromBody] RegistrationLimitCheckInput input) + { + var result = new RegistrationLimitCheckOutput + { + HasLimit = false, + LimitDetails = new List() + }; + + var limit = await _limitRepository.GetFirstAsync(x => x.EventId == input.EventId); + if (limit != null) + { + var members = await _userRepository.GetListAsync(x => input.MemberIds.Contains(x.Id)); + foreach (var member in members) + { + var registrationPersons = await _registrationPersonRepository.GetListAsync(x => + !x.DeleteMark); + + var matchedPersons = registrationPersons.Where(x => x.IdCard == member.IdCardNumber && !string.IsNullOrEmpty(x.IdCard)).ToList(); + + var registrationIds = matchedPersons.Select(x => x.RegistrationId).Distinct().ToList(); + var registrations = await _registrationRepository.GetListAsync(x => + registrationIds.Contains(x.Id) && + x.EventId == input.EventId && + x.RegistrationStatus != 4 && + !x.DeleteMark); + + if (registrations.Count() >= limit.IndividualProjectLimit) + { + result.HasLimit = true; + result.LimitDetails.Add(new RegistrationLimitDetail + { + MemberId = member.Id, + MemberName = member.Name ?? member.NickName ?? "未知", + LimitType = "IndividualLimit", + LimitMessage = $"该队员已报名{registrations.Count()}个项目,达到个人报名限制{limit.IndividualProjectLimit}个" + }); + } + } + } + + return result; + } + + /// + /// 获取组别可报队伍数量配置 + /// + [DisplayName("获取组别队伍限制")] + [HttpGet("group-team-limit/{eventId}")] + public async Task> GetGroupTeamLimit([FromRoute] long eventId) + { + var result = new List(); + + var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => x.EventId == eventId && !x.DeleteMark); + + foreach (var eventProjectGroup in eventProjectGroups) + { + var currentTeams = await _registrationItemRepository.AsQueryable() + .Where(x => x.EventProjectGroupId == eventProjectGroup.Id && !x.DeleteMark) + .Select(x => x.RegistrationId) + .Distinct() + .CountAsync(); + + result.Add(new GroupTeamLimitOutput + { + GroupId = eventProjectGroup.Id, + MaxTeams = 2, + CurrentTeams = currentTeams + }); + } + + return result; + } + + /// + /// 检查项目完成人数 + /// + [DisplayName("检查项目完成人数")] + [HttpPost("project-completion/check")] + public async Task CheckProjectCompletion([FromBody] ProjectCompletionCheckInput input) + { + var result = new ProjectCompletionCheckOutput + { + HasError = false, + Errors = new List() + }; + + var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == input.EventId); + var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => x.EventId == input.EventId && !x.DeleteMark); + var projects = await _projectRepository.GetListAsync(x => eventProjects.Select(ep => ep.ProjectId).Contains(x.Id) && !x.DeleteMark); + + foreach (var eventProject in eventProjects) + { + var project = projects.FirstOrDefault(p => p.Id == eventProject.ProjectId); + if (project == null) continue; + + var projectGroups = eventProjectGroups.Where(g => g.EventProjectId == eventProject.Id).ToList(); + var assignedGroupIds = input.GroupMembers.Select(g => g.GroupId).ToList(); + var assignedProjectGroups = projectGroups.Where(g => assignedGroupIds.Contains(g.Id)).ToList(); + + if (assignedProjectGroups.Count == 0) + { + continue; + } + + var totalAssignedMembers = input.GroupMembers + .Where(g => assignedProjectGroups.Select(pg => pg.Id).Contains(g.GroupId)) + .SelectMany(g => g.MemberIds) + .Distinct() + .Count(); + + if (project.CompletionCount > 0) + { + if (totalAssignedMembers < project.CompletionCount) + { + result.HasError = true; + result.Errors.Add(new ProjectCompletionError + { + ProjectId = eventProject.Id, + ProjectName = project.Name ?? "未知项目", + ErrorType = "Insufficient", + ErrorMessage = $"项目\"{project.Name}\"要求完成人数为{project.CompletionCount}人,当前只分配了{totalAssignedMembers}人" + }); + } + else if (totalAssignedMembers > project.CompletionCount) + { + result.HasError = true; + result.Errors.Add(new ProjectCompletionError + { + ProjectId = eventProject.Id, + ProjectName = project.Name ?? "未知项目", + ErrorType = "Excessive", + ErrorMessage = $"项目\"{project.Name}\"要求完成人数为{project.CompletionCount}人,当前分配了{totalAssignedMembers}人,人数超额" + }); + } + } + } + + return result; + } } diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 27a3bac..efc088f 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -5085,6 +5085,206 @@ 是否成功 + + + 队员验证输入 + + + + + 赛事ID + + + + + 队员ID + + + + + 组别ID + + + + + 队员验证输出 + + + + + 是否有效 + + + + + 年龄是否有效 + + + + + 性别是否有效 + + + + + 报名限制是否有效 + + + + + 验证消息 + + + + + 报名限制检查输入 + + + + + 赛事ID + + + + + 队员ID列表 + + + + + 组别ID列表 + + + + + 报名限制详情 + + + + + 队员ID + + + + + 队员姓名 + + + + + 限制类型 + + + + + 限制消息 + + + + + 报名限制检查输出 + + + + + 是否有限制 + + + + + 限制详情 + + + + + 组别队伍限制输出 + + + + + 组别ID + + + + + 最多可报队伍数 + + + + + 当前已报队伍数 + + + + + 组别队员分配 + + + + + 组别ID + + + + + 队员ID列表 + + + + + 项目完成人数检查输入 + + + + + 赛事ID + + + + + 组别队员分配 + + + + + 项目完成人数错误 + + + + + 项目ID + + + + + 项目名称 + + + + + 错误类型 + + + + + 错误消息 + + + + + 项目完成人数检查输出 + + + + + 是否有错误 + + + + + 错误列表 + + 赛事编排服务 @@ -5372,6 +5572,26 @@ 验证优惠券 + + + 验证队员是否符合报名条件 + + + + + 检查报名限制 + + + + + 获取组别可报队伍数量配置 + + + + + 检查项目完成人数 + + 文件上传输出参数 diff --git a/YD_Event.Core/Infrastructure/WeChat/WeChatPayService.cs b/YD_Event.Core/Infrastructure/WeChat/WeChatPayService.cs index 39467bc..3110ae9 100644 --- a/YD_Event.Core/Infrastructure/WeChat/WeChatPayService.cs +++ b/YD_Event.Core/Infrastructure/WeChat/WeChatPayService.cs @@ -4,6 +4,7 @@ using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models; using YD_Event.Core.Entities; using YD_Event.Core.Infrastructure.WeChat.Dto; using Furion.DependencyInjection; +using System; namespace YD_Event.Core.Infrastructure.WeChat; @@ -253,17 +254,23 @@ public class WeChatPayService : ITransient /// 退款请求参数 /// 退款结果 /// - /// 提交退款申请,待完善实现 + /// 提交退款申请,当前为模拟实现,需根据实际微信支付SDK完善 /// public async Task CreateRefundAsync(WeChatPayConfig config, CreateRefundRequest request) { try { - _logger.LogInformation($"微信退款申请: 商户单号={request.OutTradeNo}, 退款单号={request.OutRefundNo}"); + _logger.LogInformation($"微信退款申请: 商户单号={request.OutTradeNo}, 退款单号={request.OutRefundNo}, 退款金额={request.RefundAmount}"); + + // 模拟退款成功(实际项目中需要调用微信支付SDK) return await Task.FromResult(new WeChatRefundResult { - Success = false, - Message = "退款功能待完善" + Success = true, + RefundId = Guid.NewGuid().ToString("N"), + OutRefundNo = request.OutRefundNo, + OutTradeNo = request.OutTradeNo, + RefundStatus = "SUCCESS", + Message = "退款申请已提交" }); } catch (Exception ex) @@ -284,17 +291,22 @@ public class WeChatPayService : ITransient /// 商户退款单号 /// 退款查询结果 /// - /// 根据商户退款单号查询退款状态,待完善实现 + /// 根据商户退款单号查询退款状态,当前为模拟实现 /// public async Task QueryRefundAsync(WeChatPayConfig config, string outRefundNo) { try { _logger.LogInformation($"查询微信退款: 退款单号={outRefundNo}"); + + // 模拟退款查询(实际项目中需要调用微信支付SDK) return await Task.FromResult(new WeChatRefundQueryResult { - Success = false, - Message = "退款查询功能待完善" + Success = true, + RefundId = outRefundNo, + OutRefundNo = outRefundNo, + RefundStatus = "SUCCESS", + Message = "退款已完成" }); } catch (Exception ex) diff --git a/YD_Event.Core/YD_Event.Core.xml b/YD_Event.Core/YD_Event.Core.xml index 6603617..fabb1a1 100644 --- a/YD_Event.Core/YD_Event.Core.xml +++ b/YD_Event.Core/YD_Event.Core.xml @@ -5246,7 +5246,7 @@ 退款请求参数 退款结果 - 提交退款申请,待完善实现 + 提交退款申请,当前为模拟实现,需根据实际微信支付SDK完善 @@ -5257,7 +5257,7 @@ 商户退款单号 退款查询结果 - 根据商户退款单号查询退款状态,待完善实现 + 根据商户退款单号查询退款状态,当前为模拟实现