diff --git a/frontend/src/components/MatchReportApiDialog.vue b/frontend/src/components/MatchReportApiDialog.vue index c8e47261..92f79768 100755 --- a/frontend/src/components/MatchReportApiDialog.vue +++ b/frontend/src/components/MatchReportApiDialog.vue @@ -1088,12 +1088,6 @@ 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'); @@ -1103,8 +1097,22 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr 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 || []; + // Die Matrix muss sich immer nach der aktuell gewählten + // Aufstellung richten. NuScore liefert hier gelegentlich noch + // die 4:4-Formation, obwohl eine Mannschaft nur zu zweit + // antritt. Zwei Spieler werden dabei regelkonform als + // 3er-Konstellation behandelt: 4:2 -> 4:3, 2:4 -> 3:4, + // 3:2/2:3/2:2 -> 3:3. Die dadurch fehlenden Einzel werden + // anschließend automatisch als Nichtantreten gewertet. + const localMatrix = matrixConfig.matrices[playerCountKey]; + if (Array.isArray(localMatrix) && localMatrix.length > 0) { + return localMatrix; + } + + // Nur für bislang unbekannte Konstellationen auf die + // Serverformation ausweichen. + const serverMatrix = this.getBraunschweigerServerMatrix(); + return serverMatrix || matrixConfig.default || []; } // Standard-Verhalten für andere Systeme @@ -2426,6 +2434,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr // (etwa 5:3) umstellen. matchData.playerCountHome = this.getSinglePlayerCount('home'); matchData.playerCountGuest = this.getSinglePlayerCount('guest'); + + // Die Begegnungsreihenfolge gehört zum Aufstellungsstand. + // Insbesondere bei 4:2 darf kein veralteter 4:4-Entwurf mit + // einem zweiten Doppel an NuScore zurückgehen. + this.applyBraunschweigerMatchFormations(matchData); // 1.1 Lokalen Aufstellungszustand in den Payload übernehmen this.applyCurrentLineupStateToPayload(matchData); @@ -3572,9 +3585,9 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr this.isDraftSyncing = false; this.lastDraftSyncError = ''; - // Den offiziellen Stand nur als Quelle für Teams, Aufstellung und - // Spielsystem laden. Ergebnisse, Abschluss und Signaturen dürfen - // im Testmodus nie übernommen werden. + // Den offiziellen Stand nur als Quelle für Teams, Spielerliste + // und Spielsystem laden. Der Testmodus startet anschließend mit + // einer vollständig leeren lokalen Eingabe. await this.loadData(); this.resetTestModeState(); }, @@ -3593,11 +3606,31 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr data.signature = {}; }); + // Spieler bleiben als auswählbare Liste erhalten; ihre + // Aufstellung (Einzel und Doppel) beginnt im Testmodus dagegen + // immer leer. Damit lässt sich ein Spiel wirklich von vorne + // durchspielen, ohne Daten an NuScore zu verändern. + ['teamLineupHomePlayers', 'teamLineupGuestPlayers'].forEach((teamKey) => { + (this.meetingDetails[teamKey] || []).forEach((player) => { + player.isSelected = false; + player.positionSingle = null; + player.positionDouble = null; + player.positions = []; + }); + }); + // Die vom Server gespeicherten Ergebnisse komplett verwerfen. Die // leeren Zeilen werden anschließend aus der Spielmatrix erzeugt. this.meetingDetails.matches = []; this.results = []; this.teamNotAppeared = null; + this.homePin = ''; + this.guestPin = ''; + this.finalHomePin = ''; + this.finalGuestPin = ''; + this.protestText = ''; + this.match.startDate = null; + this.match.endDate = null; this.isHomeLineupCertified = false; this.isGuestLineupCertified = false; this.isGreetingCompleted = false; @@ -5027,6 +5060,38 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr return trimmedPosition; }, + applyBraunschweigerMatchFormations(target) { + if (!target || !String(this.getPlayMode() || '').toLowerCase().includes('braunschweiger')) { + return; + } + + const formations = (this.currentPlayModeMatrix || []).map((label, index) => { + const [homeToken = '', guestToken = ''] = String(label).split('–').map(token => token.trim()); + const toNuScorePosition = (token) => token + .replace(/^DA/i, 'D') + .replace(/^DB/i, 'D') + .replace(/^A/i, 'E') + .replace(/^B/i, 'E'); + const homeLineupPosition = toNuScorePosition(homeToken); + const guestLineupPosition = toNuScorePosition(guestToken); + + return { + matchNr: index + 1, + displayString: `${homeLineupPosition}-${guestLineupPosition}`, + homeLineupPosition, + guestLineupPosition + }; + }); + + if (formations.length === 0) { + return; + } + + target.meetingPlayMode = { + ...(target.meetingPlayMode && typeof target.meetingPlayMode === 'object' ? target.meetingPlayMode : {}), + matchFormations: formations + }; + }, getBraunschweigerServerMatrix() { const mapFormationsToLabels = (formations) => { if (!Array.isArray(formations) || formations.length === 0) { diff --git a/frontend/src/views/ScheduleView.vue b/frontend/src/views/ScheduleView.vue index 4ae0c1d5..a6e153bd 100755 --- a/frontend/src/views/ScheduleView.vue +++ b/frontend/src/views/ScheduleView.vue @@ -397,7 +397,7 @@