YD_Event.Admin/YD_Event.Application/Client/EventClientController.Scores.cs

203 lines
8.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YD_Event.Application.Client.Dtos;
namespace YD_Event.Application.Client;
public partial class EventClientController
{
/// <summary>
/// 获取可查询成绩的赛事。只开放比赛中、已结束两种状态。
/// </summary>
[HttpGet("scores/events")]
[AllowAnonymous]
[DisplayName("获取成绩赛事")]
public async Task<List<ScoreEventDto>> GetScoreEvents(
[FromServices] ISqlSugarRepository<EventResult> resultRepository,
[FromServices] ISqlSugarRepository<EventInfo> eventRepository)
{
var eventIds = await resultRepository.AsQueryable()
.Where(x => x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
.Select(x => x.EventId)
.Distinct()
.ToListAsync();
if (eventIds.Count == 0) return new List<ScoreEventDto>();
var events = await eventRepository.AsQueryable()
.Where(x => eventIds.Contains(x.Id) && x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
// 原型要求成绩查询只显示进行中、已结束状态的赛事。
.Where(x => x.EventStatus == EventStatus.Ongoing || x.EventStatus == EventStatus.Ended)
.OrderByDescending(x => x.MatchStartTime)
.ToListAsync();
return events.Select(x => new ScoreEventDto
{
Id = x.Id,
Name = x.EventName,
EventStatus = (int)x.EventStatus,
EventStatusText = x.EventStatus.Description()
}).ToList();
}
/// <summary>
/// 获取指定赛事成绩的项目、组别筛选项。
/// </summary>
[HttpGet("scores/filters")]
[AllowAnonymous]
[DisplayName("获取成绩筛选项")]
public async Task<ScoreFilterOptionsDto> GetScoreFilters(
[FromQuery] long eventId,
[FromServices] ISqlSugarRepository<EventResult> resultRepository,
[FromServices] ISqlSugarRepository<EventInfo> eventRepository,
[FromServices] ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository)
{
var evt = await eventRepository.GetFirstAsync(x =>
x.Id == eventId && x.Status == AvailabilityStatus.Enable && !x.DeleteMark);
if (evt == null) throw Oops.Bah("赛事不存在");
var results = await resultRepository.AsQueryable()
.Where(x => x.EventId == eventId && x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
.ToListAsync();
var projectIds = results.Select(x => x.ProjectId).Distinct().ToList();
var projects = projectIds.Count == 0
? new List<YD_Event.Core.Entities.Project>()
: await projectRepository.AsQueryable().Where(x => projectIds.Contains(x.Id)).ToListAsync();
var projectMap = projects.ToDictionary(x => x.Id, x => x.Name);
var projectFilters = results
.GroupBy(x => x.ProjectId)
.Select(group => new ScoreProjectFilterDto
{
ProjectId = group.Key,
ProjectName = projectMap.GetValueOrDefault(group.Key)
?? group.Select(x => x.ProjectTypeName).FirstOrDefault(x => !string.IsNullOrWhiteSpace(x))
?? string.Empty,
GroupNames = group.Select(x => x.GroupName)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct().OrderBy(x => x).ToList()
})
.OrderBy(x => x.ProjectName)
.ToList();
return new ScoreFilterOptionsDto
{
EventId = evt.Id,
EventName = evt.EventName,
Projects = projectFilters,
GroupNames = projectFilters.SelectMany(x => x.GroupNames).Distinct().OrderBy(x => x).ToList()
};
}
/// <summary>
/// 按赛事、项目、组别、姓名或报名人员ID查询成绩与排名。
/// </summary>
[HttpGet("scores/query")]
[AllowAnonymous]
[DisplayName("查询赛事成绩")]
public async Task<ScoreQueryOutput> QueryScores(
[FromQuery] ScoreQueryInput input,
[FromServices] ISqlSugarRepository<EventResult> resultRepository,
[FromServices] ISqlSugarRepository<EventInfo> eventRepository,
[FromServices] ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository)
{
var query = resultRepository.AsQueryable()
.Where(x => x.Status == AvailabilityStatus.Enable && !x.DeleteMark)
.WhereIF(input.EventId.HasValue, x => x.EventId == input.EventId!.Value)
.WhereIF(input.ProjectId.HasValue, x => x.ProjectId == input.ProjectId!.Value)
.WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), x => x.GroupName == input.GroupName!.Trim());
if (!string.IsNullOrWhiteSpace(input.Keyword))
{
var keyword = input.Keyword.Trim();
if (long.TryParse(keyword, out var personId))
{
query = query.Where(x => x.ParticipantName.Contains(keyword) || x.RegistrationPersonId == personId);
}
else
{
query = query.Where(x => x.ParticipantName.Contains(keyword) || x.GroupName.Contains(keyword));
}
}
// 名次升序展示;未排名(Rank 为 0)的成绩排在最后。
var results = await query.OrderBy(x => x.Rank == 0 ? 1 : 0).OrderBy(x => x.Rank)
.OrderByDescending(x => x.CreatedTime).ToListAsync();
if (results.Count == 0) return new ScoreQueryOutput();
var eventIds = results.Select(x => x.EventId).Distinct().ToList();
var projectIds = results.Select(x => x.ProjectId).Distinct().ToList();
var events = await eventRepository.AsQueryable().Where(x => eventIds.Contains(x.Id)).ToListAsync();
var projects = await projectRepository.AsQueryable().Where(x => projectIds.Contains(x.Id)).ToListAsync();
var eventMap = events.ToDictionary(x => x.Id, x => x.EventName);
var projectMap = projects.ToDictionary(x => x.Id, x => x.Name);
var rows = results.Select(x => new ClientScoreDto
{
Id = x.Id,
EventId = x.EventId,
EventName = eventMap.GetValueOrDefault(x.EventId, string.Empty),
AthleteName = x.ParticipantName,
AthleteNo = FormatBibNo(x.RegistrationPersonId),
ProjectId = x.ProjectId,
Category = projectMap.GetValueOrDefault(x.ProjectId, x.ProjectTypeName ?? string.Empty),
GroupName = x.GroupName,
Rank = x.Rank,
TotalScore = x.Score,
DifficultyScore = x.DifficultyScore,
PerformanceScore = x.PerformanceScore,
RequiredScore = x.RequiredScore,
DeductionScore = x.DeductionScore,
IsDisqualified = x.IsDisqualified,
Status = ResolveResultStatusText(x),
JudgeScores = BuildScoreBreakdown(x)
}).ToList();
var updatedTime = results.Max(x => x.UpdatedTime ?? x.CreatedTime);
return new ScoreQueryOutput
{
Rows = rows,
Total = rows.Count,
DataUpdatedTime = updatedTime,
DataUpdatedText = updatedTime.ToString("yyyy-MM-dd HH:mm:ss")
};
}
/// <summary>
/// 成绩分项明细。规定赛没有难度分,难度分为 0 时不展示该项。
/// </summary>
private static List<JudgeScoreDto> BuildScoreBreakdown(EventResult result)
{
var items = new List<JudgeScoreDto>();
if (result.DifficultyScore != 0)
items.Add(new JudgeScoreDto { Label = "难度分", Score = FormatScore(result.DifficultyScore) });
items.Add(new JudgeScoreDto { Label = "表现分", Score = FormatScore(result.PerformanceScore) });
items.Add(new JudgeScoreDto { Label = "规定分", Score = FormatScore(result.RequiredScore) });
items.Add(new JudgeScoreDto { Label = "扣分", Score = FormatScore(result.DeductionScore) });
items.Add(new JudgeScoreDto { Label = "最终成绩", Score = result.Score });
return items;
}
private static string ResolveResultStatusText(EventResult result)
{
if (result.IsDisqualified) return "取消比赛资格";
return result.ResultStatus switch
{
0 => "计算中",
10 => "待复核",
30 => "已投屏",
40 => "已更正",
90 => "成绩已作废",
_ => "成绩有效"
};
}
private static string FormatScore(decimal value) =>
Math.Round(value, 2, MidpointRounding.AwayFromZero).ToString("0.##");
private static string FormatBibNo(long personId)
{
var value = personId.ToString();
return value.Length > 6 ? value[^6..] : value.PadLeft(6, '0');
}
}