Erweitert den MatchReportApiDialog um umfassende Validierungslogik für die Eingabe von Spielberichten. Implementiert neue Warnungen für unvollständige oder fehlerhafte Match-Ergebnisse sowie für ungültige Start- und Endzeiten. Aktualisiert die Logik zur Aktivierung und Deaktivierung des Absende-Buttons basierend auf den Validierungsbedingungen. Verbessert die Benutzeroberfläche mit neuen CSS-Stilen für Validierungsbenachrichtigungen und optimiert die Benutzererfahrung durch dynamische Rückmeldungen.
This commit is contained in:
@@ -512,14 +512,34 @@
|
||||
<button
|
||||
@click="submitMatchReport"
|
||||
class="btn-primary submit-btn"
|
||||
:disabled="isMatchCompleted"
|
||||
:class="{ 'disabled': isMatchCompleted }"
|
||||
:disabled="isMatchCompleted || !areAllMatchResultsValid() || !areStartAndEndTimesValid()"
|
||||
:class="{ 'disabled': isMatchCompleted || !areAllMatchResultsValid() || !areStartAndEndTimesValid() }"
|
||||
>
|
||||
{{ isMatchCompleted ? '✅ Spielbericht bereits abgesendet' : '📝 Spielbericht absenden' }}
|
||||
{{ getSubmitButtonText() }}
|
||||
</button>
|
||||
|
||||
<!-- Warnung wenn Match abgeschlossen -->
|
||||
<div v-if="isMatchCompleted" class="completion-notice">
|
||||
⚠️ Dieser Spielbericht wurde bereits abgesendet. Keine weiteren Änderungen möglich.
|
||||
</div>
|
||||
|
||||
<!-- Warnung wenn Match-Ergebnisse fehlerhaft sind -->
|
||||
<div v-else-if="!areAllMatchResultsValid()" class="validation-notice">
|
||||
<span v-if="getPlayThrough() && getPlayThrough().toUpperCase().includes('ALLGAMES')">
|
||||
❌ Der Spielbericht kann nicht abgesendet werden. Es müssen alle Spiele abgeschlossen sein.
|
||||
<br><strong>Bitte schließen Sie alle {{ results.filter(match => !match.completed).length }} offenen Spiele ab!</strong>
|
||||
</span>
|
||||
<span v-else>
|
||||
❌ Der Spielbericht kann nicht abgesendet werden. Es gibt noch Fehler in den Match-Ergebnissen.
|
||||
<br><strong>Bitte überprüfen Sie die Ergebniserfassung!</strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Warnung wenn Zeiten fehlerhaft sind -->
|
||||
<div v-else-if="!areStartAndEndTimesValid()" class="validation-notice">
|
||||
❌ Der Spielbericht kann nicht abgesendet werden. Start- oder Endzeit sind nicht festgelegt.
|
||||
<br><strong>Bitte legen Sie beide Zeiten fest!</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -642,10 +662,21 @@ export default {
|
||||
'werner-scheffler-system': [
|
||||
'DA1 – DB1', 'DA2 – DB2', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A3 – B1', 'A1 – B3', 'A2 – B4', 'A4 – B2'
|
||||
],
|
||||
'braunschweiger system': [
|
||||
// Vierer–Vierer (häufigster Pfad)
|
||||
'DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3'
|
||||
],
|
||||
'braunschweiger system': {
|
||||
// Dynamische Auswahl je nach Spielerzahlen
|
||||
matrices: {
|
||||
// 4 vs 4 Spieler
|
||||
'4-4': ['DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3'],
|
||||
// 4 vs 3 Spieler
|
||||
'4-3': ['DA1 – DB1', 'A3 – B3', 'A1 – B2', 'A2 – B1', 'A4 – B2', 'A1 – B1', 'A4 – B3', 'A2 – B2', 'A1 – B3', 'A3 – B1'],
|
||||
// 3 vs 4 Spieler
|
||||
'3-4': ['DA1 – DB1', 'A3 – B3', 'A2 – B1', 'A1 – B2', 'A2 – B4', 'A1 – B1', 'A3 – B4', 'A2 – B2', 'A3 – B1', 'A1 – B3'],
|
||||
// 3 vs 3 Spieler
|
||||
'3-3': ['DA1 – DB1', 'A1 – B2', 'A2 – B1', 'A3 – B2', 'A2 – B3', 'A1 – B1', 'A3 – B3', 'A2 – B2', 'A3 – B1', 'A1 – B3']
|
||||
},
|
||||
// Fallback für unbekannte Kombination
|
||||
default: ['DA1 – DB1', 'DA2 – DB2', 'A1 – B1', 'A2 – B2', 'A3 – B3', 'A4 – B4', 'A1 – B2', 'A2 – B1', 'A3 – B4', 'A4 – B3']
|
||||
},
|
||||
'modifiziertes swaythling-cup-system': [
|
||||
'A1 – B2', 'A2 – B1', 'A3 – B3', 'DA1 – DB1', 'A1 – B1', 'A3 – B2', 'A2 – B3'
|
||||
],
|
||||
@@ -700,8 +731,29 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
},
|
||||
currentPlayModeMatrix() {
|
||||
const key = (this.currentPlayMode || '').toLowerCase();
|
||||
return this.playModeMatrices[key] || [];
|
||||
}
|
||||
const matrixConfig = this.playModeMatrices[key];
|
||||
|
||||
// Spezielle Behandlung für Braunschweiger System
|
||||
if (matrixConfig && typeof matrixConfig === 'object' && matrixConfig.matrices) {
|
||||
const homePlayerCount = this.getSelectedPlayerCount('home');
|
||||
const guestPlayerCount = this.getSelectedPlayerCount('guest');
|
||||
|
||||
// Erstelle Key basierend auf Spielerzahlen (z.B. "3-4", "4-4")
|
||||
const playerCountKey = `${homePlayerCount}-${guestPlayerCount}`;
|
||||
|
||||
console.log(`🎯 Braunschweiger System: ${homePlayerCount} vs ${guestPlayerCount} → Key: ${playerCountKey}`);
|
||||
|
||||
// Verwende spezifische Matrix oder Fallback
|
||||
return matrixConfig.matrices[playerCountKey] || matrixConfig.default || [];
|
||||
}
|
||||
|
||||
// Standard-Verhalten für andere Systeme
|
||||
return matrixConfig || [];
|
||||
},
|
||||
// Prüfe ob das Match bereits abgeschlossen ist
|
||||
isMatchCompleted() {
|
||||
return this.match && this.match.isCompleted === true;
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadData();
|
||||
@@ -845,10 +897,151 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
this.finalGuestPin = this.match.guestPin || '';
|
||||
},
|
||||
|
||||
// Text für den Absenden-Button basierend auf Zustand
|
||||
getSubmitButtonText() {
|
||||
if (this.isMatchCompleted) {
|
||||
return '✅ Spielbericht bereits abgesendet';
|
||||
} else if (!this.areAllMatchResultsValid()) {
|
||||
const playThrough = this.getPlayThrough();
|
||||
if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
|
||||
const unfinishedMatches = this.results.filter(match => !match.completed);
|
||||
return `❌ Spielbericht absenden (${unfinishedMatches.length} Spiel/e noch offen)`;
|
||||
}
|
||||
return '❌ Spielbericht absenden (Ergebnisse fehlerhaft)';
|
||||
} else if (!this.areStartAndEndTimesValid()) {
|
||||
return '❌ Spielbericht absenden (Zeiten fehlerhaft)';
|
||||
} else {
|
||||
return '📝 Spielbericht absenden';
|
||||
}
|
||||
},
|
||||
|
||||
// Prüfe ob Start- und Endzeiten korrekt festgelegt sind
|
||||
areStartAndEndTimesValid() {
|
||||
// Prüfe ob Startzeit festgelegt wurde
|
||||
if (!this.match.startDate) {
|
||||
console.log('❌ Startzeit ist nicht festgelegt');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prüfe ob Endzeit festgelegt wurde
|
||||
if (!this.match.endDate) {
|
||||
console.log('❌ Endzeit ist nicht festgelegt');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prüfe ob Endzeit nach Startzeit liegt
|
||||
const startTime = new Date(this.match.startDate).getTime();
|
||||
const endTime = new Date(this.match.endDate).getTime();
|
||||
|
||||
if (endTime <= startTime) {
|
||||
console.log('⚠️ Endzeit liegt vor/vor Startzeit - korrigiere auf nächsten Tag...');
|
||||
// Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
|
||||
const nextDay = new Date(endTime);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
this.match.endDate = nextDay;
|
||||
console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
|
||||
}
|
||||
|
||||
console.log('✅ Start- und Endzeiten sind korrekt');
|
||||
return true;
|
||||
},
|
||||
|
||||
// Prüfe ob alle Matchergebnisse korrekt sind (für Spielbericht-Absendung)
|
||||
areAllMatchResultsValid() {
|
||||
if (!this.results || this.results.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spezielle Regel für ALLGAMES Spielmodus
|
||||
const playThrough = this.getPlayThrough();
|
||||
if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
|
||||
// Alle Spiele müssen abgeschlossen sein
|
||||
const unfinishedMatches = this.results.filter(match => !match.completed);
|
||||
if (unfinishedMatches.length > 0) {
|
||||
console.log(`❌ ALLGAMES Modus: ${unfinishedMatches.length} Spiel(e) noch nicht abgeschlossen`);
|
||||
return false;
|
||||
}
|
||||
console.log('✅ ALLGAMES Modus: Alle Spiele sind abgeschlossen');
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.results.length; i++) {
|
||||
const match = this.results[i];
|
||||
|
||||
// Prüfe auf Lücken in der Sätze-Reihenfolge
|
||||
const gapIndices = this.hasGapInSets(match);
|
||||
if (gapIndices !== false && Array.isArray(gapIndices) && gapIndices.length > 0) {
|
||||
console.log(`❌ Match ${i + 1}: Lücken gefunden bei Satz ${gapIndices.map(idx => idx + 1).join(', ')}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prüfe jeden Satz auf Validität (nur ausgefüllte Sätze)
|
||||
for (let j = 0; j < match.sets.length; j++) {
|
||||
const set = match.sets[j];
|
||||
if (set && set.trim().length > 0 && set.includes(':')) {
|
||||
// Parse die Satzergebnisse
|
||||
const [homeScoreStr, guestScoreStr] = set.split(':');
|
||||
const homeScore = parseInt(homeScoreStr) || 0;
|
||||
const guestScore = parseInt(guestScoreStr) || 0;
|
||||
|
||||
const validationResult = this.validateSetScore(homeScore, guestScore, set);
|
||||
if (!validationResult.isValid) {
|
||||
console.log(`❌ Match ${i + 1}, Satz ${j + 1}: ${validationResult.error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfe Match-Abschluss-Regeln wenn Match als abgeschlossen markiert ist
|
||||
if (match.completed) {
|
||||
const completionValidation = this.validateMatchCompletion(i);
|
||||
if (!completionValidation.isValid) {
|
||||
console.log(`❌ Match ${i + 1}: ${completionValidation.error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Alle Match-Ergebnisse sind korrekt');
|
||||
return true;
|
||||
},
|
||||
|
||||
async submitMatchReport() {
|
||||
try {
|
||||
console.log('🚀 Starte Spielbericht-Absendung...');
|
||||
|
||||
// Validiere zuerst alle Match-Ergebnisse
|
||||
if (!this.areAllMatchResultsValid()) {
|
||||
const playThrough = this.getPlayThrough();
|
||||
if (playThrough && playThrough.toUpperCase().includes('ALLGAMES')) {
|
||||
const unfinishedMatches = this.results.filter(match => !match.completed);
|
||||
alert(`❌ Der Spielbericht kann nicht abgesendet werden. Es müssen alle Spiele abgeschlossen sein.\n\n` +
|
||||
`📊 Aktueller Status:\n` +
|
||||
`• ${this.results.length} Spiele insgesamt\n` +
|
||||
`• ${this.results.length - unfinishedMatches.length} Spiele abgeschlossen\n` +
|
||||
`• ${unfinishedMatches.length} Spiele noch offen\n\n` +
|
||||
`Bitte schließen Sie alle offenen Spiele ab, bevor Sie den Spielbericht absenden.`);
|
||||
return;
|
||||
} else {
|
||||
alert('❌ Der Spielbericht kann nicht abgesendet werden, da noch Fehler in den Match-Ergebnissen vorhanden sind. Bitte korrigieren Sie:\n\n' +
|
||||
'• Lücken in der Satze-Reihenfolge\n' +
|
||||
'• Ungültige Satzergebnisse\n' +
|
||||
'• Ungenerische Match-Abschlüsse\n\n' +
|
||||
'Überprüfen Sie die Ergebniserfassung.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Alle Match-Ergebnisse sind gültig - fahre fort...');
|
||||
|
||||
// Validiere Start- und Endzeiten
|
||||
if (!this.areStartAndEndTimesValid()) {
|
||||
alert('❌ Der Spielbericht kann nicht abgesendet werden, da Start- oder Endzeit nicht festgelegt wurden.\n\n' +
|
||||
'Bitte legen Sie sowohl Startzeit als auch Endzeit fest.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ Alle Zeiten sind gültig - fahre fort...');
|
||||
|
||||
// Validiere PINs (für Test: Gast-PIN "1234" akzeptieren)
|
||||
if (!this.finalHomePin || this.finalHomePin.trim() === '') {
|
||||
alert('Bitte geben Sie die PIN des Heimvereins ein.');
|
||||
@@ -1163,10 +1356,6 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
console.log('✅ Player-Positionen aktualisiert');
|
||||
},
|
||||
|
||||
// Prüfe ob das Match bereits abgeschlossen ist
|
||||
get isMatchCompleted() {
|
||||
return this.match && this.match.isCompleted === true;
|
||||
},
|
||||
|
||||
// Zähle die ausgewählten Spieler für ein Team
|
||||
getSelectedPlayerCount(team) {
|
||||
@@ -1874,6 +2063,21 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
const now = new Date();
|
||||
const timeString = now.toTimeString().slice(0, 5); // HH:MM format
|
||||
this.match.endDate = this.createDateTimeFromTimeString(timeString);
|
||||
|
||||
// Prüfe ob Endzeit vor Startzeit liegt und korrigiere automatisch
|
||||
if (this.match.startDate && this.match.endDate) {
|
||||
const startTime = new Date(this.match.startDate).getTime();
|
||||
const endTime = new Date(this.match.endDate).getTime();
|
||||
|
||||
if (endTime <= startTime) {
|
||||
console.log('⚠️ Endzeit liegt vor/auf Startzeit - korrigiere auf nächsten Tag...');
|
||||
// Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
|
||||
const nextDay = new Date(endTime);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
this.match.endDate = nextDay;
|
||||
console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setStartTime(timeString) {
|
||||
@@ -1882,6 +2086,21 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
|
||||
setEndTime(timeString) {
|
||||
this.match.endDate = this.createDateTimeFromTimeString(timeString);
|
||||
|
||||
// Prüfe ob Endzeit vor Startzeit liegt und korrigiere automatisch
|
||||
if (this.match.startDate && this.match.endDate) {
|
||||
const startTime = new Date(this.match.startDate).getTime();
|
||||
const endTime = new Date(this.match.endDate).getTime();
|
||||
|
||||
if (endTime <= startTime) {
|
||||
console.log('⚠️ Endzeit liegt vor/auf Startzeit - korrigiere auf nächsten Tag...');
|
||||
// Setze Endzeit auf nächsten Tag um dieselbe Uhrzeit
|
||||
const nextDay = new Date(endTime);
|
||||
nextDay.setDate(nextDay.getDate() + 1);
|
||||
this.match.endDate = nextDay;
|
||||
console.log('✅ Endzeit wurde auf nächsten Tag verschoben:', nextDay.toISOString());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getFormattedTime(dateValue) {
|
||||
@@ -2494,16 +2713,50 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
},
|
||||
|
||||
|
||||
// Hole aktuellen Spielmodus
|
||||
// Hole aktuellen Spielmodus (für Validierungen)
|
||||
getPlayThrough() {
|
||||
// Suche nach playThrough für ALLGAMES-Validierung
|
||||
const meetingPlayThrough = this.meetingDetails && this.meetingDetails.playThrough;
|
||||
const dataPlayThrough = this.meetingData && this.meetingData.playThrough;
|
||||
|
||||
const playThrough = meetingPlayThrough || dataPlayThrough || '';
|
||||
console.log(`🔍 getPlayThrough: meetingPlayThrough=${meetingPlayThrough}, dataPlayThrough=${dataPlayThrough}, result=${playThrough}`);
|
||||
return playThrough;
|
||||
},
|
||||
|
||||
// Hole aktuellen Spielmodus (für matrix/logic)
|
||||
getPlayMode() {
|
||||
return (this.meetingDetails && this.meetingDetails.playMode) ||
|
||||
(this.meetingData && (this.meetingData.playMode || this.meetingData.matchSystem || this.meetingData.system)) ||
|
||||
'';
|
||||
const meetingPlayModeObj = this.meetingDetails && this.meetingDetails.playMode;
|
||||
const dataMode = this.meetingData && (this.meetingData.playMode || this.meetingData.matchSystem || this.meetingData.system);
|
||||
|
||||
// Falls meetingPlayMode ein Objekt ist, extrahiere die richtige Eigenschaft
|
||||
let meetingPlayMode = '';
|
||||
if (meetingPlayModeObj) {
|
||||
if (typeof meetingPlayModeObj === 'string') {
|
||||
meetingPlayMode = meetingPlayModeObj;
|
||||
} else if (meetingPlayModeObj.name) {
|
||||
meetingPlayMode = meetingPlayModeObj.name;
|
||||
} else if (meetingPlayModeObj.playMode) {
|
||||
meetingPlayMode = meetingPlayModeObj.playMode;
|
||||
} else {
|
||||
// Debug: Objekt-Struktur analysieren
|
||||
console.log('🔍 meetingPlayMode Objekt-Struktur:', Object.keys(meetingPlayModeObj));
|
||||
meetingPlayMode = meetingPlayModeObj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
const playMode = meetingPlayMode || dataMode || '';
|
||||
console.log(`🔍 getPlayMode: meetingPlayModeObj=${meetingPlayModeObj}, extracted=${meetingPlayMode}, dataMode=${dataMode}, result=${playMode}`);
|
||||
return playMode;
|
||||
},
|
||||
|
||||
// Bestimme erforderliche Mindestspielerzahl für Spielmodus
|
||||
getRequiredPlayerCount(playMode) {
|
||||
const mode = (playMode || '').toLowerCase();
|
||||
if (!playMode) {
|
||||
console.log('⚠️ getRequiredPlayerCount: playMode ist undefined oder leer');
|
||||
return 3; // Fallback-Wert
|
||||
}
|
||||
const mode = playMode.toLowerCase();
|
||||
|
||||
// 6er System: 4 Spieler erforderlich
|
||||
if (mode.includes('6')) {
|
||||
@@ -3897,6 +4150,22 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.validation-notice {
|
||||
margin-top: 8px;
|
||||
padding: 8px 12px;
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: 4px;
|
||||
color: #721c24;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.validation-notice strong {
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.time-input:disabled,
|
||||
.protest-input:disabled,
|
||||
.pin-input:disabled {
|
||||
|
||||
Reference in New Issue
Block a user