596 lines
24 KiB
C#
596 lines
24 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
||
using YD_Event.Application.Client.Dtos;
|
||
using YD_Event.Core.Entities;
|
||
using YD_Event.Core.Enum;
|
||
using SqlSugar;
|
||
using Furion.DatabaseAccessor;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Furion.FriendlyException;
|
||
using System.Security.Claims;
|
||
|
||
namespace YD_Event.Application.Client;
|
||
|
||
/// <summary>
|
||
/// 小程序-赛事接口
|
||
/// </summary>
|
||
[ApiDescriptionSettings("微信小程序接口")]
|
||
public class EventClientController : IDynamicApiController
|
||
{
|
||
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
|
||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
|
||
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
|
||
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
|
||
private readonly ISqlSugarRepository<EventRegistrationItem> _registrationItemRepository;
|
||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Banner> _bannerRepository;
|
||
private readonly ISqlSugarRepository<EventUnit> _unitRepository;
|
||
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
|
||
private readonly ISqlSugarRepository<EventRegistrationLimit> _limitRepository;
|
||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||
private readonly IIdGenerator _idGenerator;
|
||
|
||
public EventClientController(
|
||
ISqlSugarRepository<EventInfo> eventRepository,
|
||
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
|
||
ISqlSugarRepository<ProjectGroup> groupRepository,
|
||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||
ISqlSugarRepository<EventRegistrationItem> registrationItemRepository,
|
||
ISqlSugarRepository<YD_Event.Core.Entities.Banner> bannerRepository,
|
||
ISqlSugarRepository<EventUnit> unitRepository,
|
||
ISqlSugarRepository<EventRegistrationPerson> personRepository,
|
||
ISqlSugarRepository<EventRegistrationLimit> limitRepository,
|
||
IHttpContextAccessor httpContextAccessor,
|
||
IIdGenerator idGenerator)
|
||
{
|
||
_eventRepository = eventRepository;
|
||
_projectRepository = projectRepository;
|
||
_groupRepository = groupRepository;
|
||
_registrationRepository = registrationRepository;
|
||
_registrationItemRepository = registrationItemRepository;
|
||
_bannerRepository = bannerRepository;
|
||
_unitRepository = unitRepository;
|
||
_personRepository = personRepository;
|
||
_limitRepository = limitRepository;
|
||
_httpContextAccessor = httpContextAccessor;
|
||
_idGenerator = idGenerator;
|
||
}
|
||
|
||
private long GetCurrentUserId()
|
||
{
|
||
var userIdStr = _httpContextAccessor.HttpContext?.User?.FindFirst(AuthClaimsConst.AuthIdKey)?.Value;
|
||
if (string.IsNullOrEmpty(userIdStr) || !long.TryParse(userIdStr, out long userId))
|
||
{
|
||
throw Oops.Bah("未登录或登录已失效");
|
||
}
|
||
return userId;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取轮播图列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("banners")]
|
||
[AllowAnonymous]
|
||
public async Task<List<BannerDto>> GetBannerList()
|
||
{
|
||
var list = await _bannerRepository.AsQueryable()
|
||
.Where(b => !b.DeleteMark && b.Status == AvailabilityStatus.Enable)
|
||
.OrderByDescending(b => b.Sort)
|
||
.ToListAsync();
|
||
|
||
return list.Select(b => new BannerDto
|
||
{
|
||
Title = b.Title,
|
||
ImageUrl = b.ImageUrl,
|
||
LinkType = b.LinkType,
|
||
LinkUrl = b.LinkUrl,
|
||
EventId = b.EventId
|
||
}).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取赛事列表
|
||
/// </summary>
|
||
/// <param name="page">页码</param>
|
||
/// <param name="pageSize">页大小</param>
|
||
/// <param name="status">状态筛选:0-全部 1-报名中 2-比赛中 3-已结束</param>
|
||
/// <param name="keyword">搜索关键字</param>
|
||
/// <returns></returns>
|
||
[HttpGet("list")]
|
||
[AllowAnonymous] // 允许未登录查看列表?根据需求,原型中有“我的”,可能需要登录。但通常列表可公开。这里先设为允许匿名,获取详情再校验。
|
||
// 修正:Class上有[Authorize],如果需要匿名需显式[AllowAnonymous]。
|
||
// 假设小程序进入即登录,保持Authorize
|
||
public async Task<PageResult<EventListDto>> GetEventList([FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] int status = 0, [FromQuery] string? keyword = null)
|
||
{
|
||
var query = _eventRepository.AsQueryable()
|
||
.Where(e => !e.DeleteMark && e.Status == AvailabilityStatus.Enable)
|
||
.WhereIF(!string.IsNullOrEmpty(keyword), e => e.EventName.Contains(keyword));
|
||
|
||
// 状态筛选逻辑
|
||
// 1-报名中: Now >= RegStart && Now <= RegEnd
|
||
// 2-比赛中: Now >= MatchStart && Now <= MatchEnd
|
||
// 3-已结束: Now > MatchEnd
|
||
var now = DateTime.Now;
|
||
if (status == 1)
|
||
{
|
||
query = query.Where(e => now >= e.RegistrationStartTime && now <= e.RegistrationEndTime);
|
||
}
|
||
else if (status == 2)
|
||
{
|
||
query = query.Where(e => now >= e.MatchStartTime && now <= e.MatchEndTime);
|
||
}
|
||
else if (status == 3)
|
||
{
|
||
query = query.Where(e => now > e.MatchEndTime);
|
||
}
|
||
|
||
// 排序:优先按报名开始时间倒序
|
||
query = query.OrderByDescending(e => e.RegistrationStartTime);
|
||
|
||
var list = await query.ToPagedListAsync(new Pagination { PageNo = page, PageSize = pageSize });
|
||
|
||
var result = new PageResult<EventListDto>
|
||
{
|
||
PageNo = list.PageNo,
|
||
PageSize = list.PageSize,
|
||
Total = list.Total,
|
||
Pages = list.Pages,
|
||
Rows = list.Rows.Select(e => new EventListDto
|
||
{
|
||
Id = e.Id,
|
||
EventName = e.EventName,
|
||
CoverImage = e.CoverImage,
|
||
EventStatus = CalculateEventStatus(e), // 动态计算状态
|
||
RegistrationStartTime = e.RegistrationStartTime,
|
||
RegistrationEndTime = e.RegistrationEndTime,
|
||
MatchStartTime = e.MatchStartTime,
|
||
MatchEndTime = e.MatchEndTime,
|
||
Address = $"{e.Province}{e.City}{e.District}{e.DetailAddress}"
|
||
}).ToList()
|
||
};
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取赛事详情
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("{id}")]
|
||
[AllowAnonymous]
|
||
public async Task<EventDetailDto> GetEventDetail(long id)
|
||
{
|
||
var evt = await _eventRepository.GetFirstAsync(e => e.Id == id && !e.DeleteMark);
|
||
if (evt == null) throw Oops.Bah("赛事不存在");
|
||
|
||
// 获取项目及组别
|
||
var projects = await _projectRepository.AsQueryable()
|
||
.LeftJoin<ProjectType>((p, t) => p.ProjectTypeId == t.Id)
|
||
.Where(p => p.EventId == id && !p.DeleteMark && p.Status == AvailabilityStatus.Enable)
|
||
.Select((p, t) => new {
|
||
p.Id,
|
||
p.Name,
|
||
p.Fee,
|
||
TypeName = t.Name
|
||
})
|
||
.ToListAsync();
|
||
|
||
var projectIds = projects.Select(p => p.Id).ToList();
|
||
var groups = await _groupRepository.AsQueryable()
|
||
.Where(g => projectIds.Contains(g.ProjectId) && !g.DeleteMark)
|
||
.ToListAsync();
|
||
|
||
// 获取单位
|
||
var units = await _unitRepository.AsQueryable()
|
||
.Where(u => u.EventId == id && !u.DeleteMark)
|
||
.OrderBy(u => u.Sort)
|
||
.ToListAsync();
|
||
|
||
// 获取限制规则
|
||
var limit = await _limitRepository.GetFirstAsync(l => l.EventId == id && !l.DeleteMark);
|
||
|
||
var detail = new EventDetailDto
|
||
{
|
||
Id = evt.Id,
|
||
EventName = evt.EventName,
|
||
CoverImage = evt.CoverImage,
|
||
EventStatus = CalculateEventStatus(evt),
|
||
RegistrationStartTime = evt.RegistrationStartTime,
|
||
RegistrationEndTime = evt.RegistrationEndTime,
|
||
MatchStartTime = evt.MatchStartTime,
|
||
MatchEndTime = evt.MatchEndTime,
|
||
Address = $"{evt.Province}{evt.City}{evt.District}{evt.DetailAddress}",
|
||
EventVideo = evt.EventVideo,
|
||
EventType = evt.EventType,
|
||
ChargeMode = evt.ChargeMode,
|
||
RegistrationType = evt.RegistrationType,
|
||
EventIntroduction = evt.EventIntroduction,
|
||
MaterialRemark = evt.MaterialRemark,
|
||
MaterialUploadStartTime = evt.MaterialUploadStartTime,
|
||
MaterialUploadEndTime = evt.MaterialUploadEndTime,
|
||
// 模拟规则文本,实际应从 EventInfo 扩展字段或关联表读取
|
||
RefundRule = "开赛前7天扣除金额5%,3-7天扣除金额10%,3天内扣除金额20%",
|
||
PointsRule = "参与积分:5积分;名次积分:1-8名 15积分,9-20名 10积分",
|
||
|
||
IndividualProjectLimit = limit?.IndividualProjectLimit ?? 0,
|
||
TeamProjectLimit = limit?.TeamProjectLimit ?? 0,
|
||
|
||
Units = units.Select(u => new EventUnitDto
|
||
{
|
||
UnitType = u.UnitType,
|
||
UnitName = u.UnitName,
|
||
LogoUrl = u.LogoUrl
|
||
}).ToList(),
|
||
|
||
Projects = projects.Select(p => new EventProjectDto
|
||
{
|
||
Id = p.Id,
|
||
Name = p.Name,
|
||
TypeName = p.TypeName,
|
||
Fee = p.Fee,
|
||
Groups = groups.Where(g => g.ProjectId == p.Id).Select(g => new EventProjectGroupDto
|
||
{
|
||
Id = g.Id,
|
||
GroupName = g.GroupName,
|
||
GenderRequirement = g.Gender == Gender.Male ? "男" : (g.Gender == Gender.Female ? "女" : "不限"),
|
||
AgeRequirement = $"{g.BirthDateStart:yyyy-MM-dd} 至 {g.BirthDateEnd:yyyy-MM-dd}"
|
||
}).ToList()
|
||
}).ToList()
|
||
};
|
||
|
||
return detail;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提交赛事报名
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("apply")]
|
||
[UnitOfWork]
|
||
public async Task<long> SubmitRegistration([FromBody] SubmitRegistrationInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
// 0. 校验报名模式
|
||
if (input.RegistrationMode == 2) // 假设2为团队
|
||
throw Oops.Bah("团队报名请前往网页端进行操作");
|
||
|
||
var evt = await _eventRepository.GetFirstAsync(e => e.Id == input.EventId);
|
||
if (evt == null) throw Oops.Bah("赛事不存在");
|
||
|
||
// 1. 校验时间
|
||
if (DateTime.Now < evt.RegistrationStartTime || DateTime.Now > evt.RegistrationEndTime)
|
||
throw Oops.Bah("不在报名时间内");
|
||
|
||
// 2. 校验重复报名 (同一赛事同一人只能报一次?还是可以多次?通常一次报名包含多个项目)
|
||
// 假设同一用户对同一赛事只能有一个“未取消”的报名记录
|
||
var exist = await _registrationRepository.IsAnyAsync(r => r.EventId == input.EventId && r.CreatedUserId == userId && r.RegistrationStatus != 4); // 4=已取消
|
||
if (exist) throw Oops.Bah("您已报名该赛事,请勿重复提交");
|
||
|
||
// 3. 校验项目有效性 & 限制
|
||
if (input.Items == null || !input.Items.Any()) throw Oops.Bah("请至少选择一个项目");
|
||
|
||
var limit = await _limitRepository.GetFirstAsync(l => l.EventId == input.EventId && !l.DeleteMark);
|
||
if (limit != null)
|
||
{
|
||
// 简单校验项目总数,更严谨需按项目类型统计
|
||
if (input.Items.Count > limit.IndividualProjectLimit)
|
||
throw Oops.Bah($"每人最多可报{limit.IndividualProjectLimit}个项目");
|
||
}
|
||
|
||
// 4. 创建报名主表
|
||
var registrationId = _idGenerator.NewLong();
|
||
var registration = new EventRegistration
|
||
{
|
||
Id = registrationId,
|
||
EventId = input.EventId,
|
||
RegistrationMode = input.RegistrationMode,
|
||
TeamName = input.RegistrationMode == 2 ? input.TeamName : null,
|
||
ContactName = input.ContactName,
|
||
ContactPhone = input.ContactPhone,
|
||
RegistrationStatus = 0, // 待提交/待支付
|
||
PaymentStatus = 0, // 未支付
|
||
RegistrationTime = DateTime.Now,
|
||
CreatedUserId = userId,
|
||
CreatedTime = DateTime.Now,
|
||
Status = AvailabilityStatus.Enable,
|
||
TotalPersonCount = 0 // 稍后计算
|
||
};
|
||
|
||
// 5. 创建报名明细 & 参赛人员 & 计算费用
|
||
decimal totalAmount = 0;
|
||
int totalPerson = 0;
|
||
var regItems = new List<EventRegistrationItem>();
|
||
var persons = new List<EventRegistrationPerson>();
|
||
|
||
foreach (var item in input.Items)
|
||
{
|
||
var project = await _projectRepository.GetFirstAsync(p => p.Id == item.ProjectId);
|
||
if (project == null) throw Oops.Bah($"项目不存在: {item.ProjectId}");
|
||
|
||
// 校验组别
|
||
// 略,假设前端传参正确,或需根据 GroupId 查
|
||
|
||
if (item.Persons == null || !item.Persons.Any())
|
||
throw Oops.Bah($"项目[{project.Name}]未填写参赛人信息");
|
||
|
||
var regItemId = _idGenerator.NewLong();
|
||
var regItem = new EventRegistrationItem
|
||
{
|
||
Id = regItemId,
|
||
RegistrationId = registrationId,
|
||
ProjectId = item.ProjectId,
|
||
ProjectName = project.Name,
|
||
GroupName = item.GroupName,
|
||
UnitPrice = project.Fee,
|
||
PersonCount = item.Persons.Count,
|
||
TotalPrice = project.Fee * item.Persons.Count,
|
||
CreatedUserId = userId,
|
||
CreatedTime = DateTime.Now
|
||
};
|
||
regItems.Add(regItem);
|
||
totalAmount += regItem.TotalPrice;
|
||
totalPerson += regItem.PersonCount;
|
||
|
||
// 添加参赛人员
|
||
foreach (var pInput in item.Persons)
|
||
{
|
||
persons.Add(new EventRegistrationPerson
|
||
{
|
||
Id = _idGenerator.NewLong(),
|
||
RegistrationId = registrationId,
|
||
RegistrationItemId = regItemId,
|
||
ProjectId = item.ProjectId,
|
||
PersonType = 1, // 运动员
|
||
Name = pInput.Name,
|
||
Gender = pInput.Gender,
|
||
IdCard = pInput.IdCard,
|
||
BirthDate = pInput.BirthDate,
|
||
Phone = pInput.Phone,
|
||
GroupName = item.GroupName,
|
||
ProjectName = project.Name,
|
||
CreatedUserId = userId,
|
||
CreatedTime = DateTime.Now
|
||
});
|
||
}
|
||
}
|
||
|
||
registration.TotalAmount = totalAmount;
|
||
registration.TotalPersonCount = totalPerson;
|
||
registration.OrderNo = DateTime.Now.ToString("yyyyMMddHHmmss") + new Random().Next(1000, 9999); // 简易订单号
|
||
|
||
await _registrationRepository.InsertAsync(registration);
|
||
await _registrationItemRepository.InsertRangeAsync(regItems);
|
||
await _personRepository.InsertRangeAsync(persons);
|
||
|
||
return registrationId;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取支付信息
|
||
/// </summary>
|
||
[HttpGet("payment-info/{registrationId}")]
|
||
public async Task<PaymentInfoDto> GetPaymentInfo(long registrationId)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == registrationId && r.CreatedUserId == userId);
|
||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||
|
||
return new PaymentInfoDto
|
||
{
|
||
RegistrationId = reg.Id,
|
||
Amount = reg.TotalAmount,
|
||
PaymentMethod = reg.PaymentMethod,
|
||
BankAccountName = "上海跃动文化科技有限公司",
|
||
BankAccountNo = "456498465198456261",
|
||
BankName = "招商银行", // 示例
|
||
WechatPayParams = new { appId = "wx8888888888888888", timeStamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), nonceStr = Guid.NewGuid().ToString("N"), package = "prepay_id=wx...", signType = "MD5", paySign = "..." } // 模拟
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上传支付凭证(线下支付)
|
||
/// </summary>
|
||
[HttpPost("upload-voucher/{registrationId}")]
|
||
public async Task<bool> UploadPaymentVoucher(long registrationId, [FromBody] UploadVoucherInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == registrationId && r.CreatedUserId == userId);
|
||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||
|
||
reg.PaymentMethod = 1; // 线下
|
||
reg.PaymentProofUrl = input.VoucherUrl;
|
||
reg.RegistrationStatus = 1; // 待审核
|
||
reg.UpdatedTime = DateTime.Now;
|
||
reg.UpdatedUserId = userId;
|
||
|
||
return await _registrationRepository.UpdateAsync(reg);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新参赛人信息
|
||
/// </summary>
|
||
[HttpPost("update-player")]
|
||
public async Task<bool> UpdateRegistrationPlayer([FromBody] UpdatePlayerInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var person = await _personRepository.GetFirstAsync(p => p.Id == input.PersonId);
|
||
if (person == null) throw Oops.Bah("参赛人不存在");
|
||
|
||
// 校验权限:确保是该用户创建的报名
|
||
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == person.RegistrationId);
|
||
if (reg == null || reg.CreatedUserId != userId) throw Oops.Bah("无权操作");
|
||
|
||
person.Name = input.Name;
|
||
person.IdCard = input.IdCard;
|
||
person.Gender = input.Gender;
|
||
person.Phone = input.Phone;
|
||
person.UpdatedTime = DateTime.Now;
|
||
person.UpdatedUserId = userId;
|
||
|
||
return await _personRepository.UpdateAsync(person);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取我的已报赛事列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("my-events")]
|
||
public async Task<PageResult<MyEventListDto>> GetMyEventList([FromQuery] int page = 1, [FromQuery] int pageSize = 10)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var query = _registrationRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((r, e) => r.EventId == e.Id)
|
||
.Where(r => r.CreatedUserId == userId && !r.DeleteMark)
|
||
.OrderByDescending(r => r.RegistrationTime)
|
||
.Select((r, e) => new MyEventListDto
|
||
{
|
||
RegistrationId = r.Id,
|
||
EventId = r.EventId,
|
||
EventName = e.EventName,
|
||
CoverImage = e.CoverImage,
|
||
RegistrationStatus = r.RegistrationStatus,
|
||
PaymentStatus = r.PaymentStatus,
|
||
RegistrationTime = r.RegistrationTime,
|
||
ProjectCount = SqlFunc.Subqueryable<EventRegistrationItem>().Where(i => i.RegistrationId == r.Id).Count()
|
||
});
|
||
|
||
return await query.ToPagedListAsync(new Pagination { PageNo = page, PageSize = pageSize });
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取报名详情(包含参赛人)
|
||
/// </summary>
|
||
[HttpGet("my-registration/{registrationId}")]
|
||
public async Task<RegistrationDetailDto> GetRegistrationDetail(long registrationId)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var reg = await _registrationRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((r, e) => r.EventId == e.Id)
|
||
.Where(r => r.Id == registrationId && r.CreatedUserId == userId)
|
||
.Select((r, e) => new {
|
||
r.Id,
|
||
r.EventId,
|
||
e.EventName,
|
||
e.CoverImage,
|
||
r.RegistrationStatus,
|
||
r.PaymentStatus,
|
||
r.TotalAmount,
|
||
r.OrderNo,
|
||
r.RegistrationTime,
|
||
r.ReviewRemark,
|
||
// 为了计算 EventStatus
|
||
RegStart = e.RegistrationStartTime,
|
||
RegEnd = e.RegistrationEndTime,
|
||
MatchStart = e.MatchStartTime,
|
||
MatchEnd = e.MatchEndTime
|
||
})
|
||
.FirstAsync();
|
||
|
||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||
|
||
// 计算 EventStatus
|
||
EventStatus status = EventStatus.Enrolling;
|
||
var now = DateTime.Now;
|
||
if (now >= reg.RegStart && now <= reg.RegEnd) status = EventStatus.Enrolling;
|
||
else if (now >= reg.MatchStart && now <= reg.MatchEnd) status = EventStatus.Ongoing;
|
||
else if (now > reg.MatchEnd) status = EventStatus.Ended;
|
||
|
||
// 获取 Items 和 Persons
|
||
var items = await _registrationItemRepository.AsQueryable()
|
||
.Where(i => i.RegistrationId == registrationId)
|
||
.ToListAsync();
|
||
|
||
var persons = await _personRepository.AsQueryable()
|
||
.Where(p => p.RegistrationId == registrationId)
|
||
.ToListAsync();
|
||
|
||
return new RegistrationDetailDto
|
||
{
|
||
RegistrationId = reg.Id,
|
||
EventId = reg.EventId,
|
||
EventName = reg.EventName,
|
||
CoverImage = reg.CoverImage,
|
||
EventStatus = status,
|
||
RegistrationStatus = reg.RegistrationStatus,
|
||
PaymentStatus = reg.PaymentStatus,
|
||
TotalAmount = reg.TotalAmount,
|
||
OrderNo = reg.OrderNo,
|
||
RegistrationTime = reg.RegistrationTime,
|
||
ReviewRemark = reg.ReviewRemark,
|
||
Items = items.Select(i => new RegistrationItemDto
|
||
{
|
||
Id = i.Id,
|
||
ProjectName = i.ProjectName,
|
||
GroupName = i.GroupName,
|
||
Price = i.UnitPrice, // 单价
|
||
Persons = persons.Where(p => p.RegistrationItemId == i.Id).Select(p => new RegistrationPersonDto
|
||
{
|
||
Id = p.Id,
|
||
Name = p.Name,
|
||
IdCard = p.IdCard,
|
||
Gender = p.Gender,
|
||
Phone = p.Phone
|
||
}).ToList()
|
||
}).ToList()
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询报名状态
|
||
/// </summary>
|
||
/// <param name="registrationId"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("status/{registrationId}")]
|
||
public async Task<RegistrationStatusDto> GetRegistrationStatus(long registrationId)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == registrationId && r.CreatedUserId == userId);
|
||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||
|
||
return new RegistrationStatusDto
|
||
{
|
||
RegistrationId = reg.Id,
|
||
RegistrationStatus = reg.RegistrationStatus,
|
||
PaymentStatus = reg.PaymentStatus,
|
||
RejectReason = reg.ReviewRemark
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消报名
|
||
/// </summary>
|
||
/// <param name="registrationId"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("cancel/{registrationId}")]
|
||
public async Task<bool> CancelRegistration(long registrationId)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == registrationId && r.CreatedUserId == userId);
|
||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||
|
||
// 校验状态:只有待提交、待审核、未支付状态可直接取消
|
||
// 已支付状态需走退款流程(暂不实现)
|
||
if (reg.PaymentStatus == 1) throw Oops.Bah("已支付订单请联系客服退款");
|
||
if (reg.RegistrationStatus == 4) throw Oops.Bah("订单已取消,无需重复操作");
|
||
|
||
reg.RegistrationStatus = 4; // 4=已取消
|
||
reg.UpdatedTime = DateTime.Now;
|
||
reg.UpdatedUserId = userId;
|
||
|
||
return await _registrationRepository.UpdateAsync(reg);
|
||
}
|
||
|
||
private EventStatus CalculateEventStatus(EventInfo e)
|
||
{
|
||
var now = DateTime.Now;
|
||
if (now >= e.RegistrationStartTime && now <= e.RegistrationEndTime) return EventStatus.Enrolling; // 报名中
|
||
if (now >= e.MatchStartTime && now <= e.MatchEndTime) return EventStatus.Ongoing; // 比赛中
|
||
if (now > e.MatchEndTime) return EventStatus.Ended; // 已结束
|
||
return EventStatus.Enrolling; // 默认? 或者新增未开始状态
|
||
}
|
||
}
|