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:
@@ -113,6 +113,16 @@ class Event extends Model
|
||||
return $this->hasMany(EventTimekeeper::class);
|
||||
}
|
||||
|
||||
public function carpools(): HasMany
|
||||
{
|
||||
return $this->hasMany(EventCarpool::class);
|
||||
}
|
||||
|
||||
public function playerStats(): HasMany
|
||||
{
|
||||
return $this->hasMany(EventPlayerStat::class);
|
||||
}
|
||||
|
||||
public function comments(): HasMany
|
||||
{
|
||||
return $this->hasMany(Comment::class);
|
||||
|
||||
36
app/Models/EventCarpool.php
Normal file
36
app/Models/EventCarpool.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class EventCarpool extends Model
|
||||
{
|
||||
protected $fillable = ['event_id', 'seats', 'note'];
|
||||
|
||||
protected $casts = [
|
||||
'seats' => 'integer',
|
||||
];
|
||||
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
}
|
||||
|
||||
public function driver(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function passengers(): HasMany
|
||||
{
|
||||
return $this->hasMany(EventCarpoolPassenger::class, 'carpool_id');
|
||||
}
|
||||
|
||||
public function remainingSeats(): int
|
||||
{
|
||||
return $this->seats - $this->passengers->count();
|
||||
}
|
||||
}
|
||||
35
app/Models/EventCarpoolPassenger.php
Normal file
35
app/Models/EventCarpoolPassenger.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class EventCarpoolPassenger extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['carpool_id', 'player_id'];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
$model->created_at = $model->freshTimestamp();
|
||||
});
|
||||
}
|
||||
|
||||
public function carpool(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(EventCarpool::class, 'carpool_id');
|
||||
}
|
||||
|
||||
public function player(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Player::class);
|
||||
}
|
||||
|
||||
public function addedByUser(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'added_by');
|
||||
}
|
||||
}
|
||||
78
app/Models/EventPlayerStat.php
Normal file
78
app/Models/EventPlayerStat.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\PlayerPosition;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class EventPlayerStat extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'event_id',
|
||||
'player_id',
|
||||
'is_goalkeeper',
|
||||
'position',
|
||||
'goalkeeper_saves',
|
||||
'goalkeeper_shots',
|
||||
'goals',
|
||||
'shots',
|
||||
'note',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_goalkeeper' => 'boolean',
|
||||
'position' => PlayerPosition::class,
|
||||
'goalkeeper_saves' => 'integer',
|
||||
'goalkeeper_shots' => 'integer',
|
||||
'goals' => 'integer',
|
||||
'shots' => 'integer',
|
||||
];
|
||||
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
}
|
||||
|
||||
public function player(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Player::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fangquote in Prozent (nur für Torwart).
|
||||
*/
|
||||
public function saveRate(): ?float
|
||||
{
|
||||
if (! $this->is_goalkeeper || ! $this->goalkeeper_shots || $this->goalkeeper_shots === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return round(($this->goalkeeper_saves / $this->goalkeeper_shots) * 100, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trefferquote in Prozent.
|
||||
*/
|
||||
public function hitRate(): ?float
|
||||
{
|
||||
if (! $this->shots || $this->shots === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return round(($this->goals / $this->shots) * 100, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob der Eintrag leer ist (keine relevanten Daten).
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return ! $this->is_goalkeeper
|
||||
&& ! $this->goalkeeper_saves
|
||||
&& ! $this->goalkeeper_shots
|
||||
&& ! $this->goals
|
||||
&& ! $this->shots
|
||||
&& ! $this->note;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\PlayerPosition;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@@ -17,6 +18,7 @@ class Player extends Model
|
||||
'last_name',
|
||||
'birth_year',
|
||||
'jersey_number',
|
||||
'position',
|
||||
'is_active',
|
||||
'photo_permission',
|
||||
'notes',
|
||||
@@ -28,6 +30,7 @@ class Player extends Model
|
||||
return [
|
||||
'is_active' => 'boolean',
|
||||
'photo_permission' => 'boolean',
|
||||
'position' => PlayerPosition::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user