{{ player.firstname }} {{ player.lastname }}
@@ -849,7 +849,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
if (this.teamNotAppeared !== null) {
return false;
}
- return this.canOpenNextStages;
+ return this.areBothLineupsCertified();
},
canOpenCompletionStage() {
if (this.isMatchCompleted) {
@@ -869,6 +869,12 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
// Spezielle Behandlung für Braunschweiger System
if (matrixConfig && typeof matrixConfig === 'object' && matrixConfig.matrices) {
+ const serverMatrix = this.getBraunschweigerServerMatrix();
+ if (Array.isArray(serverMatrix) && serverMatrix.length > 0) {
+ console.log('🎯 Braunschweiger System: verwende Server-Matrix', serverMatrix);
+ return serverMatrix;
+ }
+
const homePlayerCount = this.getEffectivePlayerCount('home');
const guestPlayerCount = this.getEffectivePlayerCount('guest');
@@ -876,6 +882,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const playerCountKey = `${homePlayerCount}-${guestPlayerCount}`;
console.log(`🎯 Braunschweiger System: ${homePlayerCount} vs ${guestPlayerCount} → Key: ${playerCountKey}`);
+ this.logBraunschweigerDebugSnapshot(`Matrix-Auswahl ${playerCountKey}`);
// Verwende spezifische Matrix oder Fallback
return matrixConfig.matrices[playerCountKey] || matrixConfig.default || [];
@@ -950,7 +957,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
if (newValue === 'home') {
- this.isHomeLineupCertified = false;
+ this.setLineupCertificationState('home', false);
this.homePin = '';
this.finalHomePin = '';
this.activeSection = 'completion';
@@ -958,7 +965,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
if (newValue === 'guest') {
- this.isGuestLineupCertified = false;
+ this.setLineupCertificationState('guest', false);
this.guestPin = '';
this.finalGuestPin = '';
this.activeSection = 'completion';
@@ -971,6 +978,41 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
methods: {
+ logBraunschweigerDebugSnapshot(context, payload = this.meetingDetails) {
+ if (!payload || typeof payload !== 'object') {
+ console.log(`[Braunschweiger Debug] ${context}: keine Daten`);
+ return;
+ }
+
+ const summarizeTeam = (teamKey) => {
+ const players = Array.isArray(payload[teamKey]) ? payload[teamKey] : [];
+ return players.map(player => ({
+ id: player?.nuLigaPersonId ?? null,
+ name: [player?.firstname || player?.firstName || '', player?.lastname || player?.lastName || ''].filter(Boolean).join(' ').trim(),
+ selected: Boolean(player?.isSelected),
+ positionSingle: player?.positionSingle ?? null,
+ positionDouble: player?.positionDouble ?? null,
+ positions: Array.isArray(player?.positions) ? [...player.positions] : []
+ }));
+ };
+
+ const matches = Array.isArray(payload.matches)
+ ? payload.matches.slice(0, 10).map((match, index) => ({
+ index: index + 1,
+ homePlayer: match?.homePlayer ?? '',
+ guestPlayer: match?.guestPlayer ?? '',
+ matchNumber: match?.matchNumber ?? null
+ }))
+ : [];
+
+ console.log(`[Braunschweiger Debug] ${context}`, {
+ playMode: payload.playMode || this.meetingData?.playMode || this.meetingData?.matchSystem || this.meetingData?.system || null,
+ homePlayers: summarizeTeam('teamLineupHomePlayers'),
+ guestPlayers: summarizeTeam('teamLineupGuestPlayers'),
+ matches
+ });
+ },
+
getFriendlySubmitErrorMessage(message) {
const normalized = (message || '').toString();
@@ -1696,7 +1738,9 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const result = await response.json();
if (result?.object) {
- this.meetingDetails = JSON.parse(JSON.stringify(result.object));
+ const hydratedResult = JSON.parse(JSON.stringify(result.object));
+ this.applyCurrentLineupStateToPayload(hydratedResult);
+ this.meetingDetails = hydratedResult;
this.meetingData = {
...(this.meetingData || {}),
...JSON.parse(JSON.stringify(result.object))
@@ -1773,6 +1817,12 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
matchData.guestPin = this.finalGuestPin.trim();
}
+ const signature = this.ensureSignatureContainer(matchData);
+ if (signature) {
+ signature.lineupSignatureHome = this.isHomeLineupCertified ? 'confirmed' : '';
+ signature.lineupSignatureGuest = this.isGuestLineupCertified ? 'confirmed' : '';
+ }
+
// Zwischenstände dürfen nie als bereits freigegeben an nuscore zurückgeschickt werden.
matchData.isCompleted = finalizeReport;
@@ -1786,7 +1836,10 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
matchData.playerCountHome = this.getSelectedPlayerCount('home');
matchData.playerCountGuest = this.getSelectedPlayerCount('guest');
- // 1.1 Player-Positionen aktualisieren (Einzel + Doppel Positionen erfassen)
+ // 1.1 Lokalen Aufstellungszustand in den Payload übernehmen
+ this.applyCurrentLineupStateToPayload(matchData);
+
+ // 1.2 Player-Positionen aktualisieren (Einzel + Doppel Positionen erfassen)
this.updatePlayerPositions(matchData);
// 2. Zeitangaben aktualisieren
@@ -1920,8 +1973,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
// Verwende positionSingle falls verfügbar, sonst rank für Einzel-Position
const singlePos = player.positionSingle || player.rank;
if (singlePos) {
+ player.positionSingle = singlePos;
positions.push(`E${singlePos}`);
}
+ } else {
+ player.positionSingle = null;
}
// Doppel-Position NUR hinzufügen wenn Spieler Doppel-Position hat
@@ -1944,8 +2000,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
// Verwende positionSingle falls verfügbar, sonst rank für Einzel-Position
const singlePos = player.positionSingle || player.rank;
if (singlePos) {
+ player.positionSingle = singlePos;
positions.push(`E${singlePos}`);
}
+ } else {
+ player.positionSingle = null;
}
// Doppel-Position NUR hinzufügen wenn Spieler Doppel-Position hat
@@ -1961,16 +2020,62 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
console.log('✅ Player-Positionen aktualisiert');
},
+ applyCurrentLineupStateToPayload(target) {
+ if (!target || typeof target !== 'object' || !this.meetingDetails) {
+ return;
+ }
+
+ const copyTeamState = (teamKey) => {
+ if (!Array.isArray(this.meetingDetails[teamKey]) || !Array.isArray(target[teamKey])) {
+ return;
+ }
+
+ const localByPersonId = new Map(
+ this.meetingDetails[teamKey]
+ .filter(player => player && player.nuLigaPersonId != null)
+ .map(player => [String(player.nuLigaPersonId), player])
+ );
+
+ target[teamKey] = target[teamKey].map((player) => {
+ if (!player || player.nuLigaPersonId == null) {
+ return player;
+ }
+
+ const localPlayer = localByPersonId.get(String(player.nuLigaPersonId));
+ if (!localPlayer) {
+ return player;
+ }
+
+ return {
+ ...player,
+ isSelected: Boolean(localPlayer.isSelected),
+ positionSingle: localPlayer.isSelected ? (localPlayer.positionSingle || null) : null,
+ positionDouble: localPlayer.isSelected ? (localPlayer.positionDouble || null) : null,
+ positions: Array.isArray(localPlayer.positions) ? [...localPlayer.positions] : []
+ };
+ });
+ };
+
+ copyTeamState('teamLineupHomePlayers');
+ copyTeamState('teamLineupGuestPlayers');
+
+ const signature = this.ensureSignatureContainer(target);
+ if (signature) {
+ signature.lineupSignatureHome = this.isHomeLineupCertified ? 'confirmed' : '';
+ signature.lineupSignatureGuest = this.isGuestLineupCertified ? 'confirmed' : '';
+ }
+ },
+
// Zähle die ausgewählten Spieler für ein Team
getSelectedPlayerCount(team) {
try {
if (team === 'home') {
const homePlayers = this.meetingDetails?.teamLineupHomePlayers || this.teamLineupHomePlayers || [];
- return homePlayers.filter(p => p.isSelected === true).length;
+ return homePlayers.filter(p => p.isSelected === true && p.nuLigaPersonId > 0).length;
} else if (team === 'guest') {
const guestPlayers = this.meetingDetails?.teamLineupGuestPlayers || this.teamLineupGuestPlayers || [];
- return guestPlayers.filter(p => p.isSelected === true).length;
+ return guestPlayers.filter(p => p.isSelected === true && p.nuLigaPersonId > 0).length;
}
return 0;
} catch (error) {
@@ -2006,6 +2111,32 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
+ formatMatchPlayerName(player) {
+ if (!player || typeof player !== 'object') {
+ return '';
+ }
+ return [player.firstname || player.firstName || '', player.lastname || player.lastName || '']
+ .filter(Boolean)
+ .join(' ')
+ .trim();
+ },
+
+ formatMeetingMatchSide(match, side) {
+ if (!match || typeof match !== 'object') {
+ return '';
+ }
+
+ const firstPlayer = side === 'home' ? match.playerA1 : match.playerB1;
+ const secondPlayer = side === 'home' ? match.playerA2 : match.playerB2;
+ const firstName = this.formatMatchPlayerName(firstPlayer);
+ const secondName = this.formatMatchPlayerName(secondPlayer);
+
+ if (firstName && secondName) {
+ return `${firstName} / ${secondName}`;
+ }
+ return firstName || secondName || '';
+ },
+
getMatchCountForPlayMode(playMode) {
// Bestimme Anzahl der Spiele basierend auf Spielsystem
switch (playMode) {
@@ -2083,6 +2214,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
if (detailsResponse.ok) {
this.meetingDetails = await detailsResponse.json();
console.log('[nuscore] /meetingdetails response:', this.meetingDetails);
+ this.logBraunschweigerDebugSnapshot('Server /meetingdetails');
}
} catch (detailsError) {
console.warn('⚠️ Detaillierte Meeting-Daten konnten nicht geladen werden:', detailsError);
@@ -2166,6 +2298,21 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const src = sourceMatches[i] || {};
const dst = this.results[i];
+ const resolvedHomeName = this.formatMeetingMatchSide(src, 'home');
+ const resolvedGuestName = this.formatMeetingMatchSide(src, 'guest');
+ const fallbackHomeName = typeof src.homePlayer === 'string' ? src.homePlayer.trim() : '';
+ const fallbackGuestName = typeof src.guestPlayer === 'string' ? src.guestPlayer.trim() : '';
+
+ if (typeof src.name === 'string' && src.name.trim() !== '') {
+ dst.label = src.name.trim();
+ }
+ if (resolvedHomeName || fallbackHomeName) {
+ dst.homeName = resolvedHomeName || fallbackHomeName;
+ }
+ if (resolvedGuestName || fallbackGuestName) {
+ dst.guestName = resolvedGuestName || fallbackGuestName;
+ }
+
if (!dst.sets || !Array.isArray(dst.sets)) {
this.$set(dst, 'sets', ['', '', '', '', '']);
}
@@ -2233,6 +2380,36 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
+ ensureSignatureContainer(target) {
+ if (!target || typeof target !== 'object') {
+ return null;
+ }
+ if (!target.signature || typeof target.signature !== 'object') {
+ target.signature = {};
+ }
+ return target.signature;
+ },
+
+ setLineupCertificationState(team, certified) {
+ const teamSuffix = team === 'home' ? 'Home' : 'Guest';
+ const signatureField = `lineupSignature${teamSuffix}`;
+ const signatureValue = certified ? 'confirmed' : '';
+
+ if (team === 'home') {
+ this.isHomeLineupCertified = certified;
+ } else {
+ this.isGuestLineupCertified = certified;
+ }
+
+ [this.meetingDetails, this.meetingData].forEach((source) => {
+ const signature = this.ensureSignatureContainer(source);
+ if (!signature) {
+ return;
+ }
+ signature[signatureField] = signatureValue;
+ });
+ },
+
normalizeCertificationValue(value) {
if (typeof value === 'boolean') return value;
if (typeof value === 'number') {
@@ -2351,6 +2528,13 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
});
return {
matches,
+ signature: this.meetingDetails.signature ? { ...this.meetingDetails.signature } : undefined,
+ teamLineupHomePlayers: Array.isArray(this.meetingDetails.teamLineupHomePlayers)
+ ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupHomePlayers))
+ : undefined,
+ teamLineupGuestPlayers: Array.isArray(this.meetingDetails.teamLineupGuestPlayers)
+ ? JSON.parse(JSON.stringify(this.meetingDetails.teamLineupGuestPlayers))
+ : undefined,
homePin: this.meetingDetails.homePin,
guestPin: this.meetingDetails.guestPin,
startDate: this.meetingData?.startDate ?? this.match?.startDate,
@@ -2385,6 +2569,15 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
if (Array.isArray(matchData.matches)) {
this.meetingDetails.matches = matchData.matches;
}
+ if (matchData.signature && typeof matchData.signature === 'object') {
+ this.meetingDetails.signature = { ...(this.meetingDetails.signature || {}), ...matchData.signature };
+ }
+ if (Array.isArray(matchData.teamLineupHomePlayers)) {
+ this.meetingDetails.teamLineupHomePlayers = matchData.teamLineupHomePlayers;
+ }
+ if (Array.isArray(matchData.teamLineupGuestPlayers)) {
+ this.meetingDetails.teamLineupGuestPlayers = matchData.teamLineupGuestPlayers;
+ }
if (matchData.homePin != null) this.meetingDetails.homePin = matchData.homePin;
if (matchData.guestPin != null) this.meetingDetails.guestPin = matchData.guestPin;
if (matchData.startDate != null && this.meetingData) this.meetingData.startDate = matchData.startDate;
@@ -2404,7 +2597,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const pos = parseInt(token.replace(/[^0-9]/g, '')); // 1 oder 2
const key = side === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
const list = (this.meetingDetails && this.meetingDetails[key]) ? this.meetingDetails[key] : [];
- const pair = list.filter(p => p.positionDouble === pos);
+ const pair = list.filter(p => p.positionDouble === pos && p.nuLigaPersonId > 0);
const n = (p) => [p.firstname || p.firstName || '', p.lastname || p.lastName || ''].filter(Boolean).join(' ').trim();
// Wenn ein Doppel-Paar gefunden wurde, verwende es
@@ -2419,7 +2612,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
// Falls kein Doppel gefunden, verwende die entsprechenden Spieler basierend auf der Position
if (pair.length === 0) {
- const selectedPlayers = list.filter(p => p.isSelected);
+ const selectedPlayers = list.filter(p => p.isSelected && p.nuLigaPersonId > 0);
// Versuche verschiedene Sortierungen
@@ -2476,7 +2669,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const list = (this.meetingDetails && this.meetingDetails[key]) ? this.meetingDetails[key] : [];
// Prüfe zuerst, ob überhaupt genügend Spieler für diese Position vorhanden sind
- const selectedPlayers = list.filter(p => p.isSelected);
+ const selectedPlayers = list.filter(p => p.isSelected && p.nuLigaPersonId > 0);
// Für Braunschweiger System: 2er-Mannschaften werden als 3er-Mannschaften gewertet
let effectivePlayerCount = selectedPlayers.length;
@@ -3290,6 +3483,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
this.meetingDetails[teamKey].forEach(player => {
if (player.nuLigaPersonId > 0) {
player.positions = [];
+ player.positionSingle = null;
}
});
@@ -3297,6 +3491,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
sortedByRank.forEach((player, index) => {
const playerIndex = this.meetingDetails[teamKey].findIndex(p => p.nuLigaPersonId === player.nuLigaPersonId);
if (playerIndex !== -1) {
+ this.meetingDetails[teamKey][playerIndex].positionSingle = index + 1;
this.meetingDetails[teamKey][playerIndex].positions = [`E${index + 1}`];
}
});
@@ -3425,10 +3620,10 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
if (isValid) {
// Aufstellung zertifizieren
if (team === 'home') {
- this.isHomeLineupCertified = true;
+ this.setLineupCertificationState('home', true);
this.originalHomePin = pin; // Ursprüngliche PIN speichern
} else {
- this.isGuestLineupCertified = true;
+ this.setLineupCertificationState('guest', true);
this.originalGuestPin = pin; // Ursprüngliche PIN speichern
}
@@ -3707,6 +3902,69 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
+ formatLineupPositionLabel(position, side) {
+ if (typeof position !== 'string') {
+ return '';
+ }
+
+ const trimmedPosition = position.trim().toUpperCase();
+ if (!trimmedPosition) {
+ return '';
+ }
+
+ if (trimmedPosition.startsWith('D')) {
+ return `${side === 'home' ? 'DA' : 'DB'}${trimmedPosition.slice(1)}`;
+ }
+
+ if (trimmedPosition.startsWith('E')) {
+ return `${side === 'home' ? 'A' : 'B'}${trimmedPosition.slice(1)}`;
+ }
+
+ return trimmedPosition;
+ },
+ getBraunschweigerServerMatrix() {
+ const mapFormationsToLabels = (formations) => {
+ if (!Array.isArray(formations) || formations.length === 0) {
+ return null;
+ }
+
+ return formations
+ .map((formation) => {
+ const homeLabel = this.formatLineupPositionLabel(formation?.homeLineupPosition, 'home');
+ const guestLabel = this.formatLineupPositionLabel(formation?.guestLineupPosition, 'guest');
+
+ if (homeLabel && guestLabel) {
+ return `${homeLabel} – ${guestLabel}`;
+ }
+
+ if (typeof formation?.displayString === 'string' && formation.displayString.trim() !== '') {
+ return formation.displayString.trim();
+ }
+
+ return '';
+ })
+ .filter(Boolean);
+ };
+
+ const meetingPlayModeFormations = mapFormationsToLabels(this.meetingDetails?.meetingPlayMode?.matchFormations);
+ if (meetingPlayModeFormations && meetingPlayModeFormations.length > 0) {
+ return meetingPlayModeFormations;
+ }
+
+ const homePlayerCount = this.getEffectivePlayerCount('home');
+ const guestPlayerCount = this.getEffectivePlayerCount('guest');
+ const optionalMode = Array.isArray(this.meetingDetails?.optionalPlayModes)
+ ? this.meetingDetails.optionalPlayModes.find(mode =>
+ Number(mode?.homePlayersCount) === Number(homePlayerCount) &&
+ Number(mode?.guestPlayersCount) === Number(guestPlayerCount) &&
+ Array.isArray(mode?.matchFormations) &&
+ mode.matchFormations.length > 0
+ )
+ : null;
+
+ return mapFormationsToLabels(optionalMode?.matchFormations);
+ },
+
// Hole aktuellen Spielmodus (für Validierungen)
getPlayThrough() {
@@ -3886,10 +4144,10 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
console.log('✅ PIN erfolgreich - entsperre Aufstellung und wechsle Tab');
if (requiresHomePin) {
- this.isHomeLineupCertified = false;
+ this.setLineupCertificationState('home', false);
}
if (requiresGuestPin) {
- this.isGuestLineupCertified = false;
+ this.setLineupCertificationState('guest', false);
}
const targetSection = requiresHomePin ? 'homeLineup' : 'guestLineup';
@@ -3907,8 +4165,23 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
return team === 'home' ? this.isHomeLineupCertified : this.isGuestLineupCertified;
},
+ areBothLineupsCertified() {
+ return this.isHomeLineupCertified && this.isGuestLineupCertified;
+ },
+
// Prüfe ob Aufstellung-Tab geöffnet werden kann
canOpenLineupTab(team) {
+ if ((team === 'home' && this.teamNotAppeared === 'home') ||
+ (team === 'guest' && this.teamNotAppeared === 'guest')) {
+ return false;
+ }
+
+ const isTeamCertified = team === 'home' ? this.isHomeLineupCertified : this.isGuestLineupCertified;
+
+ if (isTeamCertified) {
+ return this.areBothLineupsCertified();
+ }
+
if (team === 'home') {
return !this.isHomeLineupCertified;
} else {
@@ -3927,10 +4200,12 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
return;
}
- if ((section === 'homeLineup' && this.isHomeLineupCertified) ||
- (section === 'guestLineup' && this.isGuestLineupCertified)) {
- this.openPinModal(section);
- return;
+ if (section === 'homeLineup' || section === 'guestLineup') {
+ const team = section === 'homeLineup' ? 'home' : 'guest';
+
+ if (!this.canOpenLineupTab(team)) {
+ return;
+ }
}
this.activeSection = section;
diff --git a/frontend/src/components/schedule/ScheduleLayoutShell.vue b/frontend/src/components/schedule/ScheduleLayoutShell.vue
index 5c488a19..f00ec8c6 100644
--- a/frontend/src/components/schedule/ScheduleLayoutShell.vue
+++ b/frontend/src/components/schedule/ScheduleLayoutShell.vue
@@ -213,7 +213,7 @@ export default {
gap: 1rem;
min-height: 0;
height: 100%;
- overflow: hidden;
+ overflow: visible;
}
.schedule-static-chrome {
@@ -278,13 +278,15 @@ export default {
align-items: stretch;
flex: 1 1 auto;
min-height: 0;
- overflow: hidden;
+ overflow: visible;
}
.schedule-sidebar {
width: 280px;
flex: 0 0 280px;
min-height: 0;
+ display: flex;
+ flex-direction: column;
}
.schedule-sidebar-card {
@@ -300,6 +302,7 @@ export default {
overflow-y: auto;
margin-top: 0.75rem;
padding-right: 0.25rem;
+ max-height: calc(100vh - 300px);
}
.schedule-team-list {
@@ -408,6 +411,7 @@ export default {
min-height: auto;
height: auto;
overflow: visible;
+ max-height: none;
}
}
diff --git a/frontend/src/views/ScheduleView.vue b/frontend/src/views/ScheduleView.vue
index 39e26031..b92fa7ee 100644
--- a/frontend/src/views/ScheduleView.vue
+++ b/frontend/src/views/ScheduleView.vue
@@ -428,7 +428,7 @@ export default {
},
leagueTeamOptions() {
const ownTeamName = this.selectedTeam?.name;
- return Array.from(new Set(this.allLeagueMatches.flatMap(match => [
+ return Array.from(new Set(this.getCombinedLeagueMatches().flatMap(match => [
match.homeTeam?.name,
match.guestTeam?.name
].filter(Boolean))))
@@ -507,6 +507,47 @@ export default {
};
},
methods: {
+ sortMatchesByDateTime(matches) {
+ if (!Array.isArray(matches)) {
+ return [];
+ }
+
+ const toTimestamp = (match) => {
+ if (!match?.date) {
+ return Number.POSITIVE_INFINITY;
+ }
+
+ const dateValue = new Date(match.date);
+ if (isNaN(dateValue.getTime())) {
+ return Number.POSITIVE_INFINITY;
+ }
+
+ const timeString = typeof match.time === 'string' ? match.time : '';
+ const [hours, minutes] = timeString.split(':').map((value) => parseInt(value, 10));
+
+ if (!Number.isNaN(hours)) {
+ dateValue.setHours(hours, Number.isNaN(minutes) ? 0 : minutes, 0, 0);
+ } else {
+ dateValue.setHours(0, 0, 0, 0);
+ }
+
+ return dateValue.getTime();
+ };
+
+ return [...matches].sort((a, b) => {
+ const diff = toTimestamp(a) - toTimestamp(b);
+ if (diff !== 0) {
+ return diff;
+ }
+
+ const homeA = a?.homeTeam?.name || '';
+ const homeB = b?.homeTeam?.name || '';
+ const guestA = a?.guestTeam?.name || '';
+ const guestB = b?.guestTeam?.name || '';
+
+ return `${homeA} ${guestA}`.localeCompare(`${homeB} ${guestB}`);
+ });
+ },
getResultClass(match) {
if (!match.isCompleted) {
return '';
@@ -972,13 +1013,29 @@ export default {
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${leagueId}?scope=all`);
this.allLeagueMatches = response.data;
},
+ getCombinedLeagueMatches() {
+ const combined = [...(this.allLeagueMatches || []), ...(this.ownLeagueMatches || [])];
+ const seenIds = new Set();
+
+ const uniqueMatches = combined.filter((match) => {
+ const key = match?.id ?? `${match?.date || ''}-${match?.time || ''}-${match?.homeTeam?.name || ''}-${match?.guestTeam?.name || ''}`;
+ if (seenIds.has(key)) {
+ return false;
+ }
+ seenIds.add(key);
+ return true;
+ });
+
+ return this.sortMatchesByDateTime(uniqueMatches);
+ },
applyLeagueMatchScope() {
if (!this.selectedTeam) {
return;
}
const ownTeamName = this.selectedTeam.name;
+ const combinedLeagueMatches = this.getCombinedLeagueMatches();
if (this.leagueMatchScope === 'all') {
- this.matches = this.allLeagueMatches;
+ this.matches = combinedLeagueMatches;
return;
}
if (this.leagueMatchScope === 'other') {
@@ -986,7 +1043,7 @@ export default {
this.selectedComparisonTeamName = this.leagueTeamOptions[0];
}
this.matches = this.selectedComparisonTeamName
- ? this.allLeagueMatches.filter(match =>
+ ? combinedLeagueMatches.filter(match =>
match.homeTeam?.name === this.selectedComparisonTeamName ||
match.guestTeam?.name === this.selectedComparisonTeamName
)
@@ -994,8 +1051,8 @@ export default {
return;
}
this.matches = this.ownLeagueMatches.length > 0
- ? this.ownLeagueMatches
- : this.allLeagueMatches.filter(match =>
+ ? this.sortMatchesByDateTime(this.ownLeagueMatches)
+ : combinedLeagueMatches.filter(match =>
match.homeTeam?.name === ownTeamName || match.guestTeam?.name === ownTeamName
);
},
@@ -1016,7 +1073,7 @@ export default {
try {
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
- this.matches = response.data;
+ this.matches = this.sortMatchesByDateTime(response.data);
} catch (error) {
this.showInfo(this.$t('messages.error'), this.$t('schedule.errorLoadingOverallSchedule'), '', 'error');
this.matches = [];
@@ -1034,12 +1091,12 @@ export default {
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
// Filtere nur Erwachsenenligen (keine Jugendligen)
const allMatches = response.data;
- this.matches = allMatches.filter(match => {
+ this.matches = this.sortMatchesByDateTime(allMatches.filter(match => {
const leagueName = match.leagueDetails?.name || '';
// Prüfe, ob es eine Jugendliga ist (J, M, Jugend im Namen)
const isYouth = /[JM]\d|jugend/i.test(leagueName);
return !isYouth;
- });
+ }));
} catch (error) {
this.showInfo(this.$t('messages.error'), this.$t('schedule.errorLoadingAdultSchedule'), '', 'error');
this.matches = [];
@@ -1295,6 +1352,7 @@ export default {
const idx = this.matches.findIndex(m => m.id === payload.matchId);
if (idx !== -1) {
this.matches.splice(idx, 1, payload.match);
+ this.matches = this.sortMatchesByDateTime(this.matches);
return;
}
}
@@ -1314,6 +1372,7 @@ export default {
if (d.startDate) m.startDate = d.startDate;
if (d.endDate) m.endDate = d.endDate;
this.matches.splice(idx, 1, m);
+ this.matches = this.sortMatchesByDateTime(this.matches);
return;
}
}
@@ -2110,6 +2169,10 @@ li {
background: linear-gradient(180deg, rgba(47, 122, 95, 0.08), rgba(47, 122, 95, 0.03));
padding: 14px;
margin-bottom: 12px;
+ position: sticky;
+ top: 12px;
+ z-index: 5;
+ backdrop-filter: blur(6px);
}
.league-match-scope-header {