157 lines
7.8 KiB
Plaintext
157 lines
7.8 KiB
Plaintext
@model IEnumerable<RoundDto>
|
|
@{
|
|
ViewData["Title"] = "Track Event - Rounds";
|
|
var telId = ViewBag.TournamentEventLevelId as int?;
|
|
var eventName = ViewBag.EventName as string;
|
|
var levelName = ViewBag.LevelName as string;
|
|
var tournamentName = ViewBag.TournamentName as string;
|
|
var regCount = ViewBag.RegistrationCount as int? ?? 0;
|
|
var standings = ViewBag.Standings as IEnumerable<EventRegistrationDto> ?? Enumerable.Empty<EventRegistrationDto>();
|
|
}
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div>
|
|
<h2 class="mb-1">@(string.IsNullOrEmpty(eventName) ? "Track Event Scoring" : $"{eventName} — {levelName}")</h2>
|
|
<p class="text-muted mb-0">
|
|
@if (!string.IsNullOrEmpty(tournamentName)) { <span><i class="bi bi-trophy"></i> @tournamentName</span> }
|
|
<span class="ms-2"><i class="bi bi-people"></i> @regCount registered</span>
|
|
<span class="ms-2"><i class="bi bi-stopwatch"></i> @Model.Count() round(s)</span>
|
|
</p>
|
|
</div>
|
|
@if (Model.Any(r => r.RoundType == RoundType.Final))
|
|
{
|
|
<form asp-action="CalculateFinalStandings" method="post">
|
|
<input type="hidden" name="tournamentEventLevelId" value="@telId" />
|
|
<button type="submit" class="btn btn-warning" title="Rank the final-round times and award placement points">
|
|
<i class="bi bi-trophy"></i> Calculate Final Standings
|
|
</button>
|
|
</form>
|
|
}
|
|
</div>
|
|
|
|
<partial name="_Notification" />
|
|
|
|
<div class="card shadow-sm mb-3">
|
|
<div class="card-header bg-dark text-white d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">Rounds</h5>
|
|
<form asp-action="CreateRound" method="post" class="d-flex gap-2 align-items-center">
|
|
<input type="hidden" name="TournamentEventLevelId" value="@telId" />
|
|
<select name="RoundType" id="roundTypeSelect" class="form-select form-select-sm" style="width:120px">
|
|
<option value="Heat">Heats</option>
|
|
<option value="SemiFinal">Semi-Final</option>
|
|
<option value="Final">Final</option>
|
|
</select>
|
|
<input type="number" name="RoundOrder" value="@(Model.Count() + 1)" class="form-control form-control-sm" style="width:60px" title="Round order" />
|
|
<input type="number" name="AdvanceTopN" id="advanceTopN" value="3" class="form-control form-control-sm advance-field" style="width:60px" placeholder="Top N" title="Advance top N per heat" />
|
|
<input type="number" name="AdvanceFastestLosers" id="advanceFL" value="2" class="form-control form-control-sm advance-field" style="width:60px" placeholder="FL" title="Fastest losers" />
|
|
<span id="finalNote" class="text-light small fst-italic" style="display:none;">no advancement</span>
|
|
<button type="submit" class="btn btn-sm btn-success">Add Round</button>
|
|
</form>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<table class="table table-hover mb-0">
|
|
<thead><tr><th>Round</th><th>Type</th><th>Status</th><th>Heats</th><th>Competitors</th><th>Advances to next round</th><th>Actions</th></tr></thead>
|
|
<tbody>
|
|
@foreach (var r in Model.OrderBy(r => r.RoundOrder))
|
|
{
|
|
var competitors = r.Heats.Sum(h => h.HeatLanes.Count);
|
|
var isFinal = r.RoundType == RoundType.Final;
|
|
<tr>
|
|
<td><strong>Round @r.RoundOrder</strong></td>
|
|
<td><span class="badge bg-info">@r.RoundType</span></td>
|
|
<td><span class="badge @(r.Status == RoundStatus.Completed ? "bg-success" : r.Status == RoundStatus.InProgress ? "bg-primary" : "bg-secondary")">@r.Status</span></td>
|
|
<td>@r.Heats.Count</td>
|
|
<td>@competitors</td>
|
|
<td>
|
|
@if (isFinal)
|
|
{
|
|
<span class="badge bg-warning text-dark">Final — points awarded</span>
|
|
}
|
|
else if ((r.AdvanceTopN ?? 0) > 0 || (r.AdvanceFastestLosers ?? 0) > 0)
|
|
{
|
|
<span title="Top @(r.AdvanceTopN ?? 0) per heat plus @(r.AdvanceFastestLosers ?? 0) fastest losers overall">
|
|
Top @(r.AdvanceTopN ?? 0)/heat + @(r.AdvanceFastestLosers ?? 0) fastest losers
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="text-muted">—</span>
|
|
}
|
|
</td>
|
|
<td>
|
|
<a asp-action="ManageRound" asp-route-roundId="@r.RoundId" class="btn btn-sm btn-primary">Manage</a>
|
|
@if (r.Heats.Count == 0)
|
|
{
|
|
<form asp-action="SeedHeats" method="post" class="d-inline">
|
|
<input type="hidden" name="roundId" value="@r.RoundId" />
|
|
<input type="hidden" name="method" value="Random" />
|
|
<button type="submit" class="btn btn-sm btn-outline-success">Seed Heats</button>
|
|
</form>
|
|
}
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="card-footer text-muted small">
|
|
Athletes run preliminary heats (max 8 per heat); the fastest advance to the Final.
|
|
<strong>Placement points are awarded from the Final round only.</strong>
|
|
</div>
|
|
</div>
|
|
|
|
@if (standings.Any())
|
|
{
|
|
<div class="card shadow-sm mb-3">
|
|
<div class="card-header text-white" style="background-color:#003366;">
|
|
<h5 class="mb-0">Final Standings</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<table class="table table-striped table-hover mb-0">
|
|
<thead class="table-dark">
|
|
<tr><th>Place</th><th>Athlete</th><th>School</th><th>Time (s)</th><th>Points</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var r in standings)
|
|
{
|
|
<tr>
|
|
<td>
|
|
@if (r.Score!.Placement <= 3) { <span class="badge bg-warning text-dark">#@r.Score.Placement</span> }
|
|
else { <span>@r.Score.Placement</span> }
|
|
</td>
|
|
<td>@r.StudentName</td>
|
|
<td>@r.SchoolName</td>
|
|
<td>@r.Score.RawPerformance.ToString("0.00")</td>
|
|
<td><strong>@r.Score.PlacementPoints</strong></td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@section Scripts {
|
|
<script>
|
|
(function () {
|
|
var sel = document.getElementById('roundTypeSelect');
|
|
if (!sel) return;
|
|
var topN = document.getElementById('advanceTopN');
|
|
var fl = document.getElementById('advanceFL');
|
|
var note = document.getElementById('finalNote');
|
|
function sync() {
|
|
var isFinal = sel.value === 'Final';
|
|
// Finals don't advance anyone, so hide the advancement inputs.
|
|
[topN, fl].forEach(function (el) {
|
|
if (!el) return;
|
|
el.style.display = isFinal ? 'none' : '';
|
|
el.disabled = isFinal;
|
|
});
|
|
if (note) note.style.display = isFinal ? '' : 'none';
|
|
}
|
|
sel.addEventListener('change', sync);
|
|
sync();
|
|
})();
|
|
</script>
|
|
}
|