diff --git a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs
index 2ceebcb..a824947 100644
--- a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs
+++ b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs
@@ -225,6 +225,11 @@ public class CancelPreviewOutput
///
public decimal RefundableAmount { get; set; }
+ ///
+ /// 历史已退款金额
+ ///
+ public decimal RefundedAmount { get; set; }
+
///
/// 当前选择的退款金额(动态计算)
///
diff --git a/YD_Event.Application/Event/EventArrangementService.cs b/YD_Event.Application/Event/EventArrangementService.cs
index bde6ea7..b46eb3b 100644
--- a/YD_Event.Application/Event/EventArrangementService.cs
+++ b/YD_Event.Application/Event/EventArrangementService.cs
@@ -319,29 +319,59 @@ namespace YD_Event.Application.Event;
// 计算项目总时长(在查询前计算,避免在SQL中使用C#方法)
int projTotalDuration = proj.GetTotalDurationInSeconds();
- // 获取参赛人员,并关联用户和单位认证信息
- var persons = await _personRepository.AsQueryable()
+ // 第一步:先查询主要数据和相关的 MerchantCertificationId
+ var basicPersons = await _personRepository.AsQueryable()
.InnerJoin((p, r) => p.RegistrationId == r.Id)
- .LeftJoin((p, r, m) => r.MerchantCertificationId == m.Id)
- .Where((p, r, m) => p.ProjectId == eventProj.Id
+ .Where((p, r) => p.ProjectId == eventProj.Id
&& r.PaymentStatus != 4
&& !p.DeleteMark
&& p.PersonType == PersonType.Athlete)
.OrderBy(p => p.GroupName)
.OrderBy(p => p.Id)
- .Select((p, r, m) => new {
- Id = p.Id, // 添加 Id 属性
+ .Select((p, r) => new {
+ Id = p.Id,
RegistrationItemId = p.RegistrationItemId,
p.UserId,
p.Name,
p.GroupName,
r.TeamName,
- MerchantName = m.MerchantName ?? "",
- m.AuditStatus,
+ r.MerchantCertificationId,
Duration = projTotalDuration
})
.ToListAsync();
+ // 第二步:收集所有需要查询的 MerchantCertificationId
+ var merchantCertIds = basicPersons
+ .Where(x => x.MerchantCertificationId.HasValue)
+ .Select(x => x.MerchantCertificationId.Value)
+ .Distinct()
+ .ToList();
+
+ // 第三步:批量查询 MerchantCertification
+ Dictionary merchantDict = new Dictionary();
+ if (merchantCertIds.Any())
+ {
+ var merchants = await _merchantCertificationRepository.GetListAsync(x => merchantCertIds.Contains(x.Id));
+ merchantDict = merchants.ToDictionary(x => x.Id, x => x);
+ }
+
+ // 第四步:在内存中合并数据
+ var persons = basicPersons.Select(bp => new {
+ bp.Id,
+ bp.RegistrationItemId,
+ bp.UserId,
+ bp.Name,
+ bp.GroupName,
+ bp.TeamName,
+ MerchantName = bp.MerchantCertificationId.HasValue && merchantDict.ContainsKey(bp.MerchantCertificationId.Value)
+ ? merchantDict[bp.MerchantCertificationId.Value].MerchantName
+ : null,
+ AuditStatus = bp.MerchantCertificationId.HasValue && merchantDict.ContainsKey(bp.MerchantCertificationId.Value)
+ ? merchantDict[bp.MerchantCertificationId.Value].AuditStatus
+ : (AuditStatus?)null,
+ bp.Duration
+ }).ToList();
+
if (!persons.Any()) continue;
// 计算项目总时长
@@ -471,7 +501,14 @@ namespace YD_Event.Application.Event;
var teamNameProp = personData.GetType().GetProperty("TeamName");
string? merchantName = merchantNameProp?.GetValue(personData) as string;
- AuditStatus? auditStatus = auditStatusProp?.GetValue(personData) as AuditStatus?;
+ var auditStatusValue = auditStatusProp?.GetValue(personData);
+ AuditStatus? auditStatus = null;
+
+ if (auditStatusValue != null && auditStatusValue is AuditStatus status)
+ {
+ auditStatus = status;
+ }
+
string? teamName = teamNameProp?.GetValue(personData) as string;
// 优先使用认证通过的单位名称
diff --git a/YD_Event.Application/Event/UnifiedRegistrationService.cs b/YD_Event.Application/Event/UnifiedRegistrationService.cs
index 3187add..c34dca5 100644
--- a/YD_Event.Application/Event/UnifiedRegistrationService.cs
+++ b/YD_Event.Application/Event/UnifiedRegistrationService.cs
@@ -2468,10 +2468,21 @@ public class UnifiedRegistrationService : ITransient
var items = await _db.Queryable().Where(x => x.RegistrationId == registrationId).ToListAsync();
var persons = await _registrationPersonRepository.GetListAsync(x => x.RegistrationId == registrationId);
- var refundableAmount = await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime);
+ // 查询历史已退款金额
+ var historyRefunds = await _refundRecordRepository.GetListAsync(x => x.RegistrationId == registrationId && x.RefundStatus == 1);
+ var refundedAmount = historyRefunds.Sum(x => x.RefundAmount);
+
+ // 计算剩余未退款的原始金额
+ var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
+
+ // 基于剩余金额计算可退款金额
+ var refundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
+
+ // 确保可退款金额不小于0
+ refundableAmount = Math.Max(0, refundableAmount);
- _logger.LogInformation("统一取消报名预览:报名ID={RegistrationId}, 赛事名称={EventName}, 实际支付={ActualAmount}, 可退款={RefundAmount}, 支付方式={PaymentMethod}",
- registrationId, eventInfo?.EventName, registration.TotalAmount, refundableAmount, registration.PaymentMethod);
+ _logger.LogInformation("统一取消报名预览:报名ID={RegistrationId}, 赛事名称={EventName}, 实际支付={ActualAmount}, 已退款={RefundedAmount}, 剩余可退款={RefundAmount}, 支付方式={PaymentMethod}",
+ registrationId, eventInfo?.EventName, registration.TotalAmount, refundedAmount, refundableAmount, registration.PaymentMethod);
// 获取组别信息(年龄和性别限制)
var groupIds = items.Where(x => x.EventProjectGroupId.HasValue).Select(x => x.EventProjectGroupId.Value).Distinct().ToList();
@@ -2501,6 +2512,7 @@ public class UnifiedRegistrationService : ITransient
ChargeMode = (int)eventInfo.ChargeMode,
ActualPaidAmount = registration.TotalAmount,
RefundableAmount = refundableAmount,
+ RefundedAmount = refundedAmount,
CurrentRefundAmount = refundableAmount,
PaymentMethod = registration.PaymentMethod,
PaymentStatus = registration.PaymentStatus,
@@ -2669,15 +2681,28 @@ public class UnifiedRegistrationService : ITransient
return 0;
}
+ // 查询历史已退款金额
+ var historyRefunds = await _refundRecordRepository.GetListAsync(x => x.RegistrationId == registration.Id && x.RefundStatus == 1);
+ var refundedAmount = historyRefunds.Sum(x => x.RefundAmount);
+
+ // 计算剩余的原始未退款金额
+ var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
+
+ // 如果没有剩余可退,直接返回0
+ if (remainingOriginalAmount <= 0)
+ {
+ return 0;
+ }
+
// 全部取消
if (input.CancelType == 0)
{
- return await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime);
+ return await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
}
// 部分取消
- var baseRefundAmount = await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime);
- var refundRatio = registration.TotalAmount > 0 ? baseRefundAmount / registration.TotalAmount : 1;
+ var baseRefundAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
+ var refundRatio = remainingOriginalAmount > 0 ? baseRefundAmount / remainingOriginalAmount : 1;
var cancelMemberIds = input.PersonIds ?? new List();
var cancelTeams = input.CancelTeams ?? new List();
@@ -2712,7 +2737,9 @@ public class UnifiedRegistrationService : ITransient
return baseRefundAmount;
}
// 否则,按人数比例退款
- return baseRefundAmount * (decimal)cancelTeamMemberCount / persons.Count;
+ var fixedPriceCalculated = baseRefundAmount * (decimal)cancelTeamMemberCount / persons.Count;
+ // 确保不超过剩余可退款金额
+ return Math.Min(fixedPriceCalculated, baseRefundAmount);
case ChargeMode.UnitPriceEvent:
// 单价(赛事):按取消人数计算
@@ -2732,8 +2759,10 @@ public class UnifiedRegistrationService : ITransient
}
var cancelCount = allCancelMemberIds.Count;
- var unitPrice = persons.Count > 0 ? registration.TotalAmount / persons.Count : 0;
- return unitPrice * cancelCount * refundRatio;
+ var unitPrice = persons.Count > 0 ? remainingOriginalAmount / persons.Count : 0;
+ var calculatedAmount = unitPrice * cancelCount * refundRatio;
+ // 确保不超过剩余可退款金额
+ return Math.Min(calculatedAmount, baseRefundAmount);
case ChargeMode.UnitPriceProject:
// 单价(项目):按每个项目的人数计算
@@ -2766,7 +2795,9 @@ public class UnifiedRegistrationService : ITransient
}
}
- return totalCancelAmount * refundRatio;
+ var projectCalculatedAmount = totalCancelAmount * refundRatio;
+ // 确保不超过剩余可退款金额
+ return Math.Min(projectCalculatedAmount, baseRefundAmount);
default:
return 0;
diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml
index fc3bd45..7a1ba40 100644
--- a/YD_Event.Application/YD_Event.Application.xml
+++ b/YD_Event.Application/YD_Event.Application.xml
@@ -5034,6 +5034,11 @@
可退款金额(全部取消时)
+
+
+ 历史已退款金额
+
+
当前选择的退款金额(动态计算)
diff --git a/YD_Event.Application/applicationsettings.json b/YD_Event.Application/applicationsettings.json
index d2c81fb..8c3cdc6 100644
--- a/YD_Event.Application/applicationsettings.json
+++ b/YD_Event.Application/applicationsettings.json
@@ -53,7 +53,7 @@
"SleepMs": 300,
"dbconfig": {
"ConnectionStrings": [
- "8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=7,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false",
+ "8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=7,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false"
//"8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=8,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false"
],
//"Sentinels": [