YD_Event.Admin/YD_Event.Application/Client/EventClientController.Scores.cs
马梓彭 81b40a27d8 成绩查询按赛事状态开放
已结束赛事的修正通知仍需显示
2026-09-22 18:03:14 +08:00

194 lines
8.3 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<EventInfo> eventRepository)
{
var events = await eventRepository.AsQueryable()
.Where(x => 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');
}
}