Spielerpositionen, Statistiken, Fahrgemeinschaften, Spielfeld-Visualisierung
- PlayerPosition Enum (7 Handball-Positionen) mit Label/ShortLabel - Spielerstatistik pro Spiel (Tore, Würfe, TW-Paraden, Bemerkung) - Position-Dropdown in Spieler-Editor und Event-Stats-Formular - Statistik-Seite: TW zuerst, Trennlinie, Feldspieler, Position-Badges - Spielfeld-SVG mit Ampel-Performance (grün/gelb/rot) - Anklickbare Spieler im Spielfeld öffnen Detail-Modal - Fahrgemeinschaften (Anbieten, Zuordnen, Zurückziehen) - Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr) - .gitignore für Laravel hinzugefügt - Demo-Daten mit Positionen und Statistiken Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -357,6 +357,106 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Spielerstatistik (nur Spieltypen mit zugesagten Spielern) --}}
|
||||
@if ($event->type->isGameType())
|
||||
@php
|
||||
$confirmedPlayers = $event->participants
|
||||
->where('status', \App\Enums\ParticipantStatus::Yes)
|
||||
->whereNotNull('player_id')
|
||||
->sortBy(fn($p) => $p->player->last_name ?? '');
|
||||
@endphp
|
||||
@if ($confirmedPlayers->isNotEmpty())
|
||||
<div class="bg-white rounded-lg shadow p-6 max-w-4xl mt-6">
|
||||
<h2 class="text-lg font-semibold mb-1">{{ __('events.stats') }}</h2>
|
||||
<p class="text-xs text-gray-500 mb-4">{{ __('events.stats_confirmed_only') }}</p>
|
||||
|
||||
<form method="POST" action="{{ route('admin.events.update-stats', $event) }}">
|
||||
@csrf
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="text-left px-2 py-2 font-medium text-gray-600">{{ __('admin.nav_players') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-28">{{ __('events.stats_position') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-10" title="{{ __('events.stats_goalkeeper_long') }}">{{ __('events.stats_goalkeeper') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-20">{{ __('events.stats_shots_on_goal') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-20">{{ __('events.stats_saves') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-20">{{ __('events.stats_shots') }}</th>
|
||||
<th class="text-center px-2 py-2 font-medium text-gray-600 w-20">{{ __('events.stats_goals') }}</th>
|
||||
<th class="text-left px-2 py-2 font-medium text-gray-600">{{ __('events.stats_note') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
@foreach ($confirmedPlayers as $participant)
|
||||
@php
|
||||
$pid = $participant->player_id;
|
||||
$stat = $playerStatsMap[$pid] ?? null;
|
||||
@endphp
|
||||
<tr x-data="{ isGk: {{ $stat && $stat->is_goalkeeper ? 'true' : 'false' }} }">
|
||||
<td class="px-2 py-2 font-medium text-gray-900 whitespace-nowrap">
|
||||
{{ $participant->player->full_name }}
|
||||
</td>
|
||||
<td class="px-2 py-2">
|
||||
<select name="stats[{{ $pid }}][position]"
|
||||
class="w-full px-1 py-1 border border-gray-300 rounded text-sm"
|
||||
@change="isGk = ($event.target.value === 'torwart')">
|
||||
<option value="">–</option>
|
||||
@foreach (\App\Enums\PlayerPosition::cases() as $pos)
|
||||
<option value="{{ $pos->value }}"
|
||||
{{ ($stat?->position?->value ?? $participant->player->position?->value) === $pos->value ? 'selected' : '' }}>
|
||||
{{ $pos->shortLabel() }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</td>
|
||||
<td class="px-2 py-2 text-center">
|
||||
<input type="checkbox" name="stats[{{ $pid }}][is_goalkeeper]" value="1"
|
||||
x-model="isGk"
|
||||
class="rounded border-gray-300 text-blue-600">
|
||||
</td>
|
||||
<td class="px-2 py-2 text-center" x-show="isGk" x-cloak>
|
||||
<input type="number" name="stats[{{ $pid }}][goalkeeper_shots]" min="0" max="999"
|
||||
value="{{ $stat?->goalkeeper_shots }}"
|
||||
class="w-16 px-1 py-1 border border-gray-300 rounded text-center text-sm">
|
||||
</td>
|
||||
<td class="px-2 py-2 text-center" x-show="!isGk"><span class="text-gray-300">–</span></td>
|
||||
<td class="px-2 py-2 text-center" x-show="isGk" x-cloak>
|
||||
<input type="number" name="stats[{{ $pid }}][goalkeeper_saves]" min="0" max="999"
|
||||
value="{{ $stat?->goalkeeper_saves }}"
|
||||
class="w-16 px-1 py-1 border border-gray-300 rounded text-center text-sm">
|
||||
</td>
|
||||
<td class="px-2 py-2 text-center" x-show="!isGk"><span class="text-gray-300">–</span></td>
|
||||
<td class="px-2 py-2 text-center">
|
||||
<input type="number" name="stats[{{ $pid }}][shots]" min="0" max="999"
|
||||
value="{{ $stat?->shots }}"
|
||||
class="w-16 px-1 py-1 border border-gray-300 rounded text-center text-sm">
|
||||
</td>
|
||||
<td class="px-2 py-2 text-center">
|
||||
<input type="number" name="stats[{{ $pid }}][goals]" min="0" max="999"
|
||||
value="{{ $stat?->goals }}"
|
||||
class="w-16 px-1 py-1 border border-gray-300 rounded text-center text-sm">
|
||||
</td>
|
||||
<td class="px-2 py-2">
|
||||
<input type="text" name="stats[{{ $pid }}][note]" maxlength="500"
|
||||
value="{{ $stat?->note }}"
|
||||
placeholder="{{ __('events.stats_note') }}..."
|
||||
class="w-full px-2 py-1 border border-gray-300 rounded text-sm">
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 text-sm font-medium">
|
||||
{{ __('events.stats_save') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
{{-- Quill JS --}}
|
||||
<script src="https://cdn.jsdelivr.net/npm/quill@1.3.7/dist/quill.min.js" integrity="sha384-QUJ+ckWz1M+a7w0UfG1sEn4pPrbQwSxGm/1TIPyioqXBrwuT9l4f9gdHWLDLbVWI" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user