diff --git a/YD_Event.Application/Api/ApiService.cs b/YD_Event.Application/Api/ApiService.cs index ea07c8e..0ab70ff 100644 --- a/YD_Event.Application/Api/ApiService.cs +++ b/YD_Event.Application/Api/ApiService.cs @@ -1,4 +1,4 @@ -using Furion.HttpRemote; +using Furion.HttpRemote; namespace YD_Event.Application; @@ -20,11 +20,10 @@ public class ApiService : IScoped { var httpRemoteService = App.GetRequiredService(); var dto = await httpRemoteService.GetAsAsync($"{BaseUrl}/api/min"); - //var dto = await $"{BaseUrl}/api/min".SetQueries(new { t = content }).GetAsAsync(); return dto.Success && dto.Num > 0; } - catch (Exception e) + catch (Exception) { return false; } diff --git a/YD_Event.Application/Client/Dtos/EventClientDtos.cs b/YD_Event.Application/Client/Dtos/EventClientDtos.cs index 91e1bb0..b0aa3e6 100644 --- a/YD_Event.Application/Client/Dtos/EventClientDtos.cs +++ b/YD_Event.Application/Client/Dtos/EventClientDtos.cs @@ -726,11 +726,6 @@ public class MyEventListDto /// public string CoverImage { get; set; } - /// - /// 报名状态 - /// - public int RegistrationStatus { get; set; } - /// /// 支付状态 /// @@ -802,11 +797,6 @@ public class RegistrationDetailDto /// public EventStatus EventStatus { get; set; } - /// - /// 报名状态 - /// - public int RegistrationStatus { get; set; } - /// /// 支付状态 /// @@ -910,11 +900,6 @@ public class RegistrationStatusDto /// public long RegistrationId { get; set; } - /// - /// 报名状态 - /// - public int RegistrationStatus { get; set; } - /// /// 支付状态 /// diff --git a/YD_Event.Application/Client/EventClientController.cs b/YD_Event.Application/Client/EventClientController.cs index 6e8d555..cfe4c4b 100644 --- a/YD_Event.Application/Client/EventClientController.cs +++ b/YD_Event.Application/Client/EventClientController.cs @@ -230,7 +230,7 @@ public class EventClientController : IDynamicApiController { var userId = GetCurrentUserId(); isRegistered = await _registrationRepository.IsAnyAsync(r => - r.EventId == id && r.CreatedUserId == userId && r.RegistrationStatus != 4 && r.PaymentStatus == 1); + r.EventId == id && r.CreatedUserId == userId && r.PaymentStatus != 4 && r.PaymentStatus == 1); } catch { @@ -583,7 +583,7 @@ public class EventClientController : IDynamicApiController // 2. 校验重复报名 - 如果已有未取消的报名记录,直接返回现有记录ID var existingRegistration = await _registrationRepository.GetFirstAsync( - r => r.EventId == input.EventId && r.CreatedUserId == userId && r.RegistrationStatus != 4); // 4=已取消 + r => r.EventId == input.EventId && r.CreatedUserId == userId && r.PaymentStatus != 4); // 4=已取消 if (existingRegistration != null) { @@ -634,7 +634,7 @@ public class EventClientController : IDynamicApiController { var currentCount = await _registrationItemRepository.AsQueryable() .InnerJoin((ri, r) => ri.RegistrationId == r.Id) - .Where((ri, r) => ri.ProjectId == item.ProjectId && r.RegistrationStatus != 4) + .Where((ri, r) => ri.ProjectId == item.ProjectId && r.PaymentStatus != 4) .CountAsync(); if (currentCount >= projectLimit.LimitCount) @@ -679,7 +679,6 @@ public class EventClientController : IDynamicApiController TeamName = input.RegistrationMode == 2 ? input.TeamName : null, ContactName = input.ContactName, ContactPhone = input.ContactPhone, - RegistrationStatus = 0, // 待提交/待支付 PaymentStatus = 0, // 未支付 RegistrationTime = DateTime.Now, CreatedUserId = userId, @@ -788,9 +787,9 @@ public class EventClientController : IDynamicApiController break; case ChargeMode.FixedPrice: - // 定价(赛事):项目单价显示为0,因为总金额是固定的 - unitPrice = 0; - totalPrice = 0; + // 定价(赛事):使用赛事费用配置的单价 + unitPrice = feeConfig?.Price ?? 0; + totalPrice = unitPrice * item.Persons!.Count; break; case ChargeMode.UnitPriceEvent: @@ -1009,7 +1008,7 @@ public class EventClientController : IDynamicApiController reg.PaymentMethod = 1; // 线下 reg.PaymentProofUrl = input.VoucherUrl; - reg.RegistrationStatus = 1; // 待审核 + reg.PaymentStatus = 0; // 待审核 reg.UpdatedTime = DateTime.Now; reg.UpdatedUserId = userId; @@ -1061,7 +1060,6 @@ public class EventClientController : IDynamicApiController EventId = r.EventId, EventName = e.EventName, CoverImage = e.CoverImage, - RegistrationStatus = r.RegistrationStatus, PaymentStatus = r.PaymentStatus, RegistrationTime = r.RegistrationTime, ProjectCount = SqlFunc.Subqueryable().Where(i => i.RegistrationId == r.Id).Count(), @@ -1092,7 +1090,6 @@ public class EventClientController : IDynamicApiController r.EventId, e.EventName, e.CoverImage, - r.RegistrationStatus, r.PaymentStatus, r.TotalAmount, r.OrderNo, @@ -1131,7 +1128,6 @@ public class EventClientController : IDynamicApiController EventName = reg.EventName, CoverImage = reg.CoverImage, EventStatus = status, - RegistrationStatus = reg.RegistrationStatus, PaymentStatus = reg.PaymentStatus, TotalAmount = reg.TotalAmount, OrderNo = reg.OrderNo, @@ -1171,7 +1167,6 @@ public class EventClientController : IDynamicApiController return new RegistrationStatusDto { RegistrationId = reg.Id, - RegistrationStatus = reg.RegistrationStatus, PaymentStatus = reg.PaymentStatus, RejectReason = reg.ReviewRemark }; @@ -1193,9 +1188,9 @@ public class EventClientController : IDynamicApiController // 校验状态:只有待提交、待审核、未支付状态可直接取消 // 已支付状态需走退款流程(暂不实现) if (reg.PaymentStatus == 1) throw Oops.Bah("已支付订单请联系客服退款"); - if (reg.RegistrationStatus == 4) throw Oops.Bah("订单已取消,无需重复操作"); + if (reg.PaymentStatus == 4) throw Oops.Bah("订单已取消,无需重复操作"); - reg.RegistrationStatus = 4; // 4=已取消 + reg.PaymentStatus = 4; // 4=已取消 reg.UpdatedTime = DateTime.Now; reg.UpdatedUserId = userId; @@ -1222,7 +1217,7 @@ public class EventClientController : IDynamicApiController if (reg == null) throw Oops.Bah("报名记录不存在"); if (reg.PaymentStatus == 1) throw Oops.Bah("订单已支付,无法修改支付方式"); - if (reg.RegistrationStatus == 4) throw Oops.Bah("订单已取消"); + if (reg.PaymentStatus == 4) throw Oops.Bah("订单已取消"); // 如果选择微信支付,验证 OpenId 是否提供 if (input.PaymentMethod == 2) @@ -1276,7 +1271,6 @@ public class EventClientController : IDynamicApiController reg.PaymentStatus = 1; reg.PaymentTime = queryResult.SuccessTime?.DateTime; reg.RegistrationRemark = queryResult.TransactionId; // 将第三方交易号存储在备注字段 - reg.RegistrationStatus = 1; // 待审核 reg.UpdatedTime = DateTime.Now; reg.UpdatedUserId = userId; @@ -1428,7 +1422,6 @@ public class EventClientController : IDynamicApiController reg.PaymentStatus = 1; reg.PaymentTime = notifyData.SuccessTime?.DateTime; reg.RegistrationRemark = notifyData.TransactionId; // 将第三方交易号存储在备注字段 - reg.RegistrationStatus = 1; // 待审核 reg.UpdatedTime = DateTime.Now; await _registrationRepository.UpdateAsync(reg); @@ -1608,7 +1601,7 @@ public class EventClientController : IDynamicApiController if (registration.CreatedUserId != userId) throw Oops.Bah("无权操作此报名记录"); - if (registration.RegistrationStatus == 4) throw Oops.Bah("报名已取消,无法上传素材"); + if (registration.PaymentStatus == 4) throw Oops.Bah("报名已取消,无法上传素材"); var evt = await _eventRepository.GetFirstAsync(e => e.Id == registration.EventId && !e.DeleteMark); if (evt == null) throw Oops.Bah("赛事不存在"); diff --git a/YD_Event.Application/Client/MyController.cs b/YD_Event.Application/Client/MyController.cs index e88fa8f..b6995f4 100644 --- a/YD_Event.Application/Client/MyController.cs +++ b/YD_Event.Application/Client/MyController.cs @@ -548,7 +548,7 @@ public class MyController : IDynamicApiController Id = r.Id, EventName = e.EventName, TeamName = r.TeamName, - Status = r.RegistrationStatus, + Status = r.PaymentStatus, RegistrationTime = r.RegistrationTime, ProjectNames = "" }) diff --git a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs index ae59600..e49c37f 100644 --- a/YD_Event.Application/Event/Dtos/EventRecordDtos.cs +++ b/YD_Event.Application/Event/Dtos/EventRecordDtos.cs @@ -21,9 +21,9 @@ public class EventRecordPageInput : Pagination public string? EventName { get; set; } /// - /// 报名状态 + /// 支付状态 /// - public int? RegistrationStatus { get; set; } + public int? PaymentStatus { get; set; } /// /// 开始时间 @@ -67,9 +67,9 @@ public class EventRecordOutput public DateTime EndTime { get; set; } /// - /// 报名状态 + /// 支付状态 /// - public int RegistrationStatus { get; set; } + public int PaymentStatus { get; set; } /// /// 赛事ID diff --git a/YD_Event.Application/Event/Dtos/RegistrationDtos.cs b/YD_Event.Application/Event/Dtos/RegistrationDtos.cs index a86244c..2e59b0e 100644 --- a/YD_Event.Application/Event/Dtos/RegistrationDtos.cs +++ b/YD_Event.Application/Event/Dtos/RegistrationDtos.cs @@ -138,11 +138,6 @@ public class RegistrationListOutput /// 报名时间 /// public DateTime RegistrationTime { get; set; } - - /// - /// 报名状态 - /// - public int RegistrationStatus { get; set; } /// /// 报名项目详情列表 @@ -182,9 +177,9 @@ public class BatchAuditInput public List Ids { get; set; } /// - /// 审核状态 (2-通过, 3-拒绝) + /// 审核状态 (1-通过, 2-拒绝) /// - public int RegistrationStatus { get; set; } + public int PaymentStatus { get; set; } /// /// 审核备注 diff --git a/YD_Event.Application/Event/EventArrangementService.cs b/YD_Event.Application/Event/EventArrangementService.cs index 73c79f8..da590c3 100644 --- a/YD_Event.Application/Event/EventArrangementService.cs +++ b/YD_Event.Application/Event/EventArrangementService.cs @@ -61,7 +61,7 @@ public class EventArrangementService : BaseService((p, r) => p.RegistrationId == r.Id) .Where((p, r) => r.EventId == eventId - && r.RegistrationStatus != 4 // 排除已取消的报名 + && r.PaymentStatus != 4 // 排除已取消的报名 && !p.DeleteMark // 排除已删除的人员 && p.PersonType == PersonType.Athlete // 只统计运动员 ) @@ -163,7 +163,7 @@ public class EventArrangementService : BaseService((p, r) => p.RegistrationId == r.Id) .Where((p, r) => p.ProjectId == eventProj.Id - && r.RegistrationStatus != 4 + && r.PaymentStatus != 4 && !p.DeleteMark && p.PersonType == PersonType.Athlete) .OrderBy(p => p.GroupName) diff --git a/YD_Event.Application/Event/EventRecordService.cs b/YD_Event.Application/Event/EventRecordService.cs index 3fbb9da..ffb3b6e 100644 --- a/YD_Event.Application/Event/EventRecordService.cs +++ b/YD_Event.Application/Event/EventRecordService.cs @@ -43,7 +43,7 @@ public class EventRecordService : BaseService, ITransient .WhereIF(!string.IsNullOrWhiteSpace(input.EventName), (r, e, u, m) => e.EventName.Contains(input.EventName)) .WhereIF(input.StartTime.HasValue, (r, e, u, m) => e.MatchStartTime >= input.StartTime) .WhereIF(input.EndTime.HasValue, (r, e, u, m) => e.MatchStartTime <= input.EndTime) - .WhereIF(input.RegistrationStatus.HasValue, (r, e, u, m) => r.RegistrationStatus == input.RegistrationStatus) + .WhereIF(input.PaymentStatus.HasValue, (r, e, u, m) => r.PaymentStatus == input.PaymentStatus) // Filter by User ID (AppUser or Merchant) .WhereIF(input.AppUserId.HasValue, (r, e, u, m) => u.Id == input.AppUserId) .WhereIF(input.MerchantId.HasValue, (r, e, u, m) => m.Id == input.MerchantId) @@ -55,7 +55,7 @@ public class EventRecordService : BaseService, ITransient EventType = e.EventType.ToString(), StartTime = e.MatchStartTime, EndTime = e.MatchEndTime, - RegistrationStatus = r.RegistrationStatus, + PaymentStatus = r.PaymentStatus, EventId = e.Id, ContactName = r.ContactName, ContactPhone = r.ContactPhone, diff --git a/YD_Event.Application/Event/EventRegistrationService.cs b/YD_Event.Application/Event/EventRegistrationService.cs index baccb9b..a3959a7 100644 --- a/YD_Event.Application/Event/EventRegistrationService.cs +++ b/YD_Event.Application/Event/EventRegistrationService.cs @@ -62,8 +62,7 @@ public class EventRegistrationService : BaseService, ITransie TotalAmount = x.TotalAmount, PaymentStatus = x.PaymentStatus, PaymentProofUrl = x.PaymentProofUrl, - RegistrationTime = x.RegistrationTime, - RegistrationStatus = x.RegistrationStatus + RegistrationTime = x.RegistrationTime }); var result = await query.ToPagedListAsync(input); @@ -112,7 +111,7 @@ public class EventRegistrationService : BaseService, ITransie await _repository.UpdateAsync(x => new EventRegistration { - RegistrationStatus = input.RegistrationStatus, + PaymentStatus = input.PaymentStatus, ReviewRemark = input.ReviewRemark, ReviewTime = DateTime.Now }, x => input.Ids.Contains(x.Id)); @@ -141,8 +140,7 @@ public class EventRegistrationService : BaseService, ITransie x.PaymentMethod, x.TotalAmount, x.PaymentStatus, - x.RegistrationTime, - x.RegistrationStatus + x.RegistrationTime }) .ToListAsync(); @@ -175,11 +173,6 @@ public class EventRegistrationService : BaseService, ITransie var registration = await _repository.GetByIdAsync(input.RegistrationId); if (registration == null) throw Oops.Bah("报名记录不存在"); - if (registration.RegistrationStatus != 2) - { - throw Oops.Bah("只有已报名状态的记录才能进行支付审核"); - } - if (registration.PaymentStatus != 0) { throw Oops.Bah("该记录已完成支付审核,无需重复操作"); @@ -213,11 +206,11 @@ public class EventRegistrationService : BaseService, ITransie if (!registrations.Any()) throw Oops.Bah("未找到有效的报名记录"); var invalidRegistrations = registrations - .Where(r => r.RegistrationStatus != 2) + .Where(r => r.PaymentStatus != 0) .ToList(); if (invalidRegistrations.Any()) { - throw Oops.Bah("存在非已报名状态的记录,无法进行支付审核"); + throw Oops.Bah("存在非待审核状态的记录,无法进行支付审核"); } var alreadyAudited = registrations diff --git a/YD_Event.Application/Event/UserEventRecordService.cs b/YD_Event.Application/Event/UserEventRecordService.cs index 6787fec..a6b6cdd 100644 --- a/YD_Event.Application/Event/UserEventRecordService.cs +++ b/YD_Event.Application/Event/UserEventRecordService.cs @@ -33,6 +33,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient private readonly ISqlSugarRepository _certificateRepository; private readonly ISqlSugarRepository _weChatPayConfigRepository; private readonly ISqlSugarRepository _merchantRepository; + private readonly ISqlSugarRepository _eventInfoRepository; private readonly ISqlSugarClient _db; private readonly AuthManager _authManager; private readonly IIdGenerator _idGenerator; @@ -46,6 +47,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient ISqlSugarRepository certificateRepository, ISqlSugarRepository weChatPayConfigRepository, ISqlSugarRepository merchantRepository, + ISqlSugarRepository eventInfoRepository, ISqlSugarClient db, AuthManager authManager, IIdGenerator idGenerator, @@ -63,6 +65,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient _idGenerator = idGenerator; _fileService = fileService; _weChatPayService = weChatPayService; + _eventInfoRepository = eventInfoRepository; } /// @@ -73,7 +76,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient public async Task> GetRegistrationList([FromQuery] RegistrationListQueryInput input) { var userId = _authManager.UserId; - // 重新构建查询以支持复杂逻辑 + var list = await _registrationRepository.AsQueryable() .InnerJoin((r, e) => r.EventId == e.Id) .LeftJoin((r, e, fc) => e.Id == fc.EventId) @@ -83,7 +86,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient .OrderByDescending((r, e, fc) => r.CreatedTime) .Select((r, e, fc) => new { - r.Id, r.EventId, e.EventName, r.TeamName, r.RegistrationStatus, r.PaymentStatus, r.MaterialUrl, r.PaymentProofUrl, + r.Id, r.EventId, e.EventName, r.TeamName, r.PaymentStatus, r.MaterialUrl, r.PaymentProofUrl, r.CreatedTime, r.UpdatedTime, r.TotalPersonCount, e.MaterialUploadEndTime, e.CoverImage, e.EventType, e.EventStatus, e.RegistrationStartTime, e.RegistrationEndTime, e.MatchStartTime, e.MatchEndTime, @@ -94,20 +97,18 @@ public class UserEventRecordService : IDynamicApiController, ITransient var resultItems = list.Rows.Select(x => { // 计算综合状态 int statusValue = 0; - if (x.RegistrationStatus == 4) + if (x.PaymentStatus == 4) statusValue = 2; // 已取消 - else if (x.RegistrationStatus == 1) - statusValue = 1; // 已支付/待审核 else if (x.PaymentStatus == 0) statusValue = 0; // 待付款 else if (x.PaymentStatus == 1 && string.IsNullOrEmpty(x.MaterialUrl)) statusValue = 1; // 已支付 else if (x.PaymentStatus == 1 && !string.IsNullOrEmpty(x.MaterialUrl)) statusValue = 4; // 已完成/已报名 + else if (x.PaymentStatus == 2) + statusValue = 1; // 审核拒绝 else if (x.PaymentStatus == 3) statusValue = 3; // 已退款 - else if (x.PaymentStatus == 4) - statusValue = 1; // 待审核 return new RegistrationItemDTO { @@ -158,39 +159,14 @@ public class UserEventRecordService : IDynamicApiController, ITransient var registration = await _registrationRepository.GetFirstAsync(x => x.Id == registrationId && x.CreatedUserId == userId); if (registration == null) throw Oops.Bah("报名记录不存在"); - // 仅允许 status ∈ (待付款, 待上传素材) 可取消 - // 待付款: PayStatus == 0 - // 待上传素材: PayStatus == 1 && !HasMaterial - // 已取消: RegStatus == 4 - if (registration.RegistrationStatus == 4) throw Oops.Bah("订单已取消"); + if (registration.PaymentStatus == 4) throw Oops.Bah("订单已取消"); - bool canCancel = false; - if (registration.PaymentStatus == 0) canCancel = true; - else if (registration.PaymentStatus == 1 && string.IsNullOrEmpty(registration.MaterialUrl)) canCancel = true; + if (registration.PaymentStatus == 0) throw Oops.Bah("订单未支付"); - if (!canCancel) - { - // 已付款且已上传素材的报名需走退赛流程 - throw Oops.Bah("当前状态无法直接取消,请联系管理员退赛"); - } - - registration.RegistrationStatus = 4; // 已取消 + registration.PaymentStatus = 4; // 已取消 registration.UpdatedUserId = userId; registration.UpdatedTime = DateTime.Now; - // registration.CancelReason = "用户主动取消"; // 需扩展字段 await _registrationRepository.UpdateAsync(registration); - - // 记录日志 (暂不需要) - /* - await _eventLogRepository.InsertAsync(new EventLog - { - RegistrationId = registration.Id, - LogType = EventLogType.Cancel, - Description = "用户取消报名", - OperatorId = userId, - CreatedTime = DateTime.Now - }); - */ return new ResponseDTO { Code = 200, Success = true, Data = true, Message = "取消成功" }; } @@ -218,8 +194,8 @@ public class UserEventRecordService : IDynamicApiController, ITransient var result = new List(); foreach (var file in input.Files) { - var uploadResult = await _fileService.Upload(file); // 假设 FileService 支持 IFormFile - var item = uploadResult.FirstOrDefault(); // 假设返回 List + var uploadResult = await _fileService.Upload(file); + var item = uploadResult.FirstOrDefault(); if (item != null) { result.Add(new MaterialDTO @@ -237,18 +213,6 @@ public class UserEventRecordService : IDynamicApiController, ITransient { registration.MaterialUrl = result.First().OssUrl; // 更新主表 await _registrationRepository.UpdateAsync(registration); - - // 记录日志 (暂不需要) - /* - await _eventLogRepository.InsertAsync(new EventLog - { - RegistrationId = registration.Id, - LogType = EventLogType.UploadMaterial, - Description = $"用户上传素材: {result.Count}个文件", - OperatorId = userId, - CreatedTime = DateTime.Now - }); - */ } return new ResponseDTO> { Code = 200, Success = true, Data = result, Message = "上传成功" }; @@ -273,22 +237,9 @@ public class UserEventRecordService : IDynamicApiController, ITransient var fileInfo = uploadResult.First(); registration.PaymentProofUrl = fileInfo.Url; - registration.PaymentStatus = 4; // 假设 4 = 待审核 + registration.PaymentStatus = 0; registration.UpdatedTime = DateTime.Now; - // registration.VoucherUploadTime = DateTime.Now; await _registrationRepository.UpdateAsync(registration); - - // 记录日志 (暂不需要) - /* - await _eventLogRepository.InsertAsync(new EventLog - { - RegistrationId = registration.Id, - LogType = EventLogType.UploadVoucher, - Description = "用户上传付款凭证", - OperatorId = userId, - CreatedTime = DateTime.Now - }); - */ return new ResponseDTO { @@ -345,18 +296,14 @@ public class UserEventRecordService : IDynamicApiController, ITransient var person = await _registrationPersonRepository.GetFirstAsync(x => x.RegistrationId == registrationId && x.Id == userId); if (person == null) throw Oops.Bah("队员不存在"); - // 被替换人 role ≠ 队长 (假设 PersonType=Leader 是队长) + // 被替换人 role ≠ 队长 if (person.PersonType == PersonType.Leader) throw Oops.Bah("不能替换队长"); // 检查新队员 var newUser = await _userRepository.GetByIdAsync(input.NewUserId); if (newUser == null) throw Oops.Bah("新队员不存在"); - - // 检查新队员是否已报名该赛事 (简化检查: 是否在 Person 表中存在该 EventId 的记录) - // var exists = await _registrationPersonRepository.AnyAsync(x => x.EventId == registration.EventId && x.IdCard == newUser.IdCardNumber); - // if (exists) throw Oops.Bah("新队员已报名该赛事"); - long oldUserId = person.Id; // 这里应该是 AppUserId,但 Person 表没存 AppUserId,只存了 Name/Phone + long oldUserId = person.Id; // 更新信息 person.Name = newUser.Name; @@ -364,18 +311,6 @@ public class UserEventRecordService : IDynamicApiController, ITransient person.Phone = newUser.Mobile; person.UpdatedTime = DateTime.Now; await _registrationPersonRepository.UpdateAsync(person); - - // 记录日志 (暂不需要) - /* - await _eventLogRepository.InsertAsync(new EventLog - { - RegistrationId = registration.Id, - LogType = EventLogType.ReplaceMember, - Description = $"更换队员: {oldUserId} -> {input.NewUserId}", - OperatorId = currentUserId, - CreatedTime = DateTime.Now - }); - */ return new ResponseDTO { Code = 200, Success = true, Data = true, Message = "更换成功" }; } @@ -479,7 +414,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient if (registration == null) throw Oops.Bah("报名记录不存在"); // 检查状态 - if (registration.RegistrationStatus == 4) throw Oops.Bah("订单已取消"); + if (registration.PaymentStatus == 4) throw Oops.Bah("订单已取消"); if (registration.PaymentStatus != 1) throw Oops.Bah("未支付的订单无法退款"); var now = DateTime.Now; @@ -492,7 +427,6 @@ public class UserEventRecordService : IDynamicApiController, ITransient }; // 更新报名状态 - registration.RegistrationStatus = 4; // 已取消 registration.PaymentStatus = 3; // 已退款 registration.UpdatedUserId = userId; registration.UpdatedTime = now; @@ -502,8 +436,9 @@ public class UserEventRecordService : IDynamicApiController, ITransient // 如果有支付,执行退款 if (registration.TotalAmount > 0 && !string.IsNullOrEmpty(registration.OrderNo)) { + var eventInfo = await _eventInfoRepository.GetFirstAsync(e=>e.Id == registration.EventId); // 查找商户配置 - var merchant = await _merchantRepository.GetFirstAsync(x => x.CreatedUserId == userId); + var merchant = await _merchantRepository.GetFirstAsync(x => x.Id == eventInfo.MerchantId); if (merchant != null) { diff --git a/YD_Event.Application/Event/UserEventRegistrationService.cs b/YD_Event.Application/Event/UserEventRegistrationService.cs index c3f157d..d604b07 100644 --- a/YD_Event.Application/Event/UserEventRegistrationService.cs +++ b/YD_Event.Application/Event/UserEventRegistrationService.cs @@ -61,6 +61,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient private readonly ProjectService _projectService; private readonly ISqlSugarRepository _couponRepository; private readonly ISqlSugarRepository _userCouponRepository; + private readonly ISqlSugarRepository _paymentRepository; private readonly ILogger _logger; public UserEventRegistrationService( @@ -92,6 +93,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient ProjectService projectService, ISqlSugarRepository couponRepository, ISqlSugarRepository userCouponRepository, + ISqlSugarRepository paymentRepository, ILogger logger) { _eventRepository = eventRepository; @@ -122,6 +124,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient _projectService = projectService; _couponRepository = couponRepository; _userCouponRepository = userCouponRepository; + _paymentRepository = paymentRepository; _logger = logger; } @@ -289,7 +292,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient if (registration != null) { output.RegistrationId = registration.Id; - output.UserRegistrationStatus = GetRegistrationStatusDesc(registration.RegistrationStatus); + output.UserRegistrationStatus = GetPaymentStatusDesc(registration.PaymentStatus); } else { @@ -480,7 +483,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient CreatedUserId = userId, CreatedTime = DateTime.Now, Status = AvailabilityStatus.Enable, - RegistrationStatus = input.IsDraft ? 0 : 1, // 0-待提交(草稿), 1-待审核 + PaymentStatus = input.IsDraft ? 0 : 0, // 0-未支付/待审核 ContactName = userName, ContactPhone = userMobile, OrderNo = "", @@ -490,7 +493,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient } else { - registration.RegistrationStatus = input.IsDraft ? 0 : 1; + registration.PaymentStatus = input.IsDraft ? 0 : 0; registration.ContactName = userName; registration.ContactPhone = userMobile; registration.UpdatedTime = DateTime.Now; @@ -555,9 +558,9 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient break; case ChargeMode.FixedPrice: - // 定价(赛事)模式:项目单价显示为0,因为总金额是固定的 - unitPrice = 0; - totalPrice = 0; + // 定价(赛事)模式:使用赛事费用配置的单价 + unitPrice = feeConfig.Price; + totalPrice = unitPrice * groupMembers.Count(); break; case ChargeMode.UnitPriceEvent: @@ -638,9 +641,9 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient break; case ChargeMode.FixedPrice: - // 定价(赛事)模式:项目单价显示为0,因为总金额是固定的 - unitPrice = 0; - totalPrice = 0; + // 定价(赛事)模式:使用赛事费用配置的单价 + unitPrice = feeConfig.Price; + totalPrice = unitPrice * members.Count(); break; case ChargeMode.UnitPriceEvent: @@ -853,7 +856,6 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient } registration.PaymentStatus = 1; // 已支付 - registration.RegistrationStatus = 1; // 待审核 registration.PaymentTime = DateTime.Now; await _registrationRepository.UpdateAsync(registration); @@ -953,70 +955,129 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient [DisplayName("微信支付回调")] [HttpPost("wechat/notify")] [AllowAnonymous] + [UnitOfWork] [NonUnify] public async Task WechatPayNotify() { - var request = _httpContextAccessor.HttpContext.Request; - using var reader = new StreamReader(request.Body); - var body = await reader.ReadToEndAsync(); - - var signature = request.Headers["Wechatpay-Signature"].ToString(); - var timestamp = request.Headers["Wechatpay-Timestamp"].ToString(); - var nonce = request.Headers["Wechatpay-Nonce"].ToString(); - var serialNumber = request.Headers["Wechatpay-Serial"].ToString(); - - var notifyRequest = new WeChatPayNotifyRequest + try { - Body = body, - Signature = signature, - Timestamp = timestamp, - Nonce = nonce, - SerialNumber = serialNumber - }; + using var reader = new StreamReader(_httpContextAccessor.HttpContext.Request.Body); + var body = await reader.ReadToEndAsync(); + + var headers = _httpContextAccessor.HttpContext.Request.Headers; + var timestamp = headers["Wechatpay-Timestamp"].FirstOrDefault(); + var nonce = headers["Wechatpay-Nonce"].FirstOrDefault(); + var signature = headers["Wechatpay-Signature"].FirstOrDefault(); + var serialNumber = headers["Wechatpay-Serial"].FirstOrDefault(); - var payConfig = await _weChatPayConfigRepository.GetFirstAsync(x => - x.Status == AvailabilityStatus.Enable && !x.DeleteMark); + if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(nonce) || + string.IsNullOrEmpty(signature) || string.IsNullOrEmpty(serialNumber)) + { + _logger.LogWarning("微信支付回调通知参数不完整"); + return new JsonResult(new { code = "FAIL", message = "参数不完整" }); + } - if (payConfig == null) - { - return new BadRequestObjectResult(new { code = "FAIL", message = "支付配置不存在" }); - } + var platformPayConfig = await _weChatPayConfigRepository.GetFirstAsync(x => + x.Status == AvailabilityStatus.Enable && !x.DeleteMark); + if (platformPayConfig == null) + { + _logger.LogError("未找到平台级别的微信支付配置"); + return new JsonResult(new { code = "FAIL", message = "支付配置未找到" }); + } - bool valid = await _weChatPayService.VerifyPayNotifyAsync(payConfig, notifyRequest); - if (!valid) - { - return new BadRequestResult(); - } + var notifyRequest = new WeChatPayNotifyRequest + { + Timestamp = timestamp, + Nonce = nonce, + Signature = signature, + SerialNumber = serialNumber, + Body = body + }; - var notifyData = await _weChatPayService.DecryptPayNotifyDataAsync(payConfig, notifyRequest); - if (notifyData != null && notifyData.EventType == "TRANSACTION.SUCCESS") - { - var orderNo = notifyData.OutTradeNo; - var transactionId = notifyData.TransactionId; + var isValid = await _weChatPayService.VerifyPayNotifyAsync(platformPayConfig, notifyRequest); + if (!isValid) + { + _logger.LogWarning("微信支付回调签名验证失败"); + return new JsonResult(new { code = "FAIL", message = "签名验证失败" }); + } - var order = await _orderRepository.GetFirstAsync(x => x.OrderNo == orderNo); - if (order != null && order.OrderStatus == OrderStatus.Pending) + var notifyData = await _weChatPayService.DecryptPayNotifyDataAsync(platformPayConfig, notifyRequest); + if (notifyData == null || notifyData.TradeState != "SUCCESS") + { + _logger.LogWarning("微信支付回调数据无效或交易未成功"); + return new JsonResult(new { code = "SUCCESS", message = "成功" }); + } + + var reg = await _registrationRepository.GetFirstAsync(r => r.OrderNo == notifyData.OutTradeNo); + if (reg == null) + { + _logger.LogWarning($"未找到订单:{notifyData.OutTradeNo}"); + return new JsonResult(new { code = "SUCCESS", message = "成功" }); + } + + if (reg.PaymentStatus == 1) + { + _logger.LogInformation($"订单 {reg.OrderNo} 已处理过支付回调"); + return new JsonResult(new { code = "SUCCESS", message = "成功" }); + } + + var evt = await _eventRepository.GetFirstAsync(e => e.Id == reg.EventId); + if (evt == null) + { + _logger.LogError($"未找到赛事信息,订单号:{reg.OrderNo},赛事ID:{reg.EventId}"); + return new JsonResult(new { code = "FAIL", message = "赛事信息不存在" }); + } + + _logger.LogInformation("订单支付成功,订单号={OrderNo},赛事ID={EventId},商户ID={MerchantId}", + reg.OrderNo, evt.Id, evt.MerchantId); + + reg.PaymentStatus = 1; + reg.PaymentTime = notifyData.SuccessTime?.DateTime; + reg.RegistrationRemark = notifyData.TransactionId; + reg.UpdatedTime = DateTime.Now; + + await _registrationRepository.UpdateAsync(reg); + _logger.LogInformation($"订单 {reg.OrderNo} 支付成功,微信交易号:{notifyData.TransactionId}"); + + var payment = new EventRegistrationPayment + { + Id = _idGenerator.NewLong(), + RegistrationId = reg.Id, + TransactionNo = notifyData.TransactionId ?? "", + PaymentChannel = 1, + PaymentAmount = reg.TotalAmount, + PaymentTime = notifyData.SuccessTime?.DateTime ?? DateTime.Now, + PaymentStatus = 1, + RefundStatus = 0, + PayeeAccount = "", + CreatedUserId = reg.CreatedUserId, + CreatedTime = DateTime.Now + }; + await _paymentRepository.InsertAsync(payment); + _logger.LogInformation($"支付记录创建成功,报名ID={reg.Id},交易号={notifyData.TransactionId}"); + + var order = await _orderRepository.GetFirstAsync(o => o.OrderNo == reg.OrderNo); + if (order != null) { order.OrderStatus = OrderStatus.Paid; - order.PaymentTime = DateTime.Now; - if (notifyData.PayerAmount.HasValue) - { - order.ActualAmount = notifyData.PayerAmount.Value / 100m; - } - order.Remark = $"微信支付单号: {transactionId}"; + order.PaymentTime = notifyData.SuccessTime?.DateTime; + order.UpdatedTime = DateTime.Now; await _orderRepository.UpdateAsync(order); - - var registration = await _registrationRepository.GetByIdAsync(order.RegistrationId); - if (registration != null && registration.PaymentStatus != 1) - { - registration.PaymentStatus = 1; - registration.RegistrationStatus = 1; - await _registrationRepository.UpdateAsync(registration); - } + _logger.LogInformation($"Order 记录 {order.OrderNo} 状态已更新为已支付"); } - } - return new OkObjectResult(new { code = "SUCCESS", message = "成功" }); + return new JsonResult(new { code = "SUCCESS", message = "成功" }); + } + catch (ArgumentException ex) + { + _logger.LogError(ex, "处理微信支付回调通知时参数验证失败"); + return new JsonResult(new { code = "FAIL", message = "业务验证失败" }); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理微信支付回调通知异常"); + return new JsonResult(new { code = "FAIL", message = "处理失败" }); + } } /// @@ -1066,7 +1127,6 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient if (registration != null && registration.PaymentStatus != 1) { registration.PaymentStatus = 1; - registration.RegistrationStatus = 1; await _registrationRepository.UpdateAsync(registration); } return 1; @@ -1192,14 +1252,14 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient return result; } - private string GetRegistrationStatusDesc(int status) + private string GetPaymentStatusDesc(int status) { return status switch { - 0 => "待提交", - 1 => "审核中", - 2 => "已报名", - 3 => "审核拒绝", + 0 => "待审核", + 1 => "已支付", + 2 => "支付失败", + 3 => "已退款", 4 => "已取消", _ => "未知" }; @@ -1339,7 +1399,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient // 先查询该赛事的所有报名记录 var eventRegistrations = await _registrationRepository.GetListAsync(x => x.EventId == input.EventId && - x.RegistrationStatus != 4 && + x.PaymentStatus != 4 && !x.DeleteMark); var eventRegistrationIds = eventRegistrations.Select(r => r.Id).ToList(); @@ -1355,7 +1415,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient var registrations = await _registrationRepository.GetListAsync(x => registrationIds.Contains(x.Id) && x.EventId == input.EventId && - x.RegistrationStatus != 4 && + x.PaymentStatus != 4 && !x.DeleteMark); // 统计该队员已报名的项目数量(不区分个人/团队) diff --git a/YD_Event.Application/Order/Dtos/OrderListOutput.cs b/YD_Event.Application/Order/Dtos/OrderListOutput.cs index 8c19112..bce98aa 100644 --- a/YD_Event.Application/Order/Dtos/OrderListOutput.cs +++ b/YD_Event.Application/Order/Dtos/OrderListOutput.cs @@ -128,10 +128,20 @@ public class OrderDetailOutput /// public int OrderType { get; set; } + /// + /// 订单类型文本 + /// + public string OrderTypeText { get; set; } + /// /// 订单状态 /// public OrderStatus OrderStatus { get; set; } + + /// + /// 订单状态文本 + /// + public string OrderStatusText { get; set; } /// /// 赛事名称 @@ -168,6 +178,11 @@ public class OrderDetailOutput /// public string PaymentProofUrl { get; set; } + /// + /// 报名方式 + /// + public string RegistrationMode { get; set; } + /// /// 原始金额 /// @@ -187,6 +202,21 @@ public class OrderDetailOutput /// 创建时间 /// public DateTime CreatedTime { get; set; } + + /// + /// 关联订单号 + /// + public string RelatedOrderNo { get; set; } + + /// + /// 联系人姓名 + /// + public string ContactName { get; set; } + + /// + /// 联系人电话 + /// + public string ContactPhone { get; set; } } /// diff --git a/YD_Event.Application/Order/OrderService.cs b/YD_Event.Application/Order/OrderService.cs index 08298d6..e5a8b86 100644 --- a/YD_Event.Application/Order/OrderService.cs +++ b/YD_Event.Application/Order/OrderService.cs @@ -65,7 +65,6 @@ public class OrderService : BaseService, ITransien var entity = input.Adapt(); entity.Id = _idGenerator.NextId(); entity.OrderNo = DateTime.Now.ToString("yyyyMMdd") + new Random().Next(1000, 9999); // 简单生成 - entity.RegistrationStatus = 0; // 待提交 entity.PaymentStatus = 0; // 未支付 entity.RegistrationTime = DateTime.Now; entity.RegistrationMode = 2; // 后台管理页面只做团队报名 @@ -235,22 +234,25 @@ public class OrderService : BaseService, ITransien [HttpGet("detail")] public async Task Detail([FromQuery] long id) { - var order = await _orderRepository.AsQueryable() + var query = _orderRepository.AsQueryable() .LeftJoin((o, e) => o.EventId == e.Id) + .LeftJoin((o, e, r) => o.RegistrationId == r.Id) + .LeftJoin((o, e, r, ro) => o.RelatedOrderId == ro.Id) .Where(o => o.Id == id) - .Select((o, e) => new { Order = o, EventName = e.EventName }) - .FirstAsync(); + .Select((o, e, r, ro) => new { Order = o, EventName = e.EventName, Registration = r, RelatedOrderNo = ro.OrderNo }); - if (order == null) throw Oops.Bah("订单不存在"); + var orderInfo = await query.FirstAsync(); - var registrationId = order.Order.RegistrationId; + if (orderInfo == null || orderInfo.Order == null) throw Oops.Bah("订单不存在"); + + var registrationId = orderInfo.Order.RegistrationId; var items = await _itemRepository.AsQueryable().Where(x => x.RegistrationId == registrationId).ToListAsync(); var persons = await _personRepository.AsQueryable().Where(x => x.RegistrationId == registrationId).ToListAsync(); // 将项目和人员转换为DTO var itemDtos = items.Select(x => new OrderItemDto { - ProjectName = x.ProjectName, // 假设已存储或通过关联获取 + ProjectName = x.ProjectName, GroupName = x.GroupName, Fee = x.TotalPrice }).ToList(); @@ -263,21 +265,33 @@ public class OrderService : BaseService, ITransien return new OrderDetailOutput { - Id = order.Order.Id, - OrderNo = order.Order.OrderNo, - OrderType = order.Order.OrderType, - OrderStatus = order.Order.OrderStatus, - EventName = order.EventName, + Id = orderInfo.Order.Id, + OrderNo = orderInfo.Order.OrderNo, + OrderType = orderInfo.Order.OrderType, + OrderTypeText = orderInfo.Order.OrderType == 1 ? "收入" : "退款", + OrderStatus = orderInfo.Order.OrderStatus, + OrderStatusText = + orderInfo.Order.OrderStatus == OrderStatus.Pending ? "待支付" : + orderInfo.Order.OrderStatus == OrderStatus.Paid ? "已支付" : + orderInfo.Order.OrderStatus == OrderStatus.Cancelled ? "已取消" : + orderInfo.Order.OrderStatus == OrderStatus.Refunded ? "已退款" : + orderInfo.Order.OrderStatus == OrderStatus.Shipped ? "已发货" : + orderInfo.Order.OrderStatus == OrderStatus.Completed ? "已完成" : "", + EventName = orderInfo.EventName, ProjectNames = string.Join(",", items.Select(x => x.ProjectName).Distinct()), GroupNames = string.Join(",", items.Select(x => x.GroupName).Distinct()), Items = itemDtos, Persons = personDtos, - PaymentMethod = order.Order.PaymentMethod == 1 ? "线上" : "线下", - PaymentProofUrl = order.Order.PaymentProofUrl, - OriginalAmount = order.Order.OriginalAmount, - DiscountAmount = order.Order.DiscountAmount, - ActualAmount = order.Order.ActualAmount, - CreatedTime = order.Order.CreatedTime + PaymentMethod = orderInfo.Order.PaymentMethod == 2 ? "线上" : "线下", + PaymentProofUrl = orderInfo.Order.PaymentProofUrl, + RegistrationMode = orderInfo.Order.RegistrationMode == 1 ? "个人" : "团队", + OriginalAmount = orderInfo.Order.OriginalAmount, + DiscountAmount = orderInfo.Order.DiscountAmount, + ActualAmount = orderInfo.Order.ActualAmount, + CreatedTime = orderInfo.Order.CreatedTime, + RelatedOrderNo = orderInfo.RelatedOrderNo, + ContactName = orderInfo.Registration?.ContactName, + ContactPhone = orderInfo.Registration?.ContactPhone }; } diff --git a/YD_Event.Application/YD_Event.Application.xml b/YD_Event.Application/YD_Event.Application.xml index 933a583..42e519f 100644 --- a/YD_Event.Application/YD_Event.Application.xml +++ b/YD_Event.Application/YD_Event.Application.xml @@ -2261,11 +2261,6 @@ 封面图片 - - - 报名状态 - - 支付状态 @@ -2336,11 +2331,6 @@ 赛事状态 - - - 报名状态 - - 支付状态 @@ -2441,11 +2431,6 @@ 报名ID - - - 报名状态 - - 支付状态 @@ -4409,9 +4394,9 @@ 赛事名称 - + - 报名状态 + 支付状态 @@ -4454,9 +4439,9 @@ 比赛结束时间 - + - 报名状态 + 支付状态 @@ -5069,11 +5054,6 @@ 报名时间 - - - 报名状态 - - 报名项目详情列表 @@ -5109,9 +5089,9 @@ 报名ID列表 - + - 审核状态 (2-通过, 3-拒绝) + 审核状态 (1-通过, 2-拒绝) @@ -8331,11 +8311,21 @@ 订单类型 + + + 订单类型文本 + + 订单状态 + + + 订单状态文本 + + 赛事名称 @@ -8371,6 +8361,11 @@ 支付凭证URL + + + 报名方式 + + 原始金额 @@ -8391,6 +8386,21 @@ 创建时间 + + + 关联订单号 + + + + + 联系人姓名 + + + + + 联系人电话 + + 订单项目DTO @@ -8511,6 +8521,16 @@ 结束时间 + + + 订单ID列表(批量更新) + + + + + 支付状态:0-未支付,1-已支付,3-已退款 + + 订单管理服务 @@ -8531,9 +8551,9 @@ 获取订单详情 - + - 更新订单状态 + 批量更新订单支付状态 @@ -8548,7 +8568,7 @@ - 删除订单 + 删除订单(软删除) diff --git a/YD_Event.Core/Entities/EventRegistration.cs b/YD_Event.Core/Entities/EventRegistration.cs index d3576d2..f790594 100644 --- a/YD_Event.Core/Entities/EventRegistration.cs +++ b/YD_Event.Core/Entities/EventRegistration.cs @@ -53,12 +53,7 @@ public class EventRegistration : Entity, ISoftDelete, ICreatedUserId, ICre public decimal TotalAmount { get; set; } /// - /// 报名状态:0-待提交,1-待审核,2-审核通过,3-审核拒绝,4-已取消 - /// - public int RegistrationStatus { get; set; } - - /// - /// 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款 + /// 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消 /// public int PaymentStatus { get; set; } diff --git a/YD_Event.Core/YD_Event.Core.xml b/YD_Event.Core/YD_Event.Core.xml index 1845ec7..0acb848 100644 --- a/YD_Event.Core/YD_Event.Core.xml +++ b/YD_Event.Core/YD_Event.Core.xml @@ -1773,14 +1773,9 @@ 总费用 - - - 报名状态:0-待提交,1-待审核,2-审核通过,3-审核拒绝,4-已取消 - - - 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款 + 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消