feat(MatchReportApiDialog): implement meeting details polling functionality

- Added methods to start and stop polling for meeting details at regular intervals.
- Introduced logic to build a signature for meeting details to detect changes.
- Enhanced data handling to update meeting information based on the latest fetched details.
- Improved error handling during polling to ensure robustness in data retrieval.
This commit is contained in:
Torsten Schulz (local)
2026-03-25 18:43:52 +01:00
parent c2a31d3b24
commit c7d51efb5d

View File

@@ -752,6 +752,9 @@ export default {
// Aktive Zelle der schwebenden Satz-Tastatur: { matchIndex, setIndex } oder null
editingSetCell: null,
broadcastDraftTimer: null,
meetingDetailsPollInterval: null,
isMeetingDetailsPolling: false,
lastMeetingDetailsSignature: '',
// Abschluss-Felder
protestText: '',
finalHomePin: '',
@@ -912,6 +915,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
await this.loadData();
this.initializeResults();
this.initializeFinalPins();
this.startMeetingDetailsPolling();
this._matchReportSubmittedHandler = (payload) => {
if (!payload?.matchCode || !this.match?.code || String(payload.matchCode) !== String(this.match.code)) {
return;
@@ -928,6 +932,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
if (this._matchReportSubmittedHandler) {
offMatchReportSubmitted(this._matchReportSubmittedHandler);
}
this.stopMeetingDetailsPolling();
if (this.broadcastDraftTimer) {
clearTimeout(this.broadcastDraftTimer);
}
@@ -978,6 +983,118 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
methods: {
startMeetingDetailsPolling() {
this.stopMeetingDetailsPolling();
this.meetingDetailsPollInterval = setInterval(() => {
this.pollLatestMeetingDetails();
}, 15000);
},
stopMeetingDetailsPolling() {
if (this.meetingDetailsPollInterval) {
clearInterval(this.meetingDetailsPollInterval);
this.meetingDetailsPollInterval = null;
}
},
buildMeetingDetailsSignature(details) {
if (!details || typeof details !== 'object') {
return '';
}
const normalizePlayer = (player) => ({
nuLigaPersonId: player?.nuLigaPersonId ?? null,
firstName: player?.firstName ?? player?.firstname ?? '',
lastName: player?.lastName ?? player?.lastname ?? '',
isSelected: Boolean(player?.isSelected),
rank: player?.rank ?? null,
positionSingle: player?.positionSingle ?? null,
positionDouble: player?.positionDouble ?? null,
positions: Array.isArray(player?.positions) ? [...player.positions] : []
});
const normalizeMatch = (match) => ({
name: match?.name ?? '',
homePlayer: match?.homePlayer ?? '',
guestPlayer: match?.guestPlayer ?? '',
matchesA: match?.matchesA ?? null,
matchesB: match?.matchesB ?? null,
set1A: match?.set1A ?? null,
set1B: match?.set1B ?? null,
set2A: match?.set2A ?? null,
set2B: match?.set2B ?? null,
set3A: match?.set3A ?? null,
set3B: match?.set3B ?? null,
set4A: match?.set4A ?? null,
set4B: match?.set4B ?? null,
set5A: match?.set5A ?? null,
set5B: match?.set5B ?? null
});
return JSON.stringify({
isCompleted: details.isCompleted ?? null,
wo: details.wo ?? null,
startDate: details.startDate ?? null,
endDate: details.endDate ?? null,
homePin: details.homePin ?? null,
guestPin: details.guestPin ?? null,
signature: details.signature ?? null,
teamLineupHomePlayers: Array.isArray(details.teamLineupHomePlayers)
? details.teamLineupHomePlayers.map(normalizePlayer)
: [],
teamLineupGuestPlayers: Array.isArray(details.teamLineupGuestPlayers)
? details.teamLineupGuestPlayers.map(normalizePlayer)
: [],
matches: Array.isArray(details.matches) ? details.matches.map(normalizeMatch) : []
});
},
async pollLatestMeetingDetails() {
if (this.loading || this.isMeetingDetailsPolling) {
return;
}
const meetingUuid = this.meetingData?.nuLigaMeetingUuid;
if (!meetingUuid) {
return;
}
this.isMeetingDetailsPolling = true;
try {
const response = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${meetingUuid}`);
if (!response.ok) {
return;
}
const latestMeetingDetails = await response.json();
const latestSignature = this.buildMeetingDetailsSignature(latestMeetingDetails);
if (latestSignature === this.lastMeetingDetailsSignature) {
return;
}
this.lastMeetingDetailsSignature = latestSignature;
this.meetingDetails = latestMeetingDetails;
if (latestMeetingDetails.startDate != null && this.meetingData) {
this.meetingData.startDate = latestMeetingDetails.startDate;
}
if (latestMeetingDetails.endDate != null && this.meetingData) {
this.meetingData.endDate = latestMeetingDetails.endDate;
}
this.initialCompletionState = Boolean(
((typeof latestMeetingDetails?.isCompleted === 'boolean' && latestMeetingDetails.isCompleted) &&
this.hasReleaseSignatureForCompletion(latestMeetingDetails)) ||
((typeof this.meetingData?.isCompleted === 'boolean' && this.meetingData.isCompleted) &&
this.hasReleaseSignatureForCompletion(this.meetingData))
);
this.populateResultsFromMeetingDetails();
this.applyLineupCertificationFromMeetingDetails();
} catch (error) {
console.warn('⚠️ Polling der Meeting-Details fehlgeschlagen:', error);
} finally {
this.isMeetingDetailsPolling = false;
}
},
logBraunschweigerDebugSnapshot(context, payload = this.meetingDetails) {
if (!payload || typeof payload !== 'object') {
console.log(`[Braunschweiger Debug] ${context}: keine Daten`);
@@ -2213,6 +2330,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const detailsResponse = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${this.meetingData.nuLigaMeetingUuid}`);
if (detailsResponse.ok) {
this.meetingDetails = await detailsResponse.json();
this.lastMeetingDetailsSignature = this.buildMeetingDetailsSignature(this.meetingDetails);
console.log('[nuscore] /meetingdetails response:', this.meetingDetails);
this.logBraunschweigerDebugSnapshot('Server /meetingdetails');
}