赛事报名限制和退款服务

This commit is contained in:
马梓彭 2026-04-02 08:40:47 +08:00
parent 0d3d271fb5
commit 180ba797a4
5 changed files with 666 additions and 9 deletions

View File

@ -958,3 +958,225 @@ public class ResponseDTO<T>
}
#endregion
#region 阶段二功能DTO
/// <summary>
/// 队员验证输入
/// </summary>
public class MemberValidateInput
{
/// <summary>
/// 赛事ID
/// </summary>
[Required]
public long EventId { get; set; }
/// <summary>
/// 队员ID
/// </summary>
[Required]
public long MemberId { get; set; }
/// <summary>
/// 组别ID
/// </summary>
[Required]
public long GroupId { get; set; }
}
/// <summary>
/// 队员验证输出
/// </summary>
public class MemberValidateOutput
{
/// <summary>
/// 是否有效
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 年龄是否有效
/// </summary>
public bool AgeValid { get; set; }
/// <summary>
/// 性别是否有效
/// </summary>
public bool GenderValid { get; set; }
/// <summary>
/// 报名限制是否有效
/// </summary>
public bool RegistrationLimitValid { get; set; }
/// <summary>
/// 验证消息
/// </summary>
public string Message { get; set; }
}
/// <summary>
/// 报名限制检查输入
/// </summary>
public class RegistrationLimitCheckInput
{
/// <summary>
/// 赛事ID
/// </summary>
[Required]
public long EventId { get; set; }
/// <summary>
/// 队员ID列表
/// </summary>
[Required]
public List<long> MemberIds { get; set; }
/// <summary>
/// 组别ID列表
/// </summary>
[Required]
public List<long> GroupIds { get; set; }
}
/// <summary>
/// 报名限制详情
/// </summary>
public class RegistrationLimitDetail
{
/// <summary>
/// 队员ID
/// </summary>
public long MemberId { get; set; }
/// <summary>
/// 队员姓名
/// </summary>
public string MemberName { get; set; }
/// <summary>
/// 限制类型
/// </summary>
public string LimitType { get; set; }
/// <summary>
/// 限制消息
/// </summary>
public string LimitMessage { get; set; }
}
/// <summary>
/// 报名限制检查输出
/// </summary>
public class RegistrationLimitCheckOutput
{
/// <summary>
/// 是否有限制
/// </summary>
public bool HasLimit { get; set; }
/// <summary>
/// 限制详情
/// </summary>
public List<RegistrationLimitDetail> LimitDetails { get; set; }
}
/// <summary>
/// 组别队伍限制输出
/// </summary>
public class GroupTeamLimitOutput
{
/// <summary>
/// 组别ID
/// </summary>
public long GroupId { get; set; }
/// <summary>
/// 最多可报队伍数
/// </summary>
public int MaxTeams { get; set; }
/// <summary>
/// 当前已报队伍数
/// </summary>
public int CurrentTeams { get; set; }
}
/// <summary>
/// 组别队员分配
/// </summary>
public class GroupMemberAssignment
{
/// <summary>
/// 组别ID
/// </summary>
public long GroupId { get; set; }
/// <summary>
/// 队员ID列表
/// </summary>
public List<long> MemberIds { get; set; }
}
/// <summary>
/// 项目完成人数检查输入
/// </summary>
public class ProjectCompletionCheckInput
{
/// <summary>
/// 赛事ID
/// </summary>
[Required]
public long EventId { get; set; }
/// <summary>
/// 组别队员分配
/// </summary>
[Required]
public List<GroupMemberAssignment> GroupMembers { get; set; }
}
/// <summary>
/// 项目完成人数错误
/// </summary>
public class ProjectCompletionError
{
/// <summary>
/// 项目ID
/// </summary>
public long ProjectId { get; set; }
/// <summary>
/// 项目名称
/// </summary>
public string ProjectName { get; set; }
/// <summary>
/// 错误类型
/// </summary>
public string ErrorType { get; set; }
/// <summary>
/// 错误消息
/// </summary>
public string ErrorMessage { get; set; }
}
/// <summary>
/// 项目完成人数检查输出
/// </summary>
public class ProjectCompletionCheckOutput
{
/// <summary>
/// 是否有错误
/// </summary>
public bool HasError { get; set; }
/// <summary>
/// 错误列表
/// </summary>
public List<ProjectCompletionError> Errors { get; set; }
}
#endregion

View File

@ -1089,4 +1089,207 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
_ => "未知"
};
}
/// <summary>
/// 验证队员是否符合报名条件
/// </summary>
[DisplayName("验证队员")]
[HttpPost("member/validate")]
public async Task<MemberValidateOutput> 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;
}
/// <summary>
/// 检查报名限制
/// </summary>
[DisplayName("检查报名限制")]
[HttpPost("registration-limit/check")]
public async Task<RegistrationLimitCheckOutput> CheckRegistrationLimit([FromBody] RegistrationLimitCheckInput input)
{
var result = new RegistrationLimitCheckOutput
{
HasLimit = false,
LimitDetails = new List<RegistrationLimitDetail>()
};
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;
}
/// <summary>
/// 获取组别可报队伍数量配置
/// </summary>
[DisplayName("获取组别队伍限制")]
[HttpGet("group-team-limit/{eventId}")]
public async Task<List<GroupTeamLimitOutput>> GetGroupTeamLimit([FromRoute] long eventId)
{
var result = new List<GroupTeamLimitOutput>();
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;
}
/// <summary>
/// 检查项目完成人数
/// </summary>
[DisplayName("检查项目完成人数")]
[HttpPost("project-completion/check")]
public async Task<ProjectCompletionCheckOutput> CheckProjectCompletion([FromBody] ProjectCompletionCheckInput input)
{
var result = new ProjectCompletionCheckOutput
{
HasError = false,
Errors = new List<ProjectCompletionError>()
};
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;
}
}

