赛事保存积分和退款规则快照
This commit is contained in:
parent
50f0d86b91
commit
8c92e13e48
@ -240,6 +240,66 @@ public class PointsRuleDto
|
||||
public List<PointsRuleDetailDto>? Details { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则DTO
|
||||
/// </summary>
|
||||
public class RefundRuleDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 距离比赛开始天数(起)
|
||||
/// </summary>
|
||||
public int DayStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 距离比赛开始天数(止)
|
||||
/// </summary>
|
||||
public int DayEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扣除比例(%)
|
||||
/// </summary>
|
||||
public decimal DeductPercentage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则明细快照DTO
|
||||
/// </summary>
|
||||
public class PointsRuleDetailSnapshotDto
|
||||
{
|
||||
public int StartRank { get; set; }
|
||||
public int EndRank { get; set; }
|
||||
public int Points { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则快照DTO
|
||||
/// </summary>
|
||||
public class PointsRuleSnapshotDto
|
||||
{
|
||||
public long PointsRuleId { get; set; }
|
||||
public string RuleName { get; set; }
|
||||
public int? ParticipationPoints { get; set; }
|
||||
public string? Remark { get; set; }
|
||||
public List<PointsRuleDetailSnapshotDto> Details { get; set; } = new List<PointsRuleDetailSnapshotDto>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则快照DTO
|
||||
/// </summary>
|
||||
public class RefundRuleSnapshotDto
|
||||
{
|
||||
public long RefundConfigId { get; set; }
|
||||
public int DayStart { get; set; }
|
||||
public int DayEnd { get; set; }
|
||||
public decimal DeductPercentage { get; set; }
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 赛事详情DTO
|
||||
/// </summary>
|
||||
@ -314,6 +374,11 @@ public class EventDetailDto : EventListDto
|
||||
/// 积分规则详情
|
||||
/// </summary>
|
||||
public PointsRuleDto? PointsRuleDetail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则详情列表
|
||||
/// </summary>
|
||||
public List<RefundRuleDto>? RefundRules { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 个人项目限报数量
|
||||
|
||||
@ -65,6 +65,7 @@ public class EventClientController : IDynamicApiController
|
||||
private readonly YD_Event.Application.Banner.BannerService _bannerService;
|
||||
private readonly UnifiedRegistrationService _unifiedRegistrationService;
|
||||
private readonly YD_Event.Application.Refund.RefundConfigService _refundConfigService;
|
||||
private readonly EventRuleSnapshotService _ruleSnapshotService;
|
||||
|
||||
public EventClientController(
|
||||
ISqlSugarRepository<EventInfo> eventRepository,
|
||||
@ -101,7 +102,8 @@ public class EventClientController : IDynamicApiController
|
||||
OrderNoGeneratorService orderNoGeneratorService,
|
||||
YD_Event.Application.Banner.BannerService bannerService,
|
||||
UnifiedRegistrationService unifiedRegistrationService,
|
||||
YD_Event.Application.Refund.RefundConfigService refundConfigService)
|
||||
YD_Event.Application.Refund.RefundConfigService refundConfigService,
|
||||
EventRuleSnapshotService ruleSnapshotService)
|
||||
{
|
||||
_eventRepository = eventRepository;
|
||||
_projectRepository = projectRepository;
|
||||
@ -138,6 +140,7 @@ public class EventClientController : IDynamicApiController
|
||||
_bannerService = bannerService;
|
||||
_unifiedRegistrationService = unifiedRegistrationService;
|
||||
_refundConfigService = refundConfigService;
|
||||
_ruleSnapshotService = ruleSnapshotService;
|
||||
}
|
||||
|
||||
private long GetCurrentUserId()
|
||||
@ -292,29 +295,39 @@ public class EventClientController : IDynamicApiController
|
||||
if (district != null) districtName = district.DistrictName;
|
||||
}
|
||||
|
||||
PointsRuleDto? pointsRuleDetail = null;
|
||||
if (evt.PointsRuleId.HasValue)
|
||||
// 获取规则快照
|
||||
var pointsRuleSnapshot = await _ruleSnapshotService.GetPointsRuleSnapshot(evt.Id);
|
||||
var refundRuleSnapshots = await _ruleSnapshotService.GetRefundRuleSnapshot(evt.Id);
|
||||
|
||||
// 使用快照数据转换为详情DTO
|
||||
YD_Event.Application.Client.Dtos.PointsRuleDto? pointsRuleDetail = null;
|
||||
List<YD_Event.Application.Client.Dtos.RefundRuleDto>? refundRules = null;
|
||||
|
||||
if (pointsRuleSnapshot != null)
|
||||
{
|
||||
var pointsRuleEntity = await _pointsRuleRepository.GetFirstAsync(r => r.Id == evt.PointsRuleId.Value && !r.DeleteMark);
|
||||
if (pointsRuleEntity != null)
|
||||
pointsRuleDetail = new YD_Event.Application.Client.Dtos.PointsRuleDto
|
||||
{
|
||||
var details = await _pointsRuleDetailRepository.AsQueryable()
|
||||
.Where(d => d.PointsRuleId == pointsRuleEntity.Id && !d.DeleteMark)
|
||||
.ToListAsync();
|
||||
|
||||
pointsRuleDetail = new PointsRuleDto
|
||||
RuleName = pointsRuleSnapshot.RuleName,
|
||||
ParticipationPoints = pointsRuleSnapshot.ParticipationPoints,
|
||||
Remark = pointsRuleSnapshot.Remark,
|
||||
Details = pointsRuleSnapshot.Details.Select(d => new YD_Event.Application.Client.Dtos.PointsRuleDetailDto
|
||||
{
|
||||
RuleName = pointsRuleEntity.RuleName,
|
||||
ParticipationPoints = pointsRuleEntity.ParticipationPoints,
|
||||
Remark = pointsRuleEntity.Remark,
|
||||
Details = details.Select(d => new PointsRuleDetailDto
|
||||
{
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (refundRuleSnapshots != null && refundRuleSnapshots.Any())
|
||||
{
|
||||
refundRules = refundRuleSnapshots.Select(r => new YD_Event.Application.Client.Dtos.RefundRuleDto
|
||||
{
|
||||
DayStart = r.DayStart,
|
||||
DayEnd = r.DayEnd,
|
||||
DeductPercentage = r.DeductPercentage,
|
||||
Remark = r.Remark
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
var eventProjects = await _eventProjectRepository.AsQueryable()
|
||||
@ -355,31 +368,28 @@ public class EventClientController : IDynamicApiController
|
||||
string refundRule = "开赛前7天扣除金额5%,3-7天扣除金额10%,3天内扣除金额20%";
|
||||
string pointsRule = "参与积分:5积分;名次积分:1-8名 15积分,9-20名 10积分";
|
||||
|
||||
// 优先从 RefundConfig 表读取配置并生成描述文本
|
||||
try
|
||||
// 优先从快照读取配置并生成描述文本
|
||||
if (refundRuleSnapshots != null && refundRuleSnapshots.Any())
|
||||
{
|
||||
var refundConfigs = await _refundConfigService.GetList();
|
||||
var enabledConfigs = refundConfigs.Where(x => x.Status == Core.Enum.AvailabilityStatus.Enable).OrderBy(x => x.DayStart).ToList();
|
||||
if (enabledConfigs.Any())
|
||||
var ruleParts = new List<string>();
|
||||
foreach (var config in refundRuleSnapshots)
|
||||
{
|
||||
var ruleParts = new List<string>();
|
||||
foreach (var config in enabledConfigs)
|
||||
if (config.DayEnd >= 999)
|
||||
{
|
||||
if (config.DayEnd >= 999)
|
||||
{
|
||||
ruleParts.Add($"开赛前{config.DayStart}天及以上扣除金额{Math.Round(config.DeductPercentage)}%");
|
||||
}
|
||||
else
|
||||
{
|
||||
ruleParts.Add($"开赛前{config.DayStart}-{config.DayEnd}天扣除金额{Math.Round(config.DeductPercentage)}%");
|
||||
}
|
||||
ruleParts.Add($"开赛前{config.DayStart}天及以上扣除金额{Math.Round(config.DeductPercentage)}%");
|
||||
}
|
||||
else
|
||||
{
|
||||
ruleParts.Add($"开赛前{config.DayStart}-{config.DayEnd}天扣除金额{Math.Round(config.DeductPercentage)}%");
|
||||
}
|
||||
refundRule = string.Join(",", ruleParts);
|
||||
}
|
||||
refundRule = string.Join(",", ruleParts);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
// 积分规则文本从快照获取
|
||||
if (pointsRuleSnapshot != null && !string.IsNullOrWhiteSpace(pointsRuleSnapshot.Remark))
|
||||
{
|
||||
_logger.LogWarning(ex, "读取退款配置失败,赛事ID={EventId},使用默认规则", evt.Id);
|
||||
pointsRule = pointsRuleSnapshot.Remark;
|
||||
}
|
||||
|
||||
// 如果有自定义配置,优先使用自定义配置(保持向后兼容)
|
||||
@ -406,15 +416,6 @@ public class EventClientController : IDynamicApiController
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.PointsRuleId.HasValue)
|
||||
{
|
||||
var pointsRuleEntity = await _pointsRuleRepository.GetFirstAsync(r => r.Id == evt.PointsRuleId.Value && !r.DeleteMark);
|
||||
if (pointsRuleEntity != null)
|
||||
{
|
||||
pointsRule = pointsRuleEntity.Remark ?? pointsRule;
|
||||
}
|
||||
}
|
||||
|
||||
EventFeeConfigDto? feeConfigDto = null;
|
||||
if (feeConfig != null)
|
||||
{
|
||||
@ -472,6 +473,7 @@ public class EventClientController : IDynamicApiController
|
||||
RefundRule = refundRule,
|
||||
PointsRule = pointsRule,
|
||||
PointsRuleDetail = pointsRuleDetail,
|
||||
RefundRules = refundRules,
|
||||
IsRegistered = isRegistered,
|
||||
ProvinceName = provinceName,
|
||||
CityName = cityName,
|
||||
@ -945,18 +947,17 @@ public class EventClientController : IDynamicApiController
|
||||
var order = await _orderRepository.GetFirstAsync(x => x.RegistrationId == registrationId && x.OrderType == 1);
|
||||
if (order != null)
|
||||
{
|
||||
refundAmount = await CalculateRefundAmount(order.ActualAmount, reg.MatchStart);
|
||||
refundAmount = await CalculateRefundAmount(order.ActualAmount, reg.MatchStart, reg.EventId);
|
||||
}
|
||||
|
||||
// 获取退款规则文本
|
||||
// 获取退款规则文本(从赛事快照获取)
|
||||
try
|
||||
{
|
||||
var refundConfigs = await _refundConfigService.GetList();
|
||||
var enabledConfigs = refundConfigs.Where(x => x.Status == Core.Enum.AvailabilityStatus.Enable).OrderBy(x => x.DayStart).ToList();
|
||||
if (enabledConfigs.Any())
|
||||
var snapshots = await _ruleSnapshotService.GetRefundRuleSnapshot(reg.EventId);
|
||||
if (snapshots.Any())
|
||||
{
|
||||
var ruleParts = new List<string>();
|
||||
foreach (var config in enabledConfigs)
|
||||
foreach (var config in snapshots)
|
||||
{
|
||||
if (config.DayEnd >= 999 || config.DayEnd >= int.MaxValue)
|
||||
{
|
||||
@ -1495,30 +1496,9 @@ public class EventClientController : IDynamicApiController
|
||||
/// <summary>
|
||||
/// 计算退款金额
|
||||
/// </summary>
|
||||
private async Task<decimal> CalculateRefundAmount(decimal totalAmount, DateTime eventStartTime)
|
||||
private async Task<decimal> CalculateRefundAmount(decimal totalAmount, DateTime eventStartTime, long eventId)
|
||||
{
|
||||
var configs = await _refundConfigRepository.AsQueryable()
|
||||
.Where(x => x.Status == Core.Enum.AvailabilityStatus.Enable && !x.DeleteMark)
|
||||
.OrderBy(x => x.DayStart)
|
||||
.ToListAsync();
|
||||
|
||||
if (!configs.Any()) return totalAmount;
|
||||
|
||||
var daysRemaining = (eventStartTime - DateTime.Now).TotalDays;
|
||||
if (daysRemaining < 0) daysRemaining = 0;
|
||||
|
||||
var matchConfig = configs.FirstOrDefault(c =>
|
||||
daysRemaining >= c.DayStart &&
|
||||
(c.DayEnd == int.MaxValue ? true : daysRemaining < c.DayEnd)
|
||||
);
|
||||
|
||||
if (matchConfig != null)
|
||||
{
|
||||
var deductAmount = totalAmount * (matchConfig.DeductPercentage / 100m);
|
||||
return totalAmount - deductAmount;
|
||||
}
|
||||
|
||||
return totalAmount;
|
||||
return await _refundConfigService.CalculateRefundAmountByEvent(totalAmount, eventStartTime, eventId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -543,4 +543,61 @@ public class EventDetailOutput : AddEventInput
|
||||
/// 二维码URL
|
||||
/// </summary>
|
||||
public string? QrCodeUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则详情
|
||||
/// </summary>
|
||||
public PointsRuleDto? PointsRuleDetail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则详情列表
|
||||
/// </summary>
|
||||
public List<RefundRuleDto>? RefundRules { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则明细DTO
|
||||
/// </summary>
|
||||
public class PointsRuleDetailDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 起始名次
|
||||
/// </summary>
|
||||
public int StartRank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 截止名次
|
||||
/// </summary>
|
||||
public int EndRank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发放积分个数
|
||||
/// </summary>
|
||||
public int Points { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则DTO
|
||||
/// </summary>
|
||||
public class PointsRuleDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 积分规则名称
|
||||
/// </summary>
|
||||
public string RuleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参与积分(发放积分个数)
|
||||
/// </summary>
|
||||
public int? ParticipationPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名次积分规则明细
|
||||
/// </summary>
|
||||
public List<PointsRuleDetailDto>? Details { get; set; }
|
||||
}
|
||||
|
||||
13
YD_Event.Application/Event/Dtos/Mapper.cs
Normal file
13
YD_Event.Application/Event/Dtos/Mapper.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace YD_Event.Application.Event.Dtos;
|
||||
|
||||
public class Mapper : IRegister
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
// 配置EventInfo到EventDetailOutput的映射
|
||||
config.ForType<Core.Entities.EventInfo, EventDetailOutput>();
|
||||
|
||||
// 配置EventInfo到UserEventDetailOutput的映射
|
||||
config.ForType<Core.Entities.EventInfo, UserEventDetailOutput>();
|
||||
}
|
||||
}
|
||||
@ -295,3 +295,34 @@ public class BatchPaymentAuditInput
|
||||
/// </summary>
|
||||
public string? ReviewRemark { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报名统计输出
|
||||
/// </summary>
|
||||
public class RegistrationStatsOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 报名总人数
|
||||
/// </summary>
|
||||
public int TotalParticipants { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 个人项目人数
|
||||
/// </summary>
|
||||
public int IndividualParticipants { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 团队项目队伍数
|
||||
/// </summary>
|
||||
public int TeamCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 团队项目人数
|
||||
/// </summary>
|
||||
public int TeamParticipants { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 待审核数量
|
||||
/// </summary>
|
||||
public int PendingReview { get; set; }
|
||||
}
|
||||
|
||||
88
YD_Event.Application/Event/Dtos/RuleSnapshotDtos.cs
Normal file
88
YD_Event.Application/Event/Dtos/RuleSnapshotDtos.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using YD_Event.Core.Enum;
|
||||
|
||||
namespace YD_Event.Application.Event.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则详情快照 DTO
|
||||
/// </summary>
|
||||
public class PointsRuleDetailSnapshotDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 起始名次
|
||||
/// </summary>
|
||||
public int StartRank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 截止名次
|
||||
/// </summary>
|
||||
public int EndRank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发放积分个数
|
||||
/// </summary>
|
||||
public int Points { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则快照 DTO
|
||||
/// </summary>
|
||||
public class PointsRuleSnapshotDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 积分规则 ID(快照时的 ID)
|
||||
/// </summary>
|
||||
public long PointsRuleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则名称
|
||||
/// </summary>
|
||||
public string RuleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参与积分(发放积分个数)
|
||||
/// </summary>
|
||||
public int? ParticipationPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的名次积分规则
|
||||
/// </summary>
|
||||
public List<PointsRuleDetailSnapshotDto> Details { get; set; } = new List<PointsRuleDetailSnapshotDto>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则快照 DTO
|
||||
/// </summary>
|
||||
public class RefundRuleSnapshotDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 退款配置 ID(快照时的 ID)
|
||||
/// </summary>
|
||||
public long RefundConfigId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 距离比赛开始天数(起)
|
||||
/// </summary>
|
||||
public int DayStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 距离比赛开始天数(止)
|
||||
/// </summary>
|
||||
public int DayEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扣除比例 (0-100)
|
||||
/// </summary>
|
||||
public decimal DeductPercentage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@ -668,4 +668,106 @@ public class EventRegistrationService : BaseService<EventRegistration>, ITransie
|
||||
PaymentTime = input.PaymentStatus == 1 ? now : x.PaymentTime
|
||||
}, x => input.Ids.Contains(x.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取报名统计数据
|
||||
/// </summary>
|
||||
[DisplayName("获取报名统计数据")]
|
||||
[HttpGet("stats/{eventId}")]
|
||||
public async Task<RegistrationStatsOutput> GetStats(long eventId)
|
||||
{
|
||||
var stats = new RegistrationStatsOutput();
|
||||
|
||||
// 获取赛事项目信息
|
||||
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));
|
||||
var eventProjectToProjectDict = eventProjects.ToDictionary(x => x.Id, x => x.ProjectId);
|
||||
var projectDict = projects.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// 统计符合条件的所有运动员(与赛事编排页面保持一致的筛选规则)
|
||||
var athletes = await _personRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||
.Where((p, r) => r.EventId == eventId
|
||||
// 线上支付只显示已支付(1),线下支付显示待审核(0)和已支付(1)
|
||||
&& ((r.PaymentMethod == 2 && r.PaymentStatus == 1) || (r.PaymentMethod == 1 && (r.PaymentStatus == 0 || r.PaymentStatus == 1)))
|
||||
&& !p.DeleteMark // 排除已删除的人员
|
||||
&& p.PersonType == PersonType.Athlete) // 只统计运动员
|
||||
.Select((p, r) => new
|
||||
{
|
||||
PersonId = p.Id,
|
||||
EventProjectId = p.ProjectId,
|
||||
GroupName = p.GroupName,
|
||||
TeamName = r.TeamName,
|
||||
RegistrationItemId = p.RegistrationItemId,
|
||||
UserId = p.UserId,
|
||||
RegistrationId = r.Id,
|
||||
PaymentMethod = r.PaymentMethod,
|
||||
PaymentStatus = r.PaymentStatus
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
if (!athletes.Any())
|
||||
{
|
||||
// 待审核数量:线下支付(1)且支付状态为0(待审核)
|
||||
var pendingRegistrations = await _repository.GetListAsync(x =>
|
||||
x.EventId == eventId && !x.DeleteMark && x.PaymentMethod == 1 && x.PaymentStatus == 0);
|
||||
stats.PendingReview = pendingRegistrations.Count;
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 计算总人数(所有符合条件的运动员)
|
||||
stats.TotalParticipants = athletes.Select(x => x.UserId > 0 ? x.UserId : x.PersonId).Distinct().Count();
|
||||
|
||||
// 分别计算个人项目和团队项目的统计数据
|
||||
var individualSet = new HashSet<long>();
|
||||
var teamSet = new HashSet<(long EventProjectId, string GroupName, string TeamName, long RegistrationItemId)>();
|
||||
var teamPersonSet = new HashSet<long>();
|
||||
|
||||
foreach (var athlete in athletes)
|
||||
{
|
||||
// 判断项目类型
|
||||
bool isIndividualProject = false;
|
||||
if (eventProjectToProjectDict.TryGetValue(athlete.EventProjectId, out var projectId) &&
|
||||
projectDict.TryGetValue(projectId, out var project))
|
||||
{
|
||||
isIndividualProject = YD_Event.Core.Extensions.ProjectTypeExtensions.IsIndividualProject(project);
|
||||
}
|
||||
|
||||
var personKey = athlete.UserId > 0 ? athlete.UserId : athlete.PersonId;
|
||||
|
||||
if (isIndividualProject)
|
||||
{
|
||||
// 个人项目:统计人数
|
||||
individualSet.Add(personKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 团队项目:统计团队数(与赛事编排一致,按 EventProjectId、GroupName、TeamName、RegistrationItemId 分组)
|
||||
if (!string.IsNullOrEmpty(athlete.TeamName))
|
||||
{
|
||||
teamSet.Add((
|
||||
athlete.EventProjectId,
|
||||
athlete.GroupName ?? "",
|
||||
athlete.TeamName,
|
||||
athlete.RegistrationItemId
|
||||
));
|
||||
}
|
||||
|
||||
// 团队项目人数
|
||||
teamPersonSet.Add(personKey);
|
||||
}
|
||||
}
|
||||
|
||||
stats.IndividualParticipants = individualSet.Count;
|
||||
stats.TeamCount = teamSet.Count;
|
||||
stats.TeamParticipants = teamPersonSet.Count;
|
||||
|
||||
// 待审核数量:线下支付(1)且支付状态为0(待审核)
|
||||
var pendingRegs = await _repository.GetListAsync(x =>
|
||||
x.EventId == eventId && !x.DeleteMark && x.PaymentMethod == 1 && x.PaymentStatus == 0);
|
||||
stats.PendingReview = pendingRegs.Count;
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
257
YD_Event.Application/Event/EventRuleSnapshotService.cs
Normal file
257
YD_Event.Application/Event/EventRuleSnapshotService.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using YD_Event.Application.Event.Dtos;
|
||||
using YD_Event.Core.Entities;
|
||||
using SqlSugar;
|
||||
|
||||
namespace YD_Event.Application.Event;
|
||||
|
||||
/// <summary>
|
||||
/// 赛事规则快照服务 - 管理积分规则和退款规则的快照
|
||||
/// </summary>
|
||||
public class EventRuleSnapshotService : ITransient
|
||||
{
|
||||
private readonly ISqlSugarRepository<EventInfo> _eventInfoRepository;
|
||||
private readonly ISqlSugarRepository<PointsRule> _pointsRuleRepository;
|
||||
private readonly ISqlSugarRepository<PointsRuleDetail> _pointsRuleDetailRepository;
|
||||
private readonly ISqlSugarRepository<RefundConfig> _refundConfigRepository;
|
||||
|
||||
// JSON 序列化选项,支持中文正常显示
|
||||
private static readonly System.Text.Json.JsonSerializerOptions _jsonOptions = new System.Text.Json.JsonSerializerOptions
|
||||
{
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
public EventRuleSnapshotService(
|
||||
ISqlSugarRepository<EventInfo> eventInfoRepository,
|
||||
ISqlSugarRepository<PointsRule> pointsRuleRepository,
|
||||
ISqlSugarRepository<PointsRuleDetail> pointsRuleDetailRepository,
|
||||
ISqlSugarRepository<RefundConfig> refundConfigRepository)
|
||||
{
|
||||
_eventInfoRepository = eventInfoRepository;
|
||||
_pointsRuleRepository = pointsRuleRepository;
|
||||
_pointsRuleDetailRepository = pointsRuleDetailRepository;
|
||||
_refundConfigRepository = refundConfigRepository;
|
||||
}
|
||||
|
||||
#region 积分规则快照
|
||||
|
||||
/// <summary>
|
||||
/// 保存积分规则快照到赛事
|
||||
/// </summary>
|
||||
/// <param name="eventId">赛事 ID</param>
|
||||
/// <param name="pointsRuleId">积分规则 ID</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("保存积分规则快照")]
|
||||
public async Task SavePointsRuleSnapshot(long eventId, long? pointsRuleId)
|
||||
{
|
||||
var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId);
|
||||
if (eventInfo == null)
|
||||
throw new InvalidOperationException("赛事不存在");
|
||||
|
||||
if (!pointsRuleId.HasValue || pointsRuleId.Value <= 0)
|
||||
{
|
||||
eventInfo.PointsRuleSnapshot = null;
|
||||
await _eventInfoRepository.UpdateAsync(eventInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
var pointsRule = await _pointsRuleRepository.GetByIdAsync(pointsRuleId.Value);
|
||||
if (pointsRule == null)
|
||||
throw new InvalidOperationException("积分规则不存在");
|
||||
|
||||
var details = await _pointsRuleDetailRepository.GetListAsync(x =>
|
||||
x.PointsRuleId == pointsRuleId.Value && !x.DeleteMark);
|
||||
|
||||
var snapshot = new PointsRuleSnapshotDto
|
||||
{
|
||||
PointsRuleId = pointsRule.Id,
|
||||
RuleName = pointsRule.RuleName,
|
||||
ParticipationPoints = pointsRule.ParticipationPoints,
|
||||
Remark = pointsRule.Remark,
|
||||
Details = details.Select(d => new PointsRuleDetailSnapshotDto
|
||||
{
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
eventInfo.PointsRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshot, _jsonOptions);
|
||||
await _eventInfoRepository.UpdateAsync(eventInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取赛事积分规则快照
|
||||
/// </summary>
|
||||
/// <param name="eventId">赛事 ID</param>
|
||||
/// <returns>积分规则快照,如果不存在则返回 null</returns>
|
||||
[DisplayName("获取积分规则快照")]
|
||||
public async Task<PointsRuleSnapshotDto?> GetPointsRuleSnapshot(long eventId)
|
||||
{
|
||||
var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId);
|
||||
if (eventInfo == null)
|
||||
throw new InvalidOperationException("赛事不存在");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(eventInfo.PointsRuleSnapshot))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return System.Text.Json.JsonSerializer.Deserialize<PointsRuleSnapshotDto>(eventInfo.PointsRuleSnapshot, _jsonOptions);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 退款规则快照
|
||||
|
||||
/// <summary>
|
||||
/// 保存退款规则快照到赛事
|
||||
/// </summary>
|
||||
/// <param name="eventId">赛事 ID</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("保存退款规则快照")]
|
||||
public async Task SaveRefundRuleSnapshot(long eventId)
|
||||
{
|
||||
var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId);
|
||||
if (eventInfo == null)
|
||||
throw new InvalidOperationException("赛事不存在");
|
||||
|
||||
var refundConfigs = await _refundConfigRepository.GetListAsync(x =>
|
||||
x.Status == Core.Enum.AvailabilityStatus.Enable && !x.DeleteMark);
|
||||
|
||||
if (!refundConfigs.Any())
|
||||
{
|
||||
eventInfo.RefundRuleSnapshot = null;
|
||||
await _eventInfoRepository.UpdateAsync(eventInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
var snapshots = refundConfigs.OrderBy(c => c.DayStart).Select(c => new RefundRuleSnapshotDto
|
||||
{
|
||||
RefundConfigId = c.Id,
|
||||
DayStart = c.DayStart,
|
||||
DayEnd = c.DayEnd,
|
||||
DeductPercentage = c.DeductPercentage,
|
||||
Remark = c.Remark
|
||||
}).ToList();
|
||||
|
||||
eventInfo.RefundRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshots, _jsonOptions);
|
||||
await _eventInfoRepository.UpdateAsync(eventInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取赛事退款规则快照
|
||||
/// </summary>
|
||||
/// <param name="eventId">赛事 ID</param>
|
||||
/// <returns>退款规则快照列表,如果不存在则返回空列表</returns>
|
||||
[DisplayName("获取退款规则快照")]
|
||||
public async Task<List<RefundRuleSnapshotDto>> GetRefundRuleSnapshot(long eventId)
|
||||
{
|
||||
var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId);
|
||||
if (eventInfo == null)
|
||||
throw new InvalidOperationException("赛事不存在");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(eventInfo.RefundRuleSnapshot))
|
||||
return new List<RefundRuleSnapshotDto>();
|
||||
|
||||
try
|
||||
{
|
||||
var snapshots = System.Text.Json.JsonSerializer.Deserialize<List<RefundRuleSnapshotDto>>(eventInfo.RefundRuleSnapshot, _jsonOptions);
|
||||
return snapshots ?? new List<RefundRuleSnapshotDto>();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new List<RefundRuleSnapshotDto>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 快捷方法
|
||||
|
||||
/// <summary>
|
||||
/// 同时保存积分规则和退款规则快照
|
||||
/// </summary>
|
||||
/// <param name="eventId">赛事 ID</param>
|
||||
/// <param name="pointsRuleId">积分规则 ID</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("保存所有规则快照")]
|
||||
public async Task SaveAllRuleSnapshots(long eventId, long? pointsRuleId)
|
||||
{
|
||||
await SavePointsRuleSnapshot(eventId, pointsRuleId);
|
||||
await SaveRefundRuleSnapshot(eventId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据赛事实体保存快照(用于创建/编辑时)
|
||||
/// </summary>
|
||||
/// <param name="eventInfo">赛事实体</param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("根据赛事实体保存快照")]
|
||||
public async Task SaveAllRuleSnapshots(EventInfo eventInfo)
|
||||
{
|
||||
if (eventInfo.PointsRuleId.HasValue && eventInfo.PointsRuleId.Value > 0)
|
||||
{
|
||||
var pointsRule = await _pointsRuleRepository.GetByIdAsync(eventInfo.PointsRuleId.Value);
|
||||
if (pointsRule != null)
|
||||
{
|
||||
var details = await _pointsRuleDetailRepository.GetListAsync(x =>
|
||||
x.PointsRuleId == eventInfo.PointsRuleId.Value && !x.DeleteMark);
|
||||
|
||||
var snapshot = new PointsRuleSnapshotDto
|
||||
{
|
||||
PointsRuleId = pointsRule.Id,
|
||||
RuleName = pointsRule.RuleName,
|
||||
ParticipationPoints = pointsRule.ParticipationPoints,
|
||||
Remark = pointsRule.Remark,
|
||||
Details = details.Select(d => new PointsRuleDetailSnapshotDto
|
||||
{
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
eventInfo.PointsRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshot, _jsonOptions);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eventInfo.PointsRuleSnapshot = null;
|
||||
}
|
||||
|
||||
var refundConfigs = await _refundConfigRepository.GetListAsync(x =>
|
||||
x.Status == Core.Enum.AvailabilityStatus.Enable && !x.DeleteMark);
|
||||
|
||||
if (refundConfigs.Any())
|
||||
{
|
||||
var snapshots = refundConfigs.OrderBy(c => c.DayStart).Select(c => new RefundRuleSnapshotDto
|
||||
{
|
||||
RefundConfigId = c.Id,
|
||||
DayStart = c.DayStart,
|
||||
DayEnd = c.DayEnd,
|
||||
DeductPercentage = c.DeductPercentage,
|
||||
Remark = c.Remark
|
||||
}).ToList();
|
||||
|
||||
eventInfo.RefundRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshots, _jsonOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventInfo.RefundRuleSnapshot = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -62,6 +62,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
private readonly CertificateGenerateService _certificateGenerateService;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly ILogger<EventScoreService> _logger;
|
||||
private readonly EventRuleSnapshotService _ruleSnapshotService;
|
||||
|
||||
public EventScoreService(
|
||||
ISqlSugarRepository<EventRegistrationPerson> personRepository,
|
||||
@ -82,7 +83,8 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
ISqlSugarRepository<MerchantCertification> merchantCertificationRepository,
|
||||
CertificateGenerateService certificateGenerateService,
|
||||
IIdGenerator idGenerator,
|
||||
ILogger<EventScoreService> logger) : base(resultRepository)
|
||||
ILogger<EventScoreService> logger,
|
||||
EventRuleSnapshotService ruleSnapshotService) : base(resultRepository)
|
||||
{
|
||||
_personRepository = personRepository;
|
||||
_resultRepository = resultRepository;
|
||||
@ -103,6 +105,7 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
_certificateGenerateService = certificateGenerateService;
|
||||
_idGenerator = idGenerator;
|
||||
_logger = logger;
|
||||
_ruleSnapshotService = ruleSnapshotService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1647,27 +1650,13 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
throw Oops.Bah("赛事不存在");
|
||||
}
|
||||
|
||||
if (!eventInfo.PointsRuleId.HasValue)
|
||||
// 从快照获取积分规则
|
||||
var pointsRuleSnapshot = await _ruleSnapshotService.GetPointsRuleSnapshot(input.EventId);
|
||||
if (pointsRuleSnapshot == null)
|
||||
{
|
||||
throw Oops.Bah("该赛事未配置积分规则");
|
||||
}
|
||||
|
||||
var pointsRule = await _pointsRuleRepository.GetByIdAsync(eventInfo.PointsRuleId.Value);
|
||||
if (pointsRule == null)
|
||||
{
|
||||
throw Oops.Bah("积分规则不存在");
|
||||
}
|
||||
|
||||
if (pointsRule.Status != AvailabilityStatus.Enable)
|
||||
{
|
||||
throw Oops.Bah("积分规则未启用");
|
||||
}
|
||||
|
||||
var ruleDetails = await _pointsRuleDetailRepository.AsQueryable()
|
||||
.Where(x => x.PointsRuleId == pointsRule.Id)
|
||||
.OrderBy(x => x.StartRank)
|
||||
.ToListAsync();
|
||||
|
||||
// 获取所有 EventProject 和对应的 Project 信息,用于判断项目类型
|
||||
var eventProjects = await _eventProjectRepository.AsQueryable()
|
||||
.Where(ep => ep.EventId == input.EventId)
|
||||
@ -1762,12 +1751,12 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
|
||||
int pointsToAward = 0;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
if (pointsRuleSnapshot.ParticipationPoints.HasValue && pointsRuleSnapshot.ParticipationPoints.Value > 0)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
pointsToAward += pointsRuleSnapshot.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => teamResult.Rank >= d.StartRank && teamResult.Rank <= d.EndRank);
|
||||
var matchingDetail = pointsRuleSnapshot.Details.FirstOrDefault(d => teamResult.Rank >= d.StartRank && teamResult.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
@ -1820,12 +1809,12 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
|
||||
int pointsToAward = 0;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
if (pointsRuleSnapshot.ParticipationPoints.HasValue && pointsRuleSnapshot.ParticipationPoints.Value > 0)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
pointsToAward += pointsRuleSnapshot.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => result.Rank >= d.StartRank && result.Rank <= d.EndRank);
|
||||
var matchingDetail = pointsRuleSnapshot.Details.FirstOrDefault(d => result.Rank >= d.StartRank && result.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
|
||||
@ -31,6 +31,7 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly YD_Event.Application.Menu.SysMenuService _sysMenuService;
|
||||
private readonly YD_Event.Application.Auth.AuthManager _authManager;
|
||||
private readonly EventRuleSnapshotService _ruleSnapshotService;
|
||||
|
||||
public EventService(
|
||||
ISqlSugarRepository<EventInfo> repository,
|
||||
@ -49,7 +50,8 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Merchant> merchantRepository,
|
||||
IIdGenerator idGenerator,
|
||||
YD_Event.Application.Menu.SysMenuService sysMenuService,
|
||||
YD_Event.Application.Auth.AuthManager authManager) : base(repository)
|
||||
YD_Event.Application.Auth.AuthManager authManager,
|
||||
EventRuleSnapshotService ruleSnapshotService) : base(repository)
|
||||
{
|
||||
_repository = repository;
|
||||
_unitRepository = unitRepository;
|
||||
@ -68,6 +70,7 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
_idGenerator = idGenerator;
|
||||
_sysMenuService = sysMenuService;
|
||||
_authManager = authManager;
|
||||
_ruleSnapshotService = ruleSnapshotService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -266,6 +269,37 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 获取积分规则和退款规则快照,并赋值到原有的规则DTO中
|
||||
var pointsRuleSnapshot = await _ruleSnapshotService.GetPointsRuleSnapshot(id);
|
||||
var refundRuleSnapshots = await _ruleSnapshotService.GetRefundRuleSnapshot(id);
|
||||
|
||||
if (pointsRuleSnapshot != null)
|
||||
{
|
||||
output.PointsRuleDetail = new PointsRuleDto
|
||||
{
|
||||
RuleName = pointsRuleSnapshot.RuleName,
|
||||
ParticipationPoints = pointsRuleSnapshot.ParticipationPoints,
|
||||
Remark = pointsRuleSnapshot.Remark,
|
||||
Details = pointsRuleSnapshot.Details.Select(d => new PointsRuleDetailDto
|
||||
{
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
if (refundRuleSnapshots != null && refundRuleSnapshots.Any())
|
||||
{
|
||||
output.RefundRules = refundRuleSnapshots.Select(r => new RefundRuleDto
|
||||
{
|
||||
DayStart = r.DayStart,
|
||||
DayEnd = r.DayEnd,
|
||||
DeductPercentage = r.DeductPercentage,
|
||||
Remark = r.Remark
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -363,6 +397,9 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
var now = DateTime.Now;
|
||||
eventInfo.EventStatus = EventStatusUpdateService.CalculateEventStatus(eventInfo, now);
|
||||
|
||||
// 保存规则快照
|
||||
await _ruleSnapshotService.SaveAllRuleSnapshots(eventInfo);
|
||||
|
||||
await _repository.InsertAsync(eventInfo);
|
||||
|
||||
// 1. 保存参与单位
|
||||
@ -526,6 +563,9 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
var now = DateTime.Now;
|
||||
eventInfo.EventStatus = EventStatusUpdateService.CalculateEventStatus(eventInfo, now);
|
||||
|
||||
// 保存规则快照
|
||||
await _ruleSnapshotService.SaveAllRuleSnapshots(eventInfo);
|
||||
|
||||
await _repository.UpdateAsync(eventInfo);
|
||||
|
||||
// 1. 更新参与单位
|
||||
@ -827,6 +867,9 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
if (eventInfo == null) throw new InvalidOperationException("赛事不存在");
|
||||
input.Adapt(eventInfo);
|
||||
eventInfo.UpdatedTime = DateTime.Now;
|
||||
|
||||
// 保存规则快照
|
||||
await _ruleSnapshotService.SaveAllRuleSnapshots(eventInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -840,6 +883,9 @@ public class EventService : BaseService<EventInfo>, ITransient
|
||||
var now = DateTime.Now;
|
||||
eventInfo.EventStatus = EventStatusUpdateService.CalculateEventStatus(eventInfo, now);
|
||||
|
||||
// 保存规则快照
|
||||
await _ruleSnapshotService.SaveAllRuleSnapshots(eventInfo);
|
||||
|
||||
await _repository.InsertAsync(eventInfo);
|
||||
}
|
||||
|
||||
|
||||
@ -2742,6 +2742,13 @@ public class UnifiedRegistrationService : ITransient
|
||||
return roundedRefundAmount;
|
||||
}
|
||||
|
||||
public async Task<decimal> CalculateRefundAmountAsync(decimal totalAmount, DateTime eventStartTime, long eventId)
|
||||
{
|
||||
var refundAmount = await _refundConfigService.CalculateRefundAmountByEvent(totalAmount, eventStartTime, eventId);
|
||||
var roundedRefundAmount = RoundUpToTwoDecimalPlaces(refundAmount);
|
||||
return roundedRefundAmount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一取消报名预览方法
|
||||
/// </summary>
|
||||
@ -2780,7 +2787,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
{
|
||||
var itemPersons = persons.Where(p => p.RegistrationItemId == item.Id && !p.DeleteMark).ToList();
|
||||
var itemOriginalAmount = item.UnitPrice * itemPersons.Count;
|
||||
var itemRefund = await CalculateRefundAmountAsync(itemOriginalAmount, eventInfo.MatchStartTime);
|
||||
var itemRefund = await CalculateRefundAmountAsync(itemOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
originalRefundableAmount += itemRefund;
|
||||
}
|
||||
}
|
||||
@ -2802,13 +2809,13 @@ public class UnifiedRegistrationService : ITransient
|
||||
// 剩余可退款的人数
|
||||
var remainingPersonCount = personGroups.Count;
|
||||
var remainingOriginalAmount = eventUnitPrice * remainingPersonCount;
|
||||
originalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||
originalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 定价(赛事)模式:使用传统方式计算
|
||||
var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
|
||||
originalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||
originalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
}
|
||||
|
||||
// 确保可退款金额不小于0
|
||||
@ -3054,7 +3061,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
{
|
||||
var itemPersons = persons.Where(p => p.RegistrationItemId == item.Id && !p.DeleteMark).ToList();
|
||||
var itemOriginalAmount = item.UnitPrice * itemPersons.Count;
|
||||
var itemRefund = await CalculateRefundAmountAsync(itemOriginalAmount, eventInfo.MatchStartTime);
|
||||
var itemRefund = await CalculateRefundAmountAsync(itemOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
remainingOriginalRefundableAmount += itemRefund;
|
||||
}
|
||||
}
|
||||
@ -3076,13 +3083,13 @@ public class UnifiedRegistrationService : ITransient
|
||||
// 剩余可退款的人数
|
||||
var remainingPersonCount = personGroups.Count;
|
||||
var remainingOriginalAmount = eventUnitPrice * remainingPersonCount;
|
||||
remainingOriginalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||
remainingOriginalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 定价(赛事)模式:使用传统方式计算
|
||||
var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
|
||||
remainingOriginalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||
remainingOriginalRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
}
|
||||
|
||||
// 按比例计算剩余可退款金额(基于实际支付金额)
|
||||
@ -3181,7 +3188,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
remainingOriginalTotal = remainingOriginalAmount;
|
||||
}
|
||||
|
||||
var fullRefundAmount = await CalculateRefundAmountAsync(remainingOriginalTotal, eventInfo.MatchStartTime);
|
||||
var fullRefundAmount = await CalculateRefundAmountAsync(remainingOriginalTotal, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
_logger.LogInformation("全部取消,退款金额={Amount}", fullRefundAmount);
|
||||
return fullRefundAmount;
|
||||
}
|
||||
@ -3231,7 +3238,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
}
|
||||
|
||||
// 取消了所有队员,按退款规则退款
|
||||
var fixedPriceRefundAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||
var fixedPriceRefundAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
_logger.LogInformation("定价赛事全部取消,按退款规则退款,金额={Amount}", fixedPriceRefundAmount);
|
||||
return fixedPriceRefundAmount;
|
||||
|
||||
@ -3292,7 +3299,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
// 计算本次取消的原始金额
|
||||
var unitPriceEventCancelAmount = eventUnitPrice * fullyCanceledPersonCount;
|
||||
// 直接对本次取消的原始金额应用退款规则
|
||||
var unitPriceEventFinalAmount = await CalculateRefundAmountAsync(unitPriceEventCancelAmount, eventInfo.MatchStartTime);
|
||||
var unitPriceEventFinalAmount = await CalculateRefundAmountAsync(unitPriceEventCancelAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
|
||||
_logger.LogInformation("单价(赛事)退款:完全取消所有项目的人数={CancelCount}, 赛事单价={UnitPrice}, 本次取消原始金额={CancelAmount}, 按规则退款金额={RefundAmount}",
|
||||
fullyCanceledPersonCount, eventUnitPrice, unitPriceEventCancelAmount, unitPriceEventFinalAmount);
|
||||
@ -3333,7 +3340,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
}
|
||||
|
||||
// 直接对本次取消的原始总金额应用退款规则
|
||||
var projectRefundAmount = await CalculateRefundAmountAsync(totalProjectCancelAmount, eventInfo.MatchStartTime);
|
||||
var projectRefundAmount = await CalculateRefundAmountAsync(totalProjectCancelAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
|
||||
_logger.LogInformation("单价(项目)退款:本次取消总原始金额={TotalCancelAmount}, 按规则退款金额={RefundAmount}",
|
||||
totalProjectCancelAmount, projectRefundAmount);
|
||||
|
||||
@ -69,6 +69,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
||||
private readonly ILogger<UserEventRegistrationService> _logger;
|
||||
private readonly OrderNoGeneratorService _orderNoGeneratorService;
|
||||
private readonly UnifiedRegistrationService _unifiedRegistrationService;
|
||||
private readonly EventRuleSnapshotService _ruleSnapshotService;
|
||||
|
||||
public UserEventRegistrationService(
|
||||
ISqlSugarRepository<EventInfo> eventRepository,
|
||||
@ -104,7 +105,8 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
||||
ISqlSugarRepository<EventRegistrationPayment> paymentRepository,
|
||||
ILogger<UserEventRegistrationService> logger,
|
||||
OrderNoGeneratorService orderNoGeneratorService,
|
||||
UnifiedRegistrationService unifiedRegistrationService)
|
||||
UnifiedRegistrationService unifiedRegistrationService,
|
||||
EventRuleSnapshotService ruleSnapshotService)
|
||||
{
|
||||
_eventRepository = eventRepository;
|
||||
_unitRepository = unitRepository;
|
||||
@ -140,6 +142,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
||||
_logger = logger;
|
||||
_orderNoGeneratorService = orderNoGeneratorService;
|
||||
_unifiedRegistrationService = unifiedRegistrationService;
|
||||
_ruleSnapshotService = ruleSnapshotService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -245,40 +248,30 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
||||
output.DistrictName = district?.DistrictName ?? "";
|
||||
}
|
||||
|
||||
if (eventInfo.PointsRuleId.HasValue)
|
||||
// 从快照获取积分规则
|
||||
var pointsRuleSnapshot = await _ruleSnapshotService.GetPointsRuleSnapshot(id);
|
||||
if (pointsRuleSnapshot != null)
|
||||
{
|
||||
var rule = await _pointsRuleRepository.GetByIdAsync(eventInfo.PointsRuleId.Value);
|
||||
output.PointsRuleName = rule?.RuleName ?? "";
|
||||
output.PointsRuleName = pointsRuleSnapshot.RuleName ?? "";
|
||||
|
||||
if (rule != null)
|
||||
output.PointsRuleDetail = new YD_Event.Application.Client.Dtos.PointsRuleDto
|
||||
{
|
||||
var details = await _pointsRuleDetailRepository.AsQueryable()
|
||||
.Where(d => d.PointsRuleId == rule.Id && !d.DeleteMark)
|
||||
.OrderBy(d => d.StartRank)
|
||||
.ToListAsync();
|
||||
|
||||
output.PointsRuleDetail = new YD_Event.Application.Client.Dtos.PointsRuleDto
|
||||
RuleName = pointsRuleSnapshot.RuleName,
|
||||
ParticipationPoints = pointsRuleSnapshot.ParticipationPoints,
|
||||
Remark = pointsRuleSnapshot.Remark,
|
||||
Details = pointsRuleSnapshot.Details.Select(d => new YD_Event.Application.Client.Dtos.PointsRuleDetailDto
|
||||
{
|
||||
RuleName = rule.RuleName,
|
||||
ParticipationPoints = rule.ParticipationPoints,
|
||||
Remark = rule.Remark,
|
||||
Details = details.Select(d => new YD_Event.Application.Client.Dtos.PointsRuleDetailDto
|
||||
{
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
StartRank = d.StartRank,
|
||||
EndRank = d.EndRank,
|
||||
Points = d.Points
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
// 获取退款规则
|
||||
var refundConfigs = await _refundConfigRepository.AsQueryable()
|
||||
.Where(c => c.Status == AvailabilityStatus.Enable && !c.DeleteMark)
|
||||
.OrderBy(c => c.DayStart)
|
||||
.ToListAsync();
|
||||
// 从快照获取退款规则
|
||||
var refundRuleSnapshots = await _ruleSnapshotService.GetRefundRuleSnapshot(id);
|
||||
|
||||
output.RefundRules = refundConfigs.Select(c => new YD_Event.Application.Event.Dtos.RefundRuleDto
|
||||
output.RefundRules = refundRuleSnapshots.Select(c => new YD_Event.Application.Event.Dtos.RefundRuleDto
|
||||
{
|
||||
DayStart = c.DayStart,
|
||||
DayEnd = c.DayEnd,
|
||||
|
||||
@ -527,7 +527,7 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
|
||||
|
||||
_logger.LogInformation("调用统一退款金额计算:订单ID={OrderId}, 总金额={TotalAmount}, 赛事开始时间={EventStartTime}",
|
||||
orderId, order.ActualAmount, eventInfo.MatchStartTime);
|
||||
return await _unifiedRegistrationService.CalculateRefundAmountAsync(order.ActualAmount, eventInfo.MatchStartTime);
|
||||
return await _unifiedRegistrationService.CalculateRefundAmountAsync(order.ActualAmount, eventInfo.MatchStartTime, eventInfo.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using YD_Event.Application.Refund.Dtos;
|
||||
using YD_Event.Core.Entities;
|
||||
|
||||
using YD_Event.Application.Event;
|
||||
|
||||
namespace YD_Event.Application.Refund;
|
||||
|
||||
/// <summary>
|
||||
@ -11,15 +13,18 @@ public class RefundConfigService : BaseService<RefundConfig>, ITransient
|
||||
private readonly ISqlSugarRepository<RefundConfig> _repository;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly IEasyCachingProvider _easyCachingProvider;
|
||||
private readonly EventRuleSnapshotService _ruleSnapshotService;
|
||||
private const string CacheKey = "RefundConfig:List";
|
||||
|
||||
public RefundConfigService(ISqlSugarRepository<RefundConfig> repository,
|
||||
IIdGenerator idGenerator,
|
||||
IEasyCachingProvider easyCachingProvider) : base(repository)
|
||||
IEasyCachingProvider easyCachingProvider,
|
||||
EventRuleSnapshotService ruleSnapshotService) : base(repository)
|
||||
{
|
||||
_repository = repository;
|
||||
_idGenerator = idGenerator;
|
||||
_easyCachingProvider = easyCachingProvider;
|
||||
_ruleSnapshotService = ruleSnapshotService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -172,4 +177,37 @@ public class RefundConfigService : BaseService<RefundConfig>, ITransient
|
||||
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据赛事快照计算退款金额
|
||||
/// </summary>
|
||||
/// <param name="totalAmount">总金额</param>
|
||||
/// <param name="eventStartTime">赛事开始时间</param>
|
||||
/// <param name="eventId">赛事ID</param>
|
||||
/// <returns>应退金额</returns>
|
||||
[NonAction]
|
||||
public async Task<decimal> CalculateRefundAmountByEvent(decimal totalAmount, DateTime eventStartTime, long eventId)
|
||||
{
|
||||
// 从快照获取退款规则
|
||||
var snapshots = await _ruleSnapshotService.GetRefundRuleSnapshot(eventId);
|
||||
|
||||
if (!snapshots.Any()) return totalAmount;
|
||||
|
||||
var daysRemaining = (eventStartTime - DateTime.Now).TotalDays;
|
||||
if (daysRemaining < 0) daysRemaining = 0;
|
||||
|
||||
// 查找匹配的规则
|
||||
var matchConfig = snapshots.FirstOrDefault(c =>
|
||||
daysRemaining >= c.DayStart &&
|
||||
(c.DayEnd == int.MaxValue ? true : daysRemaining < c.DayEnd)
|
||||
);
|
||||
|
||||
if (matchConfig != null)
|
||||
{
|
||||
var deductAmount = totalAmount * (matchConfig.DeductPercentage / 100m);
|
||||
return totalAmount - deductAmount;
|
||||
}
|
||||
|
||||
return totalAmount;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2009,6 +2009,46 @@
|
||||
名次积分规则明细
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.RefundRuleDto">
|
||||
<summary>
|
||||
退款规则DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.RefundRuleDto.DayStart">
|
||||
<summary>
|
||||
距离比赛开始天数(起)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.RefundRuleDto.DayEnd">
|
||||
<summary>
|
||||
距离比赛开始天数(止)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.RefundRuleDto.DeductPercentage">
|
||||
<summary>
|
||||
扣除比例(%)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.RefundRuleDto.Remark">
|
||||
<summary>
|
||||
退款备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.PointsRuleDetailSnapshotDto">
|
||||
<summary>
|
||||
积分规则明细快照DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.PointsRuleSnapshotDto">
|
||||
<summary>
|
||||
积分规则快照DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.RefundRuleSnapshotDto">
|
||||
<summary>
|
||||
退款规则快照DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.EventDetailDto">
|
||||
<summary>
|
||||
赛事详情DTO
|
||||
@ -2084,6 +2124,11 @@
|
||||
积分规则详情
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventDetailDto.RefundRules">
|
||||
<summary>
|
||||
退款规则详情列表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventDetailDto.IndividualProjectLimit">
|
||||
<summary>
|
||||
个人项目限报数量
|
||||
@ -3733,7 +3778,7 @@
|
||||
<param name="input">报名限制检查输入参数</param>
|
||||
<returns>报名限制检查结果</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.EventClientController.CalculateRefundAmount(System.Decimal,System.DateTime)">
|
||||
<member name="M:YD_Event.Application.Client.EventClientController.CalculateRefundAmount(System.Decimal,System.DateTime,System.Int64)">
|
||||
<summary>
|
||||
计算退款金额
|
||||
</summary>
|
||||
@ -4915,6 +4960,61 @@
|
||||
二维码URL
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.EventDetailOutput.PointsRuleDetail">
|
||||
<summary>
|
||||
积分规则详情
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.EventDetailOutput.RefundRules">
|
||||
<summary>
|
||||
退款规则详情列表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.PointsRuleDetailDto">
|
||||
<summary>
|
||||
积分规则明细DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailDto.StartRank">
|
||||
<summary>
|
||||
起始名次
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailDto.EndRank">
|
||||
<summary>
|
||||
截止名次
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailDto.Points">
|
||||
<summary>
|
||||
发放积分个数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.PointsRuleDto">
|
||||
<summary>
|
||||
积分规则DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDto.RuleName">
|
||||
<summary>
|
||||
积分规则名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDto.ParticipationPoints">
|
||||
<summary>
|
||||
参与积分(发放积分个数)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDto.Remark">
|
||||
<summary>
|
||||
备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDto.Details">
|
||||
<summary>
|
||||
名次积分规则明细
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.EventRecordPageInput">
|
||||
<summary>
|
||||
赛事记录分页查询输入
|
||||
@ -6392,6 +6492,116 @@
|
||||
审核备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.RegistrationStatsOutput">
|
||||
<summary>
|
||||
报名统计输出
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationStatsOutput.TotalParticipants">
|
||||
<summary>
|
||||
报名总人数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationStatsOutput.IndividualParticipants">
|
||||
<summary>
|
||||
个人项目人数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationStatsOutput.TeamCount">
|
||||
<summary>
|
||||
团队项目队伍数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationStatsOutput.TeamParticipants">
|
||||
<summary>
|
||||
团队项目人数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationStatsOutput.PendingReview">
|
||||
<summary>
|
||||
待审核数量
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.PointsRuleDetailSnapshotDto">
|
||||
<summary>
|
||||
积分规则详情快照 DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailSnapshotDto.StartRank">
|
||||
<summary>
|
||||
起始名次
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailSnapshotDto.EndRank">
|
||||
<summary>
|
||||
截止名次
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleDetailSnapshotDto.Points">
|
||||
<summary>
|
||||
发放积分个数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto">
|
||||
<summary>
|
||||
积分规则快照 DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto.PointsRuleId">
|
||||
<summary>
|
||||
积分规则 ID(快照时的 ID)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto.RuleName">
|
||||
<summary>
|
||||
积分规则名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto.ParticipationPoints">
|
||||
<summary>
|
||||
参与积分(发放积分个数)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto.Remark">
|
||||
<summary>
|
||||
备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.PointsRuleSnapshotDto.Details">
|
||||
<summary>
|
||||
关联的名次积分规则
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto">
|
||||
<summary>
|
||||
退款规则快照 DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto.RefundConfigId">
|
||||
<summary>
|
||||
退款配置 ID(快照时的 ID)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto.DayStart">
|
||||
<summary>
|
||||
距离比赛开始天数(起)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto.DayEnd">
|
||||
<summary>
|
||||
距离比赛开始天数(止)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto.DeductPercentage">
|
||||
<summary>
|
||||
扣除比例 (0-100)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.RefundRuleSnapshotDto.Remark">
|
||||
<summary>
|
||||
备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.Dtos.ScoreQueryInput">
|
||||
<summary>
|
||||
成绩查询输入
|
||||
@ -7258,6 +7468,11 @@
|
||||
素材备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.UserEventDetailOutput.MaterialUploadStartTime">
|
||||
<summary>
|
||||
素材上传开始时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Event.Dtos.UserEventDetailOutput.MaterialUploadEndTime">
|
||||
<summary>
|
||||
素材上传截止时间
|
||||
@ -8563,6 +8778,60 @@
|
||||
批量支付审核
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRegistrationService.GetStats(System.Int64)">
|
||||
<summary>
|
||||
获取报名统计数据
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.EventRuleSnapshotService">
|
||||
<summary>
|
||||
赛事规则快照服务 - 管理积分规则和退款规则的快照
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.SavePointsRuleSnapshot(System.Int64,System.Nullable{System.Int64})">
|
||||
<summary>
|
||||
保存积分规则快照到赛事
|
||||
</summary>
|
||||
<param name="eventId">赛事 ID</param>
|
||||
<param name="pointsRuleId">积分规则 ID</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.GetPointsRuleSnapshot(System.Int64)">
|
||||
<summary>
|
||||
获取赛事积分规则快照
|
||||
</summary>
|
||||
<param name="eventId">赛事 ID</param>
|
||||
<returns>积分规则快照,如果不存在则返回 null</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.SaveRefundRuleSnapshot(System.Int64)">
|
||||
<summary>
|
||||
保存退款规则快照到赛事
|
||||
</summary>
|
||||
<param name="eventId">赛事 ID</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.GetRefundRuleSnapshot(System.Int64)">
|
||||
<summary>
|
||||
获取赛事退款规则快照
|
||||
</summary>
|
||||
<param name="eventId">赛事 ID</param>
|
||||
<returns>退款规则快照列表,如果不存在则返回空列表</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.SaveAllRuleSnapshots(System.Int64,System.Nullable{System.Int64})">
|
||||
<summary>
|
||||
同时保存积分规则和退款规则快照
|
||||
</summary>
|
||||
<param name="eventId">赛事 ID</param>
|
||||
<param name="pointsRuleId">积分规则 ID</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Event.EventRuleSnapshotService.SaveAllRuleSnapshots(YD_Event.Core.Entities.EventInfo)">
|
||||
<summary>
|
||||
根据赛事实体保存快照(用于创建/编辑时)
|
||||
</summary>
|
||||
<param name="eventInfo">赛事实体</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Event.EventScoreService">
|
||||
<summary>
|
||||
成绩与证书管理
|
||||
@ -9981,9 +10250,22 @@
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Menu.SysMenuService.IsCurrentUserAdminAsync">
|
||||
<summary>
|
||||
检查当前登录用户是否是管理员
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Menu.SysMenuService.FilterMenus(System.Collections.Generic.List{YD_Event.Core.Entities.SysMenu},System.Collections.Generic.List{System.Int64})">
|
||||
<summary>
|
||||
过滤菜单,移除配置中指定的菜单ID及其子菜单
|
||||
</summary>
|
||||
<param name="menus">菜单列表</param>
|
||||
<param name="hiddenMenuIds">需要隐藏的菜单ID列表</param>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Menu.SysMenuService.TreeMenuButton">
|
||||
<summary>
|
||||
菜单按钮树
|
||||
菜单按钮树 - 仅在角色管理页面使用此接口时应用隐藏规则
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
@ -11990,6 +12272,15 @@
|
||||
<param name="eventStartTime">赛事开始时间</param>
|
||||
<returns>应退金额</returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Refund.RefundConfigService.CalculateRefundAmountByEvent(System.Decimal,System.DateTime,System.Int64)">
|
||||
<summary>
|
||||
根据赛事快照计算退款金额
|
||||
</summary>
|
||||
<param name="totalAmount">总金额</param>
|
||||
<param name="eventStartTime">赛事开始时间</param>
|
||||
<param name="eventId">赛事ID</param>
|
||||
<returns>应退金额</returns>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Region.Dtos.RegionPageInput">
|
||||
<summary>
|
||||
区域分页查询输入
|
||||
|
||||
@ -60,11 +60,23 @@ public class EventInfo : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime
|
||||
public long? PointsRuleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分发放规则(导航属性)
|
||||
/// 积分规则(导航属性)
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public PointsRule? PointsRule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分规则快照(JSON格式,保存创建/编辑赛事时的积分规则)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
|
||||
public string? PointsRuleSnapshot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退款规则快照(JSON格式,保存创建/编辑赛事时的退款规则)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
|
||||
public string? RefundRuleSnapshot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报名开始时间
|
||||
/// </summary>
|
||||
|
||||
@ -1334,7 +1334,17 @@
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventInfo.PointsRule">
|
||||
<summary>
|
||||
积分发放规则(导航属性)
|
||||
积分规则(导航属性)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventInfo.PointsRuleSnapshot">
|
||||
<summary>
|
||||
积分规则快照(JSON格式,保存创建/编辑赛事时的积分规则)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventInfo.RefundRuleSnapshot">
|
||||
<summary>
|
||||
退款规则快照(JSON格式,保存创建/编辑赛事时的退款规则)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Entities.EventInfo.RegistrationStartTime">
|
||||
@ -5861,6 +5871,11 @@
|
||||
单位用户角色ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Core.Options.RoleOptions.HiddenMenuIds">
|
||||
<summary>
|
||||
需要对非管理员用户隐藏的菜单ID列表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Core.Options.SmsOptions">
|
||||
<summary>
|
||||
短信配置选项
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user