feat(myTischtennis): implement asynchronous team data fetching and job status tracking

- Added a new endpoint to start an asynchronous job for fetching team data, allowing for non-blocking operations.
- Implemented job status tracking to retrieve the status of ongoing fetch jobs, enhancing user experience with real-time updates.
- Updated the frontend to initiate async fetch requests and poll for job completion, improving data retrieval efficiency and user feedback.
This commit is contained in:
Torsten Schulz (local)
2026-03-02 13:32:57 +01:00
parent e26bc22e19
commit 3df8f6fd81
3 changed files with 172 additions and 16 deletions

View File

@@ -1176,20 +1176,50 @@ export default {
myTischtennisSuccess.value = '';
try {
const response = await apiClient.post('/mytischtennis/fetch-team-data', {
const startResponse = await apiClient.post('/mytischtennis/fetch-team-data/async', {
clubTeamId: teamToEdit.value.id
}, { timeout: 30000 });
if (response.data && response.data.success) {
const successMessage = getSafeMessage(response.data.message, 'Teamdaten erfolgreich abgerufen.');
});
const jobId = startResponse?.data?.jobId;
if (!jobId) {
throw new Error('Async-Job konnte nicht gestartet werden.');
}
const maxPollAttempts = 120; // ~4 Minuten bei 2s Intervall
let completedResponse = null;
for (let attempt = 0; attempt < maxPollAttempts; attempt++) {
await new Promise((resolve) => setTimeout(resolve, 2000));
const pollResponse = await apiClient.get(`/mytischtennis/fetch-team-data/jobs/${jobId}`, {
timeout: 15000
});
const job = pollResponse?.data?.job;
if (!job) continue;
if (job.status === 'completed') {
completedResponse = job.result;
break;
}
if (job.status === 'failed') {
const failedMsg = getSafeMessage(job.error, 'Daten konnten nicht abgerufen werden.');
throw new Error(failedMsg);
}
}
if (!completedResponse) {
throw new Error('Zeitüberschreitung beim Abruf (Async-Job läuft zu lange).');
}
if (completedResponse && completedResponse.success) {
const successMessage = getSafeMessage(completedResponse.message, 'Teamdaten erfolgreich abgerufen.');
myTischtennisSuccess.value = successMessage;
const teamName = getSafeMessage(response.data.data?.teamName, teamToEdit.value?.name || 'Unbekanntes Team');
const fetchedCount = getSafeMessage(String(response.data.data?.fetchedCount ?? ''), '0');
const teamName = getSafeMessage(completedResponse.data?.teamName, teamToEdit.value?.name || 'Unbekanntes Team');
const fetchedCount = getSafeMessage(String(completedResponse.data?.fetchedCount ?? ''), '0');
let detailsMessage = `Team: ${teamName}\nAbgerufene Datensätze: ${fetchedCount}`;
if (response.data.data?.tableUpdate) {
const tableUpdate = getSafeMessage(response.data.data.tableUpdate);
if (completedResponse.data?.tableUpdate) {
const tableUpdate = getSafeMessage(completedResponse.data.tableUpdate);
if (tableUpdate) {
detailsMessage += `\n\nTabellenaktualisierung:\n${tableUpdate}`;
}
@@ -1201,23 +1231,25 @@ export default {
detailsMessage,
'success'
);
} else if (response.data && response.data.success === false) {
const errorTitle = response.data.needsMyTischtennisReauth ? 'Login bei myTischtennis erforderlich' : 'Fehler';
const errorMessage = getSafeMessage(response.data.error, 'Daten konnten nicht abgerufen werden.');
const details = response.data.debug ? getSafeMessage(JSON.stringify(response.data.debug, null, 2)) : '';
} else if (completedResponse && completedResponse.success === false) {
const errorTitle = completedResponse.needsMyTischtennisReauth ? 'Login bei myTischtennis erforderlich' : 'Fehler';
const errorMessage = getSafeMessage(completedResponse.error, 'Daten konnten nicht abgerufen werden.');
const details = completedResponse.debug ? getSafeMessage(JSON.stringify(completedResponse.debug, null, 2)) : '';
await showInfo(
errorTitle,
errorMessage,
details,
response.data.needsMyTischtennisReauth ? 'warning' : 'error'
completedResponse.needsMyTischtennisReauth ? 'warning' : 'error'
);
myTischtennisError.value = errorMessage;
}
} catch (error) {
console.error('Fehler beim Abrufen der Team-Daten:', error);
const isTimeout = error?.code === 'ECONNABORTED';
const isTimeout = error?.code === 'ECONNABORTED' || /Zeitüberschreitung/i.test(String(error?.message || ''));
const errData = error?.response?.data || {};
const errorMsg = isTimeout ? 'Zeitüberschreitung beim Abruf (Timeout).' : getSafeMessage(errData.message || errData.error, 'Daten konnten nicht abgerufen werden.');
const errorMsg = isTimeout
? 'Zeitüberschreitung beim Abruf (Timeout).'
: getSafeMessage(error?.message || errData.message || errData.error, 'Daten konnten nicht abgerufen werden.');
const details = errData.debug ? getSafeMessage(JSON.stringify(errData.debug, null, 2)) : '';
myTischtennisError.value = errorMsg;
await showInfo('Fehler', errorMsg, details, isTimeout ? 'warning' : 'error');