View File

@ -5085,6 +5085,206 @@
是否成功
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.MemberValidateInput">
<summary>
队员验证输入
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateInput.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateInput.MemberId">
<summary>
队员ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateInput.GroupId">
<summary>
组别ID
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.MemberValidateOutput">
<summary>
队员验证输出
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateOutput.IsValid">
<summary>
是否有效
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateOutput.AgeValid">
<summary>
年龄是否有效
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateOutput.GenderValid">
<summary>
性别是否有效
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateOutput.RegistrationLimitValid">
<summary>
报名限制是否有效
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.MemberValidateOutput.Message">
<summary>
验证消息
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.RegistrationLimitCheckInput">
<summary>
报名限制检查输入
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitCheckInput.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitCheckInput.MemberIds">
<summary>
队员ID列表
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitCheckInput.GroupIds">
<summary>
组别ID列表
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.RegistrationLimitDetail">
<summary>
报名限制详情
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitDetail.MemberId">
<summary>
队员ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitDetail.MemberName">
<summary>
队员姓名
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitDetail.LimitType">
<summary>
限制类型
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitDetail.LimitMessage">
<summary>
限制消息
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.RegistrationLimitCheckOutput">
<summary>
报名限制检查输出
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitCheckOutput.HasLimit">
<summary>
是否有限制
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.RegistrationLimitCheckOutput.LimitDetails">
<summary>
限制详情
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.GroupTeamLimitOutput">
<summary>
组别队伍限制输出
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.GroupTeamLimitOutput.GroupId">
<summary>
组别ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.GroupTeamLimitOutput.MaxTeams">
<summary>
最多可报队伍数
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.GroupTeamLimitOutput.CurrentTeams">
<summary>
当前已报队伍数
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.GroupMemberAssignment">
<summary>
组别队员分配
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.GroupMemberAssignment.GroupId">
<summary>
组别ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.GroupMemberAssignment.MemberIds">
<summary>
队员ID列表
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.ProjectCompletionCheckInput">
<summary>
项目完成人数检查输入
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionCheckInput.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionCheckInput.GroupMembers">
<summary>
组别队员分配
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.ProjectCompletionError">
<summary>
项目完成人数错误
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionError.ProjectId">
<summary>
项目ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionError.ProjectName">
<summary>
项目名称
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionError.ErrorType">
<summary>
错误类型
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionError.ErrorMessage">
<summary>
错误消息
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.ProjectCompletionCheckOutput">
<summary>
项目完成人数检查输出
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionCheckOutput.HasError">
<summary>
是否有错误
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectCompletionCheckOutput.Errors">
<summary>
错误列表
</summary>
</member>
<member name="T:YD_Event.Application.Event.EventArrangementService">
<summary>
赛事编排服务
@ -5372,6 +5572,26 @@
验证优惠券
</summary>
</member>
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.ValidateMember(YD_Event.Application.Event.Dtos.MemberValidateInput)">
<summary>
验证队员是否符合报名条件
</summary>
</member>
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CheckRegistrationLimit(YD_Event.Application.Event.Dtos.RegistrationLimitCheckInput)">
<summary>
检查报名限制
</summary>
</member>
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.GetGroupTeamLimit(System.Int64)">
<summary>
获取组别可报队伍数量配置
</summary>
</member>
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CheckProjectCompletion(YD_Event.Application.Event.Dtos.ProjectCompletionCheckInput)">
<summary>
检查项目完成人数
</summary>
</member>
<member name="T:YD_Event.Application.File.Dtos.UploadFileOutput">
<summary>
文件上传输出参数

View File

@ -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
/// <param name="request">退款请求参数</param>
/// <returns>退款结果</returns>
/// <remarks>
/// 提交退款申请,待完善实现
/// 提交退款申请,当前为模拟实现,需根据实际微信支付SDK完善
/// </remarks>
public async Task<WeChatRefundResult> 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
/// <param name="outRefundNo">商户退款单号</param>
/// <returns>退款查询结果</returns>
/// <remarks>
/// 根据商户退款单号查询退款状态,待完善实现
/// 根据商户退款单号查询退款状态,当前为模拟实现
/// </remarks>
public async Task<WeChatRefundQueryResult> 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)

View File

@ -5246,7 +5246,7 @@
<param name="request">退款请求参数</param>
<returns>退款结果</returns>
<remarks>
提交退款申请,待完善实现
提交退款申请,当前为模拟实现,需根据实际微信支付SDK完善
</remarks>
</member>
<member name="M:YD_Event.Core.Infrastructure.WeChat.WeChatPayService.QueryRefundAsync(YD_Event.Core.Entities.WeChatPayConfig,System.String)">
@ -5257,7 +5257,7 @@
<param name="outRefundNo">商户退款单号</param>
<returns>退款查询结果</returns>
<remarks>
根据商户退款单号查询退款状态,待完善实现
根据商户退款单号查询退款状态,当前为模拟实现
</remarks>
</member>
<member name="M:YD_Event.Core.Infrastructure.WeChat.WeChatPayService.VerifyPayNotifyAsync(YD_Event.Core.Entities.WeChatPayConfig,YD_Event.Core.Infrastructure.WeChat.Dto.WeChatPayNotifyRequest)">