diff --git a/frontend/src/lib/stores/times.svelte.ts b/frontend/src/lib/stores/times.svelte.ts index dd340ae..6c445c4 100644 --- a/frontend/src/lib/stores/times.svelte.ts +++ b/frontend/src/lib/stores/times.svelte.ts @@ -228,8 +228,18 @@ export class TimeStore { this.records = next } - async applyCorrection(timeId: string, seconds: number) { - return await api.collection('times').update(timeId, { correction: seconds }) + /** + * Zeitkorrektur setzen, mit optionalem Grund. + * + * Der Grund steht im vorhandenen Feld `comment`. Eine Strafe ohne Grund + * ist nach dem Event nicht mehr zu verteidigen — Pflicht ist er trotzdem + * nicht: An der Strecke zaehlt, dass die Zahl stimmt. + */ + async applyCorrection(timeId: string, seconds: number, comment?: string) { + return await api.collection('times').update(timeId, { + correction: seconds, + comment: comment?.trim() ?? '', + }) } async updateStatus(timeId: string, status: TimeStatus) { diff --git a/frontend/src/routes/dashboard/events/[id]/stages/[stageId]/+page.svelte b/frontend/src/routes/dashboard/events/[id]/stages/[stageId]/+page.svelte index 0c2a57a..f6e03e6 100644 --- a/frontend/src/routes/dashboard/events/[id]/stages/[stageId]/+page.svelte +++ b/frontend/src/routes/dashboard/events/[id]/stages/[stageId]/+page.svelte @@ -56,8 +56,6 @@ const running = $derived(valid && stage ? times.runningByStage(stage.id, clock.now) : []) const leaderboard = $derived(valid && stage ? times.getLeaderboard(stage.id) : []) const unranked = $derived(valid && stage ? times.unrankedByStage(stage.id) : []) - /** Alle gewerteten Zeiten dieser Stage — Ziel einer Strafe für alle. */ - const stageTimes = $derived(leaderboard) /** * Laufende und gewertete Zeiten in einer Liste: Wer gerade unterwegs ist, @@ -97,38 +95,31 @@ // --- Strafzeiten ------------------------------------------------------ // // Die Korrektur steckt als Sekunden an der Zeit (times.correction) und - // wird auf die Dauer gerechnet. Zwei Wege dorthin: an einer Zeit einzeln, - // das ist der Normalfall, und über alle Zeiten dieser Stage auf einmal — - // etwa wenn eine Schikane für alle nicht zählte. + // wird auf die Dauer gerechnet; der Grund daneben im Feld `comment`. + // Immer an einer einzelnen Zeit — eine Strafe trifft einen Fahrer, und + // was fuer alle gleich gilt, ist keine Strafe, sondern eine andere Stage. let penaltyDialog = $state(false) let penaltyTime = $state(null) let penaltySeconds = $state(0) + let penaltyReason = $state('') let penaltyBusy = $state(false) let penaltyError = $state(null) - function openPenalty(timeId: string | null, current = 0) { + function openPenalty(timeId: string, current = 0, reason = '') { penaltyTime = timeId penaltySeconds = current + penaltyReason = reason penaltyError = null penaltyDialog = true } async function savePenalty() { - if (penaltyBusy) return + if (penaltyBusy || !penaltyTime) return penaltyBusy = true penaltyError = null try { - if (penaltyTime) { - await times.applyCorrection(penaltyTime, penaltySeconds) - } else { - // Auf die ganze Stage: Die Korrektur wird gesetzt, nicht - // addiert. Zweimal denselben Dialog abzuschicken darf keine - // doppelte Strafe ergeben. - for (const t of stageTimes) { - await times.applyCorrection(t.id, penaltySeconds) - } - } + await times.applyCorrection(penaltyTime, penaltySeconds, penaltyReason) penaltyDialog = false } catch (e: any) { penaltyError = e.message ?? 'Die Korrektur konnte nicht gespeichert werden.' @@ -146,7 +137,7 @@ function exportCsv() { if (leaderboard.length === 0) return - const rows = [['Platz', 'Nummer', 'Name', 'Zeit', 'Korrektur (s)']] + const rows = [['Platz', 'Nummer', 'Name', 'Zeit', 'Korrektur (s)', 'Grund']] leaderboard.forEach((t, i) => { const r = rider(t.rider) rows.push([ @@ -155,6 +146,7 @@ r ? riderName(r) : '', t.formattedTime ?? '', String(t.correction ?? 0), + t.comment ?? '', ]) }) @@ -253,12 +245,6 @@ Zeiten ({leaderboard.length} gewertet{running.length ? `, ${running.length} laufend` : ''}) - {#if leaderboard.length > 0} - - {/if} @@ -379,10 +365,12 @@ class="tabular-nums font-normal {t.correction ? '' : 'text-muted-foreground'}" - tooltip="Zeitkorrektur" + tooltip={t.comment + ? `Zeitkorrektur: ${t.comment}` + : 'Zeitkorrektur'} onclick={(e) => { e.stopPropagation() - openPenalty(t.id, t.correction ?? 0) + openPenalty(t.id, t.correction ?? 0, t.comment ?? '') }} > {t.correction @@ -446,18 +434,10 @@ - - {penaltyTime ? 'Zeitkorrektur' : 'Strafzeit für alle'} - + Zeitkorrektur - {#if penaltyTime} - Wird auf die gemessene Zeit gerechnet. Eine Strafe ist positiv, eine - Gutschrift negativ. - {:else} - Gilt für alle {stageTimes.length} gewerteten Zeiten dieser Stage. Der - Wert wird gesetzt, nicht addiert — zweimal abschicken ergibt keine - doppelte Strafe. - {/if} + Wird auf die gemessene Zeit gerechnet. Eine Strafe ist positiv, eine + Gutschrift negativ. @@ -470,6 +450,19 @@

+
+ + +

+ Optional, aber nach dem Event ist eine Strafe ohne Grund schwer zu + verteidigen. +

+
+ {#if penaltyError}

{penaltyError}

{/if}