using EasyCaching.Core;
using YD_Event.Application.Auth;
using YD_Event.Application.Referee.Dtos;
using YD_Event.Core.Entities;
using YD_Event.Core.Enum;
namespace YD_Event.Application.Referee;
/// 裁判库管理。
[ApiDescriptionSettings("打分系统")]
public class RefereeService : BaseService, ITransient
{
private readonly ISqlSugarRepository _repository;
private readonly ISqlSugarRepository _userRepository;
private readonly IEasyCachingProvider _cache;
private readonly IIdGenerator _idGenerator;
private readonly AuthManager _authManager;
public RefereeService(ISqlSugarRepository repository,
ISqlSugarRepository userRepository, IEasyCachingProvider cache,
IIdGenerator idGenerator, AuthManager authManager) : base(repository)
{
_repository = repository;
_userRepository = userRepository;
_cache = cache;
_idGenerator = idGenerator;
_authManager = authManager;
}
[DisplayName("裁判分页查询")]
[HttpGet("page")]
public async Task> Page([FromQuery] RefereeQueryInput input)
{
var query = _repository.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), x => x.Name.Contains(input.Name!))
.WhereIF(!string.IsNullOrWhiteSpace(input.Mobile), x => x.Mobile.Contains(input.Mobile!))
.WhereIF(!string.IsNullOrWhiteSpace(input.RegionCode), x => x.ProvinceCode == input.RegionCode || x.CityCode == input.RegionCode || x.DistrictCode == input.RegionCode)
.WhereIF(input.Level.HasValue, x => x.Level == input.Level)
.WhereIF(input.Role.HasValue, x => (x.Roles & input.Role!.Value) == input.Role.Value)
.WhereIF(input.AuditStatus.HasValue, x => x.AuditStatus == input.AuditStatus)
.WhereIF(input.StartTime.HasValue, x => x.CreatedTime >= input.StartTime)
.WhereIF(input.EndTime.HasValue, x => x.CreatedTime < input.EndTime!.Value.Date.AddDays(1))
.OrderByDescending(x => x.CreatedTime);
var page = await query.ToPagedListAsync(input);
return new PageResult
{
PageNo = page.PageNo, PageSize = page.PageSize, Total = page.Total,
Rows = page.Rows.Select(ToOutput).ToList()
};
}
[DisplayName("新增裁判")]
[HttpPost("add")]
public async Task Add([FromBody] SaveRefereeInput input)
{
await EnsureMobileAvailable(input.Mobile, null);
await VerifyCode(input.Mobile, input.VerificationCode);
var appUser = await FindAppUserAsync(input.Mobile);
var entity = input.Adapt();
entity.Id = _idGenerator.NextId();
entity.AppUserId = appUser?.Id;
// 后台管理员直接维护的裁判档案无需再次审批。
var now = DateTime.Now;
entity.AuditStatus = AuditStatus.Pass;
entity.AuditUserId = _authManager.UserId;
entity.AuditTime = now;
entity.Status = AvailabilityStatus.Enable;
entity.CreatedUserId = _authManager.UserId;
entity.CreatedTime = now;
await _repository.InsertAsync(entity);
await _cache.RemoveAsync($"sms:code:{input.Mobile}");
}
[DisplayName("修改裁判")]
[HttpPut("update")]
public async Task Update([FromBody] UpdateRefereeInput input)
{
var entity = await _repository.GetByIdAsync(input.Id);
if (entity == null || entity.DeleteMark) throw Oops.Bah("裁判不存在");
await EnsureMobileAvailable(input.Mobile, input.Id);
if (!string.Equals(entity.Mobile, input.Mobile, StringComparison.Ordinal))
{
await VerifyCode(input.Mobile, input.VerificationCode);
await _cache.RemoveAsync($"sms:code:{input.Mobile}");
}
var appUser = await FindAppUserAsync(input.Mobile);
input.Adapt(entity);
entity.AppUserId = appUser?.Id;
entity.UpdatedUserId = _authManager.UserId;
entity.UpdatedTime = DateTime.Now;
await _repository.UpdateAsync(entity);
}
[DisplayName("审核裁判"), HttpPost("audit")]
public async Task Audit([FromBody] AuditRefereeInput input)
{
if (input.AuditStatus != AuditStatus.Pass && input.AuditStatus != AuditStatus.Reject)
throw Oops.Bah("审核状态不正确");
var entity = await _repository.GetByIdAsync(input.Id);
if (entity == null || entity.DeleteMark) throw Oops.Bah("裁判不存在");
var now = DateTime.Now;
entity.AuditStatus = input.AuditStatus;
entity.AuditRemark = input.Remark;
entity.AuditUserId = _authManager.UserId;
entity.AuditTime = now;
entity.UpdatedUserId = _authManager.UserId;
entity.UpdatedTime = now;
await _repository.UpdateAsync(entity);
}
private async Task EnsureMobileAvailable(string mobile, long? exceptId)
{
// 不要把 Nullable.HasValue 分支写进 SqlSugar 表达式;空值时会生成 “<>” 附近的非法 SQL。
var refereeQuery = _repository.AsQueryable().Where(x => x.Mobile == mobile);
if (exceptId.HasValue)
refereeQuery = refereeQuery.Where(x => x.Id != exceptId.Value);
if (await refereeQuery.AnyAsync())
throw Oops.Bah("该手机号已存在于裁判库");
}
///
/// 手机号已注册小程序账号时自动建立关联,未注册时允许裁判档案独立存在。
///
private Task FindAppUserAsync(string mobile)
{
return _userRepository.AsQueryable().Where(x => x.Mobile == mobile).FirstAsync();
}
///
/// 批量回填已存在裁判的AppUserId。按手机号匹配小程序用户,建立关联。
///
[DisplayName("批量回填AppUserId")]
[HttpPost("backfill-appuser")]
public async Task