using YD_Event.Application.Client.Dtos;
namespace YD_Event.Application.Client;
public partial class EventClientController
{
///
/// 获取可查询成绩的赛事。只开放比赛中、已结束两种状态。
///
[HttpGet("scores/events")]
[AllowAnonymous]
[DisplayName("获取成绩赛事")]
public async Task> GetScoreEvents(
[FromServices] ISqlSugarRepository resultRepository,
[FromServices] ISqlSugarRepository 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();
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();
}
///
/// 获取指定赛事成绩的项目、组别筛选项。
///
[HttpGet("scores/filters")]
[AllowAnonymous]
[DisplayName("获取成绩筛选项")]
public async Task GetScoreFilters(
[FromQuery] long eventId,
[FromServices] ISqlSugarRepository resultRepository,
[FromServices] ISqlSugarRepository eventRepository,
[FromServices] ISqlSugarRepository 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()
: 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()
};
}
///
/// 按赛事、项目、组别、姓名或报名人员ID查询成绩与排名。
///
[HttpGet("scores/query")]
[AllowAnonymous]
[DisplayName("查询赛事成绩")]
public async Task QueryScores(
[FromQuery] ScoreQueryInput input,
[FromServices] ISqlSugarRepository resultRepository,
[FromServices] ISqlSugarRepository eventRepository,
[FromServices] ISqlSugarRepository 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")
};
}
///
/// 成绩分项明细。规定赛没有难度分,难度分为 0 时不展示该项。
///
private static List BuildScoreBreakdown(EventResult result)
{
var items = new List();
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');
}
}