后台登录注册
This commit is contained in:
parent
239fb777f3
commit
b2dafc2ad2
@ -1,4 +1,5 @@
|
||||
using YD_Event.Application.Auth.Dtos;
|
||||
using YD_Event.Core.Enum;
|
||||
|
||||
namespace YD_Event.Application.Auth;
|
||||
/// <summary>
|
||||
@ -8,18 +9,21 @@ namespace YD_Event.Application.Auth;
|
||||
public class AuthService : IDynamicApiController
|
||||
{
|
||||
private readonly ISqlSugarRepository<SysUser> _sysUseRepository;
|
||||
private readonly ISqlSugarRepository<SysUserRole> _sysUserRoleRepository;
|
||||
private readonly ICaptcha _captcha;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly IEasyCachingProvider _easyCachingProvider;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AuthService(ISqlSugarRepository<SysUser> sysUseRepository,
|
||||
ISqlSugarRepository<SysUserRole> sysUserRoleRepository,
|
||||
ICaptcha captcha,
|
||||
IIdGenerator idGenerator,
|
||||
IEasyCachingProvider easyCachingProvider,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_sysUseRepository = sysUseRepository;
|
||||
_sysUserRoleRepository = sysUserRoleRepository;
|
||||
_captcha = captcha;
|
||||
_idGenerator = idGenerator;
|
||||
_easyCachingProvider = easyCachingProvider;
|
||||
@ -95,5 +99,147 @@ public class AuthService : IDynamicApiController
|
||||
return new FileStreamResult(stream, "image/gif");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("用户注册")]
|
||||
[HttpPost]
|
||||
[UnitOfWork]
|
||||
public async Task Register(RegisterInput dto)
|
||||
{
|
||||
var codeCacheKey = $"sms:code:{dto.Phone}";
|
||||
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
|
||||
|
||||
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
|
||||
{
|
||||
throw Oops.Bah("验证码错误或已过期");
|
||||
}
|
||||
|
||||
}
|
||||
var existAccount = await _sysUseRepository.IsAnyAsync(x => x.Account == dto.Account);
|
||||
if (existAccount)
|
||||
{
|
||||
throw Oops.Bah("该账号已被注册");
|
||||
}
|
||||
|
||||
var existPhone = await _sysUseRepository.IsAnyAsync(x => x.Mobile == dto.Phone);
|
||||
if (existPhone)
|
||||
{
|
||||
throw Oops.Bah("该手机号已被注册");
|
||||
}
|
||||
|
||||
var user = new SysUser
|
||||
{
|
||||
Id = _idGenerator.NewLong(),
|
||||
Account = dto.Account,
|
||||
Name = dto.Account,
|
||||
Mobile = dto.Phone,
|
||||
Gender = Gender.Unknown,
|
||||
OrgId = 0,
|
||||
Status = AvailabilityStatus.Enable,
|
||||
DeleteMark = false,
|
||||
CreatedTime = DateTime.Now,
|
||||
CreatedUserId = 0
|
||||
};
|
||||
|
||||
user.Password = MD5Encryption.Encrypt($"{_idGenerator.Encode(user.Id)}{dto.Password}");
|
||||
|
||||
await _sysUseRepository.InsertAsync(user);
|
||||
|
||||
// 为新用户分配普通用户角色 (RoleId = 1001)
|
||||
var userRole = new SysUserRole
|
||||
{
|
||||
Id = _idGenerator.NewLong(),
|
||||
UserId = user.Id,
|
||||
RoleId = 1001,
|
||||
CreatedTime = DateTime.Now,
|
||||
CreatedUserId = 0,
|
||||
DeleteMark = false
|
||||
};
|
||||
await _sysUserRoleRepository.InsertAsync(userRole);
|
||||
|
||||
await _easyCachingProvider.RemoveAsync(codeCacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 短信验证码登录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("短信验证码登录")]
|
||||
[HttpPost]
|
||||
public async Task SmsSignIn(SmsLoginInput dto)
|
||||
{
|
||||
var codeCacheKey = $"sms:code:{dto.Phone}";
|
||||
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
|
||||
|
||||
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
|
||||
{
|
||||
throw Oops.Bah("验证码错误或已过期");
|
||||
}
|
||||
|
||||
SysUser user = await _sysUseRepository.GetFirstAsync(x => x.Mobile == dto.Phone);
|
||||
if (user == null)
|
||||
{
|
||||
throw Oops.Bah("该手机号尚未注册");
|
||||
}
|
||||
|
||||
var context = _httpContextAccessor.HttpContext;
|
||||
if (user.Status == AvailabilityStatus.Disable || (user.LockExpired.HasValue && DateTime.Now < user.LockExpired))
|
||||
{
|
||||
throw Oops.Bah("您的账号被锁定");
|
||||
}
|
||||
|
||||
long uniqueId = _idGenerator.NewLong();
|
||||
string token = JWTEncryption.Encrypt(new Dictionary<string, object>()
|
||||
{
|
||||
[AuthClaimsConst.AuthIdKey] = user.Id,
|
||||
[AuthClaimsConst.AccountKey] = user.Account,
|
||||
[AuthClaimsConst.UuidKey] = uniqueId,
|
||||
[AuthClaimsConst.AuthPlatformTypeKey] = AuthPlatformType.Manager
|
||||
});
|
||||
var refreshToken = JWTEncryption.GenerateRefreshToken(token);
|
||||
context.SigninToSwagger(token);
|
||||
context!.Response.Headers["access-token"] = token;
|
||||
context.Response.Headers["x-access-token"] = refreshToken;
|
||||
|
||||
await _easyCachingProvider.RemoveAsync(codeCacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置密码
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("重置密码")]
|
||||
[HttpPost]
|
||||
public async Task ResetPassword(ResetPasswordInput dto)
|
||||
{
|
||||
var codeCacheKey = $"sms:code:{dto.Phone}";
|
||||
var cachedCode = await _easyCachingProvider.GetAsync<string>(codeCacheKey);
|
||||
|
||||
if (!cachedCode.HasValue || cachedCode.Value != dto.Code)
|
||||
{
|
||||
throw Oops.Bah("验证码错误或已过期");
|
||||
}
|
||||
|
||||
SysUser user = await _sysUseRepository.GetFirstAsync(x => x.Mobile == dto.Phone);
|
||||
if (user == null)
|
||||
{
|
||||
throw Oops.Bah("该手机号尚未注册");
|
||||
}
|
||||
|
||||
if (user.Status == AvailabilityStatus.Disable || (user.LockExpired.HasValue && DateTime.Now < user.LockExpired))
|
||||
{
|
||||
throw Oops.Bah("您的账号被锁定");
|
||||
}
|
||||
|
||||
user.Password = MD5Encryption.Encrypt($"{_idGenerator.Encode(user.Id)}{dto.NewPassword}");
|
||||
user.UpdatedTime = DateTime.Now;
|
||||
|
||||
await _sysUseRepository.UpdateAsync(user);
|
||||
|
||||
await _easyCachingProvider.RemoveAsync(codeCacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
108
YD_Event.Application/Auth/Dtos/AuthDtos.cs
Normal file
108
YD_Event.Application/Auth/Dtos/AuthDtos.cs
Normal file
@ -0,0 +1,108 @@
|
||||
#nullable enable
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace YD_Event.Application.Auth.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册输入参数
|
||||
/// </summary>
|
||||
public class RegisterInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "手机号不能为空")]
|
||||
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
|
||||
public string Phone { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号不能为空")]
|
||||
[MinLength(3, ErrorMessage = "账号至少3个字符")]
|
||||
[MaxLength(32, ErrorMessage = "账号最多32个字符")]
|
||||
public string Account { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "密码不能为空")]
|
||||
[MinLength(6, ErrorMessage = "密码至少6个字符")]
|
||||
[MaxLength(18, ErrorMessage = "密码最多18个字符")]
|
||||
public string Password { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 确认密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "请再次输入密码")]
|
||||
[Compare(nameof(Password), ErrorMessage = "两次输入的密码不一致")]
|
||||
public string ConfirmPassword { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 短信验证码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "验证码不能为空")]
|
||||
[StringLength(6, MinimumLength = 4, ErrorMessage = "验证码格式不正确")]
|
||||
public string Code { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 同意用户协议
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "请同意用户协议")]
|
||||
public bool AgreeTerms { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 短信登录输入参数
|
||||
/// </summary>
|
||||
public class SmsLoginInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "手机号不能为空")]
|
||||
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
|
||||
public string Phone { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "验证码不能为空")]
|
||||
[StringLength(6, MinimumLength = 4, ErrorMessage = "验证码格式不正确")]
|
||||
public string Code { get; set; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置密码输入参数
|
||||
/// </summary>
|
||||
public class ResetPasswordInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "手机号不能为空")]
|
||||
[RegularExpression(@"^1[3456789]\d{9}$", ErrorMessage = "手机号格式不正确")]
|
||||
public string Phone { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "验证码不能为空")]
|
||||
[StringLength(6, MinimumLength = 4, ErrorMessage = "验证码格式不正确")]
|
||||
public string Code { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 新密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "密码不能为空")]
|
||||
[MinLength(6, ErrorMessage = "密码至少6个字符")]
|
||||
[MaxLength(18, ErrorMessage = "密码最多18个字符")]
|
||||
public string NewPassword { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 确认新密码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "请再次输入密码")]
|
||||
[Compare(nameof(NewPassword), ErrorMessage = "两次输入的密码不一致")]
|
||||
public string ConfirmNewPassword { get; set; } = null!;
|
||||
}
|
||||
@ -3,6 +3,32 @@ using YD_Event.Core.Enum;
|
||||
|
||||
namespace YD_Event.Application.Client.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 客户端赛事查询输入
|
||||
/// </summary>
|
||||
public class EventClientQueryInput : Pagination
|
||||
{
|
||||
/// <summary>
|
||||
/// 搜索关键字
|
||||
/// </summary>
|
||||
public string? Keyword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态筛选:0-全部 1-报名中 2-比赛中 3-已结束
|
||||
/// </summary>
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 赛事类型
|
||||
/// </summary>
|
||||
public EventFormat? EventType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收费模式
|
||||
/// </summary>
|
||||
public ChargeMode? ChargeMode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 赛事列表项DTO
|
||||
/// </summary>
|
||||
|
||||
@ -2,10 +2,8 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using YD_Event.Application.Client.Dtos;
|
||||
using YD_Event.Application.Event;
|
||||
using YD_Event.Core.Entities;
|
||||
using YD_Event.Core.Enum;
|
||||
using YD_Event.Core.Domain.Pricing;
|
||||
using YD_Event.Core.Infrastructure.WeChat;
|
||||
using YD_Event.Core.Infrastructure.WeChat.Dto;
|
||||
using YD_Event.Core.Options;
|
||||
@ -41,6 +39,7 @@ public class EventClientController : IDynamicApiController
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Merchant> _merchantRepository;
|
||||
private readonly ISqlSugarRepository<PointsRule> _pointsRuleRepository;
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
|
||||
private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly WeChatPayService _weChatPayService;
|
||||
@ -64,6 +63,7 @@ public class EventClientController : IDynamicApiController
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Merchant> merchantRepository,
|
||||
ISqlSugarRepository<PointsRule> pointsRuleRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
||||
ISqlSugarRepository<ProjectType> projectTypeRepository,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IIdGenerator idGenerator,
|
||||
WeChatPayService weChatPayService,
|
||||
@ -86,6 +86,7 @@ public class EventClientController : IDynamicApiController
|
||||
_merchantRepository = merchantRepository;
|
||||
_pointsRuleRepository = pointsRuleRepository;
|
||||
_appUserRepository = appUserRepository;
|
||||
_projectTypeRepository = projectTypeRepository;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_idGenerator = idGenerator;
|
||||
_weChatPayService = weChatPayService;
|
||||
@ -109,6 +110,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <returns></returns>
|
||||
[HttpGet("banners")]
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取轮播图列表")]
|
||||
public async Task<List<BannerDto>> GetBannerList()
|
||||
{
|
||||
var list = await _bannerRepository.AsQueryable()
|
||||
@ -129,43 +131,36 @@ public class EventClientController : IDynamicApiController
|
||||
/// <summary>
|
||||
/// 获取赛事列表
|
||||
/// </summary>
|
||||
/// <param name="page">页码</param>
|
||||
/// <param name="pageSize">页大小</param>
|
||||
/// <param name="status">状态筛选:0-全部 1-报名中 2-比赛中 3-已结束</param>
|
||||
/// <param name="keyword">搜索关键字</param>
|
||||
/// <param name="input">查询参数</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)
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取赛事列表")]
|
||||
public async Task<PageResult<EventListDto>> GetEventList([FromQuery] EventClientQueryInput input)
|
||||
{
|
||||
var query = _eventRepository.AsQueryable()
|
||||
.Where(e => !e.DeleteMark && e.Status == AvailabilityStatus.Enable)
|
||||
.WhereIF(!string.IsNullOrEmpty(keyword), e => e.EventName.Contains(keyword));
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Keyword), e => e.EventName.Contains(input.Keyword))
|
||||
.WhereIF(input.EventType.HasValue, e => e.EventType == input.EventType)
|
||||
.WhereIF(input.ChargeMode.HasValue, e => e.ChargeMode == input.ChargeMode);
|
||||
|
||||
// 状态筛选逻辑
|
||||
// 1-报名中: Now >= RegStart && Now <= RegEnd
|
||||
// 2-比赛中: Now >= MatchStart && Now <= MatchEnd
|
||||
// 3-已结束: Now > MatchEnd
|
||||
var now = DateTime.Now;
|
||||
if (status == 1)
|
||||
if (input.Status == 1)
|
||||
{
|
||||
query = query.Where(e => now >= e.RegistrationStartTime && now <= e.RegistrationEndTime);
|
||||
}
|
||||
else if (status == 2)
|
||||
else if (input.Status == 2)
|
||||
{
|
||||
query = query.Where(e => now >= e.MatchStartTime && now <= e.MatchEndTime);
|
||||
}
|
||||
else if (status == 3)
|
||||
else if (input.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 list = await query.ToPagedListAsync(input);
|
||||
|
||||
var result = new PageResult<EventListDto>
|
||||
{
|
||||
@ -178,7 +173,7 @@ public class EventClientController : IDynamicApiController
|
||||
Id = e.Id,
|
||||
EventName = e.EventName,
|
||||
CoverImage = e.CoverImage,
|
||||
EventStatus = CalculateEventStatus(e), // 动态计算状态
|
||||
EventStatus = CalculateEventStatus(e),
|
||||
RegistrationStartTime = e.RegistrationStartTime,
|
||||
RegistrationEndTime = e.RegistrationEndTime,
|
||||
MatchStartTime = e.MatchStartTime,
|
||||
@ -197,6 +192,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
[AllowAnonymous]
|
||||
[DisplayName("获取赛事详情")]
|
||||
public async Task<EventDetailDto> GetEventDetail(long id)
|
||||
{
|
||||
var evt = await _eventRepository.GetFirstAsync(e => e.Id == id && !e.DeleteMark);
|
||||
@ -338,6 +334,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("calculate-amount")]
|
||||
[DisplayName("计算报名金额")]
|
||||
public async Task<CalculateAmountOutput> CalculateRegistrationAmount([FromBody] CalculateAmountInput input)
|
||||
{
|
||||
var evt = await _eventRepository.GetFirstAsync(e => e.Id == input.EventId && !e.DeleteMark);
|
||||
@ -431,6 +428,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <returns></returns>
|
||||
[HttpPost("apply")]
|
||||
[UnitOfWork]
|
||||
[DisplayName("提交赛事报名")]
|
||||
public async Task<long> SubmitRegistration([FromBody] SubmitRegistrationInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -457,10 +455,32 @@ public class EventClientController : IDynamicApiController
|
||||
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}个项目");
|
||||
}
|
||||
|
||||
var projectLimits = await _projectLimitRepository.AsQueryable()
|
||||
.Where(pl => pl.EventId == input.EventId && !pl.DeleteMark)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in input.Items)
|
||||
{
|
||||
var projectLimit = projectLimits.FirstOrDefault(pl => pl.ProjectId == item.ProjectId);
|
||||
if (projectLimit != null)
|
||||
{
|
||||
var currentCount = await _registrationItemRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistration>((ri, r) => ri.RegistrationId == r.Id)
|
||||
.Where((ri, r) => ri.ProjectId == item.ProjectId && r.RegistrationStatus != 4)
|
||||
.CountAsync();
|
||||
|
||||
if (currentCount >= projectLimit.LimitCount)
|
||||
{
|
||||
var eventProject = await _eventProjectRepository.GetFirstAsync(ep => ep.Id == item.ProjectId);
|
||||
var project = await _projectRepository.GetFirstAsync(p => p.Id == eventProject.ProjectId);
|
||||
throw Oops.Bah($"项目[{project?.Name}]已达到报名上限,无法继续报名");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 创建报名主表
|
||||
var registrationId = _idGenerator.NewLong();
|
||||
@ -563,6 +583,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <param name="input">支付信息查询输入参数,包含报名记录ID和OpenId</param>
|
||||
/// <returns>支付信息,包括微信支付参数(如果是微信支付)</returns>
|
||||
[HttpPost("payment-info")]
|
||||
[DisplayName("获取支付信息")]
|
||||
public async Task<PaymentInfoDto> GetPaymentInfo([FromBody] GetPaymentInfoInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -573,14 +594,15 @@ public class EventClientController : IDynamicApiController
|
||||
if (evt == null) throw Oops.Bah("赛事不存在");
|
||||
|
||||
var configOptions = _wechatTenpayClientOptionsMonitor.CurrentValue;
|
||||
var merchant = await _merchantRepository.GetFirstAsync(m => m.Id == evt.MerchantId && !m.DeleteMark);
|
||||
var paymentInfo = new PaymentInfoDto
|
||||
{
|
||||
RegistrationId = reg.Id,
|
||||
Amount = reg.TotalAmount,
|
||||
PaymentMethod = reg.PaymentMethod,
|
||||
BankAccountName = "上海跃动文化科技有限公司",
|
||||
BankAccountNo = "456498465198456261",
|
||||
BankName = "招商银行"
|
||||
BankAccountName = merchant?.MerchantName ?? "上海跃动文化科技有限公司",
|
||||
BankAccountNo = merchant?.AccountNumber ?? "456498465198456261",
|
||||
BankName = merchant?.BankName ?? "招商银行"
|
||||
};
|
||||
|
||||
if (reg.PaymentMethod == 2 && reg.TotalAmount > 0)
|
||||
@ -649,6 +671,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// 上传支付凭证(线下支付)
|
||||
/// </summary>
|
||||
[HttpPost("upload-voucher/{registrationId}")]
|
||||
[DisplayName("上传支付凭证")]
|
||||
public async Task<bool> UploadPaymentVoucher(long registrationId, [FromBody] UploadVoucherInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -668,6 +691,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// 更新参赛人信息
|
||||
/// </summary>
|
||||
[HttpPost("update-player")]
|
||||
[DisplayName("更新参赛人信息")]
|
||||
public async Task<bool> UpdateRegistrationPlayer([FromBody] UpdatePlayerInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -693,6 +717,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("my-events")]
|
||||
[DisplayName("获取我的已报赛事列表")]
|
||||
public async Task<PageResult<MyEventListDto>> GetMyEventList([FromQuery] int page = 1, [FromQuery] int pageSize = 10)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -720,6 +745,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// 获取报名详情(包含参赛人)
|
||||
/// </summary>
|
||||
[HttpGet("my-registration/{registrationId}")]
|
||||
[DisplayName("获取报名详情")]
|
||||
public async Task<RegistrationDetailDto> GetRegistrationDetail(long registrationId)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -749,15 +775,11 @@ public class EventClientController : IDynamicApiController
|
||||
if (reg == null) throw Oops.Bah("报名记录不存在");
|
||||
|
||||
// 计算 EventStatus
|
||||
EventStatus status = EventStatus.Enrolling;
|
||||
var now = DateTime.Now;
|
||||
var tempEvent = new EventInfo
|
||||
{
|
||||
RegistrationStartTime = reg.RegStart,
|
||||
RegistrationEndTime = reg.RegEnd,
|
||||
MatchStartTime = reg.MatchStart,
|
||||
MatchEndTime = reg.MatchEnd
|
||||
};
|
||||
EventStatus status = EventStatusUpdateService.CalculateEventStatus(tempEvent, 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()
|
||||
@ -805,6 +827,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <param name="registrationId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("status/{registrationId}")]
|
||||
[DisplayName("查询报名状态")]
|
||||
public async Task<RegistrationStatusDto> GetRegistrationStatus(long registrationId)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -826,6 +849,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <param name="registrationId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("cancel/{registrationId}")]
|
||||
[DisplayName("取消报名")]
|
||||
public async Task<bool> CancelRegistration(long registrationId)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -856,6 +880,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// <returns>操作是否成功</returns>
|
||||
[HttpPost("select-payment-method")]
|
||||
[UnitOfWork]
|
||||
[DisplayName("选择支付方式")]
|
||||
public async Task<bool> SelectPaymentMethod([FromBody] SelectPaymentMethodInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -890,6 +915,7 @@ public class EventClientController : IDynamicApiController
|
||||
/// </summary>
|
||||
[HttpPost("sync-payment/{registrationId}")]
|
||||
[UnitOfWork]
|
||||
[DisplayName("同步支付状态")]
|
||||
public async Task<bool> SyncPaymentStatus(long registrationId)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
@ -1138,6 +1164,9 @@ public class EventClientController : IDynamicApiController
|
||||
private EventStatus CalculateEventStatus(EventInfo e)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
return EventStatusUpdateService.CalculateEventStatus(e, 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; // 默认? 或者新增未开始状态
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ public class AddPointsRuleInput
|
||||
/// <summary>
|
||||
/// 参与积分(发放积分个数)
|
||||
/// </summary>
|
||||
public int ParticipationPoints { get; set; }
|
||||
public int? ParticipationPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
|
||||
@ -1,12 +1,47 @@
|
||||
namespace YD_Event.Application.User.Dtos;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace YD_Event.Application.User.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统用户输入
|
||||
/// </summary>
|
||||
public class UpdateSysUserInput : AddSysUserInput
|
||||
public class UpdateSysUserInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "用户Id为必填项")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "姓名为必填项")]
|
||||
[MaxLength(16, ErrorMessage = "姓名限制16个字符内")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "账号为必填项")]
|
||||
[MaxLength(32, ErrorMessage = "账号限制32个字符内")]
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码(编辑时可选,不填则不修改)
|
||||
/// </summary>
|
||||
[MinLength(6, ErrorMessage = "密码长度至少6位")]
|
||||
[MaxLength(32, ErrorMessage = "密码长度最多32位")]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联角色ID集合
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "请选择关联角色")]
|
||||
public List<long> Roles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态(默认启用)
|
||||
/// </summary>
|
||||
public AvailabilityStatus Status { get; set; } = AvailabilityStatus.Enable;
|
||||
}
|
||||
@ -147,7 +147,17 @@ public class SysUserService : BaseService<SysUser>, ITransient
|
||||
if (await _repository.IsAnyAsync(x => x.Account == dto.Account && x.Id != dto.Id))
|
||||
throw new InvalidOperationException($"账号 {dto.Account} 已被使用");
|
||||
|
||||
dto.Adapt(user);
|
||||
// 先更新除密码外的其他字段
|
||||
user.Name = dto.Name;
|
||||
user.Account = dto.Account;
|
||||
user.Status = dto.Status;
|
||||
|
||||
// 只有密码不为空时才更新密码
|
||||
if (!string.IsNullOrWhiteSpace(dto.Password))
|
||||
{
|
||||
string encode = _idGenerator.Encode(user.Id);
|
||||
user.Password = MD5Encryption.Encrypt(encode + dto.Password);
|
||||
}
|
||||
|
||||
// 处理角色关联:先删后加
|
||||
var roles = new List<SysUserRole>();
|
||||
|
||||
@ -431,6 +431,27 @@
|
||||
<param name="id">验证码唯一id</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Auth.AuthService.Register(YD_Event.Application.Auth.Dtos.RegisterInput)">
|
||||
<summary>
|
||||
用户注册
|
||||
</summary>
|
||||
<param name="dto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Auth.AuthService.SmsSignIn(YD_Event.Application.Auth.Dtos.SmsLoginInput)">
|
||||
<summary>
|
||||
短信验证码登录
|
||||
</summary>
|
||||
<param name="dto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Auth.AuthService.ResetPassword(YD_Event.Application.Auth.Dtos.ResetPasswordInput)">
|
||||
<summary>
|
||||
重置密码
|
||||
</summary>
|
||||
<param name="dto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Auth.Dtos.AdminLoginInput">
|
||||
<summary>
|
||||
管理员登录输入参数
|
||||
@ -456,6 +477,81 @@
|
||||
验证码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Auth.Dtos.RegisterInput">
|
||||
<summary>
|
||||
用户注册输入参数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.Phone">
|
||||
<summary>
|
||||
手机号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.Account">
|
||||
<summary>
|
||||
账号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.Password">
|
||||
<summary>
|
||||
密码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.ConfirmPassword">
|
||||
<summary>
|
||||
确认密码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.Code">
|
||||
<summary>
|
||||
短信验证码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.RegisterInput.AgreeTerms">
|
||||
<summary>
|
||||
同意用户协议
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Auth.Dtos.SmsLoginInput">
|
||||
<summary>
|
||||
短信登录输入参数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.SmsLoginInput.Phone">
|
||||
<summary>
|
||||
手机号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.SmsLoginInput.Code">
|
||||
<summary>
|
||||
验证码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Auth.Dtos.ResetPasswordInput">
|
||||
<summary>
|
||||
重置密码输入参数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.ResetPasswordInput.Phone">
|
||||
<summary>
|
||||
手机号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.ResetPasswordInput.Code">
|
||||
<summary>
|
||||
验证码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.ResetPasswordInput.NewPassword">
|
||||
<summary>
|
||||
新密码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Auth.Dtos.ResetPasswordInput.ConfirmNewPassword">
|
||||
<summary>
|
||||
确认新密码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Banner.BannerService">
|
||||
<summary>
|
||||
轮播图服务
|
||||
@ -1495,6 +1591,31 @@
|
||||
主键ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.EventClientQueryInput">
|
||||
<summary>
|
||||
客户端赛事查询输入
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventClientQueryInput.Keyword">
|
||||
<summary>
|
||||
搜索关键字
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventClientQueryInput.Status">
|
||||
<summary>
|
||||
状态筛选:0-全部 1-报名中 2-比赛中 3-已结束
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventClientQueryInput.EventType">
|
||||
<summary>
|
||||
赛事类型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.Client.Dtos.EventClientQueryInput.ChargeMode">
|
||||
<summary>
|
||||
收费模式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.Client.Dtos.EventListDto">
|
||||
<summary>
|
||||
赛事列表项DTO
|
||||
@ -2919,14 +3040,11 @@
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.EventClientController.GetEventList(System.Int32,System.Int32,System.Int32,System.String)">
|
||||
<member name="M:YD_Event.Application.Client.EventClientController.GetEventList(YD_Event.Application.Client.Dtos.EventClientQueryInput)">
|
||||
<summary>
|
||||
获取赛事列表
|
||||
</summary>
|
||||
<param name="page">页码</param>
|
||||
<param name="pageSize">页大小</param>
|
||||
<param name="status">状态筛选:0-全部 1-报名中 2-比赛中 3-已结束</param>
|
||||
<param name="keyword">搜索关键字</param>
|
||||
<param name="input">查询参数</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YD_Event.Application.Client.EventClientController.GetEventDetail(System.Int64)">
|
||||
@ -9868,6 +9986,31 @@
|
||||
用户Id
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.User.Dtos.UpdateSysUserInput.Name">
|
||||
<summary>
|
||||
姓名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.User.Dtos.UpdateSysUserInput.Account">
|
||||
<summary>
|
||||
账号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.User.Dtos.UpdateSysUserInput.Password">
|
||||
<summary>
|
||||
密码(编辑时可选,不填则不修改)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.User.Dtos.UpdateSysUserInput.Roles">
|
||||
<summary>
|
||||
关联角色ID集合
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YD_Event.Application.User.Dtos.UpdateSysUserInput.Status">
|
||||
<summary>
|
||||
状态(默认启用)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YD_Event.Application.User.SysUserService">
|
||||
<summary>
|
||||
系统用户管理
|
||||
|
||||
@ -16,7 +16,7 @@ public class PointsRule : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTim
|
||||
/// <summary>
|
||||
/// 参与积分(发放积分个数)
|
||||
/// </summary>
|
||||
public int ParticipationPoints { get; set; }
|
||||
public int? ParticipationPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user