Refactor logging in cleanup scripts to use report array for improved output management

Updated various cleanup scripts to replace console.log statements with a report array, enhancing the output handling and allowing for better formatting of messages. This change improves the readability of logs and ensures consistent reporting across different cleanup operations, including database connection status, index management, and summary reports.
This commit is contained in:
Torsten Schulz (local)
2025-11-10 13:25:11 +01:00
parent eb37532de2
commit d94238f6df
28 changed files with 225 additions and 474 deletions

View File

@@ -71,7 +71,7 @@ export default {
const isOpen = ref(false);
const handleClose = () => {
console.log('Dialog geschlossen');
// Reagiere auf das Schließen des Dialogs
};
return { isOpen, handleClose };
@@ -163,11 +163,11 @@ export default {
const showConfirm = ref(false);
const handleDelete = () => {
console.log('Gelöscht');
// Lösche den Eintrag
};
const handleCancel = () => {
console.log('Abgebrochen');
// Brich die Aktion ab
};
return { showConfirm, handleDelete, handleCancel };
@@ -307,108 +307,4 @@ toggle();
Promise-basiertes Composable für Bestätigungsdialoge.
```javascript
import { useConfirm } from '@/composables/useDialog.js';
const { isOpen, config, confirm, handleConfirm, handleCancel } = useConfirm();
// Im Template:
<ConfirmDialog
v-model="isOpen"
:title="config.title"
:message="config.message"
:type="config.type"
@confirm="handleConfirm"
@cancel="handleCancel"
/>
// In Methoden:
async function deleteItem() {
const confirmed = await confirm({
title: 'Löschen bestätigen',
message: 'Wirklich löschen?',
type: 'danger'
});
if (confirmed) {
// Löschvorgang durchführen
}
}
```
## Dialog-Größen
| Größe | Breite | Beschreibung |
|-------|--------|--------------|
| `small` | 400px | Kleine Dialoge (z.B. Bestätigungen) |
| `medium` | 600px | Standard-Dialoge |
| `large` | 900px | Große Dialoge mit viel Inhalt |
| `fullscreen` | 90vw x 90vh | Fast Fullscreen |
## Best Practices
### Modale Dialoge verwenden für:
- Wichtige Benutzer-Entscheidungen
- Formulare, die Fokus erfordern
- Warnungen und Fehler
- Prozesse, die nicht unterbrochen werden sollten
### Nicht-modale Dialoge verwenden für:
- Zusätzliche Informationen
- Tools und Paletten
- Mehrere gleichzeitige Arbeitsschritte
- Drag & Drop-Workflows
### Tipps
1. **Minimieren-Funktion**: Nur bei nicht-modalen Dialogen sinnvoll
2. **closeOnOverlay**: Bei wichtigen Formularen auf `false` setzen
3. **z-Index**: Bei mehreren nicht-modalen Dialogen unterschiedliche z-Indices verwenden
4. **Footer-Slot**: Für Aktions-Buttons verwenden
5. **header-actions**: Für kontextspezifische Header-Aktionen
## Styling
Die Dialoge verwenden CSS-Variablen für konsistentes Styling:
- `--primary-color`: Primärfarbe für Header und Buttons
- `--primary-hover`: Hover-Farbe
- `--border-color`: Rahmenfarbe
- `--text-color`: Textfarbe
- `--text-muted`: Gedämpfte Textfarbe
## Migration bestehender Dialoge
### Alt (individueller Dialog):
```vue
<div v-if="showDialog" class="modal-overlay" @click.self="closeDialog">
<div class="modal">
<div class="modal-header">
<h3>Titel</h3>
<button @click="closeDialog">×</button>
</div>
<div class="modal-body">
Inhalt
</div>
</div>
</div>
```
### Neu (BaseDialog):
```vue
<BaseDialog v-model="showDialog" title="Titel">
Inhalt
</BaseDialog>
```
## Beispiele ansehen
Die Datei `DialogExamples.vue` enthält vollständige Beispiele für alle Dialog-Typen.
Route hinzufügen in `router.js`:
```javascript
import DialogExamples from './components/DialogExamples.vue';
{ path: '/dialog-examples', component: DialogExamples }
```
```

View File

@@ -326,19 +326,19 @@ export default {
});
if (result) {
alert('Bestätigt!');
// Hier kann ein nutzerfreundlicher Hinweis (z. B. Toast) implementiert werden
} else {
alert('Abgebrochen!');
// Hier kann ein nutzerfreundlicher Hinweis (z. B. Toast) implementiert werden
}
},
handleWarningConfirm() {
console.log('Warnung bestätigt');
// Hier kann ein nutzerfreundlicher Hinweis (z. B. Toast) implementiert werden
this.warningConfirm.isOpen = false;
},
handleDelete() {
console.log('Eintrag gelöscht');
// Hier kann nach erfolgreicher Aktion ein Hinweis angezeigt werden
this.dangerConfirm.isOpen = false;
},

View File

@@ -99,29 +99,19 @@ export default {
},
insertPinIntoIframe(match) {
console.log('🔍 PIN-Einfügen gestartet für Match:', match);
console.log('📌 Verfügbare PINs:', {
homePin: match.homePin,
guestPin: match.guestPin
});
// Versuche direkten Zugriff auf die MatchReportDialog-Komponente
const matchReportDialogs = document.querySelectorAll('.match-report-dialog');
console.log('🖼️ Gefundene MatchReportDialogs:', matchReportDialogs.length);
if (matchReportDialogs.length > 0) {
// Versuche die insertPinManually Methode aufzurufen
console.log('🎯 Versuche direkten Zugriff auf MatchReportDialog');
// Finde das iframe im aktuellen Dialog
const iframe = matchReportDialogs[matchReportDialogs.length - 1].querySelector('iframe');
if (iframe) {
console.log('✅ Iframe gefunden, versuche PIN-Einfügung');
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (iframeDoc) {
console.log('✅ Direkter DOM-Zugriff möglich');
// Suche nach PIN-Feldern
const pinSelectors = [
@@ -137,26 +127,20 @@ export default {
for (const selector of pinSelectors) {
pinField = iframeDoc.querySelector(selector);
if (pinField) {
console.log(`✅ PIN-Feld gefunden mit Selektor: ${selector}`);
break;
}
}
if (pinField && match.homePin) {
console.log('📝 Füge PIN ein:', match.homePin);
pinField.value = match.homePin;
pinField.dispatchEvent(new Event('input', { bubbles: true }));
pinField.dispatchEvent(new Event('change', { bubbles: true }));
pinField.dispatchEvent(new Event('blur', { bubbles: true }));
console.log('✅ PIN erfolgreich eingefügt');
return;
} else {
console.log('❌ PIN-Feld nicht gefunden');
console.log('🔍 Verfügbare Input-Felder:', iframeDoc.querySelectorAll('input'));
}
}
} catch (error) {
console.log('🚫 Cross-Origin-Zugriff blockiert (erwartet)');
// Cross-Origin-Zugriffe sind erwartbar blockiert
}
}
}
@@ -173,44 +157,28 @@ export default {
source: 'trainingstagebuch'
};
console.log('📤 Sende PostMessage:', message);
const origins = ['https://ttde-apps.liga.nu', 'https://liga.nu', '*'];
origins.forEach(origin => {
try {
iframe.contentWindow.postMessage(message, origin);
console.log(`📤 PostMessage an ${origin} gesendet`);
} catch (e) {
console.log(`❌ PostMessage an ${origin} fehlgeschlagen:`, e.message);
// Ignoriere fehlgeschlagene PostMessage-Versuche
}
});
}
console.log('💡 Alternative: Verwenden Sie den "📋 PIN kopieren" Button');
console.log('📋 PIN zum Kopieren:', match.homePin || match.guestPin);
},
handlePostMessage(event) {
console.log('📨 PostMessage empfangen:', event);
console.log('- Origin:', event.origin);
console.log('- Data:', event.data);
// Nur Nachrichten von nuscore verarbeiten
if (event.origin !== 'https://ttde-apps.liga.nu' && event.origin !== 'https://liga.nu') {
console.log('🚫 Nachricht von unbekannter Origin ignoriert');
return;
}
// Hier können wir auf Antworten von nuscore reagieren
if (event.data && event.data.action) {
console.log('🎯 Action empfangen:', event.data.action);
if (event.data.action === 'pinFilled') {
console.log('✅ PIN wurde erfolgreich eingefügt');
} else if (event.data.action === 'pinError') {
console.log('❌ Fehler beim PIN-Einfügen:', event.data.error);
}
if (!event.data || typeof event.data !== 'object') {
return;
}
// Weitere Aktionen bei Bedarf implementieren
}
},

View File

@@ -63,8 +63,6 @@ export default {
},
onIframeLoad() {
console.log('🔄 Iframe geladen, URL:', this.$refs.reportIframe?.src);
// Warte kurz, damit das iframe vollständig geladen ist
setTimeout(() => {
this.injectContentScript();
@@ -78,15 +76,12 @@ export default {
try {
const iframe = this.$refs.reportIframe;
if (!iframe || !iframe.contentWindow) {
console.log('Iframe noch nicht bereit für Content Script');
return;
}
// Content Script als String definieren
const contentScript = `
(function() {
console.log('Content Script geladen');
// Warte bis die Seite vollständig geladen ist
function waitForElement(selector, callback) {
const element = document.querySelector(selector);
@@ -99,7 +94,6 @@ export default {
// Suche nach dem Input-Feld
waitForElement('#gamecode', function(input) {
console.log('Input-Feld gefunden:', input);
// Code einfügen
input.value = '${this.match.code}';
@@ -109,16 +103,11 @@ export default {
input.dispatchEvent(new Event('change', { bubbles: true }));
input.dispatchEvent(new Event('blur', { bubbles: true }));
console.log('Code eingefügt:', '${this.match.code}');
// Suche nach dem Button und klicke ihn
setTimeout(() => {
const button = document.querySelector('button.btn-primary');
if (button) {
console.log('Button gefunden, klicke ihn');
button.click();
} else {
console.log('Button nicht gefunden');
}
}, 500);
});
@@ -130,10 +119,7 @@ export default {
script.textContent = contentScript;
iframe.contentDocument.head.appendChild(script);
console.log('Content Script injiziert');
} catch (error) {
console.log('Fehler beim Injizieren des Content Scripts:', error);
// Fallback zu PostMessage
this.tryPostMessage();
}
@@ -143,7 +129,6 @@ export default {
try {
const iframe = this.$refs.reportIframe;
if (!iframe || !iframe.contentWindow) {
console.log('Iframe noch nicht bereit');
return;
}
@@ -160,22 +145,19 @@ export default {
gameCodeInput.dispatchEvent(new Event('input', { bubbles: true }));
gameCodeInput.dispatchEvent(new Event('change', { bubbles: true }));
console.log('Spielcode erfolgreich eingefügt:', this.match.code);
// Optional: Automatisch den Button klicken
setTimeout(() => {
this.clickLoadButton(iframeDoc);
}, 500);
} else {
console.log('Input-Feld mit ID "gamecode" nicht gefunden');
// Fallback: PostMessage verwenden
this.tryPostMessage();
}
} else {
console.log('Kein Zugriff auf iframe-Dokument (Cross-Origin)');
// Fallback: PostMessage verwenden
this.tryPostMessage();
}
} catch (error) {
console.log('Fehler beim Zugriff auf iframe:', error);
// Fallback: PostMessage verwenden
this.tryPostMessage();
}
@@ -198,12 +180,8 @@ export default {
if (loadButton) {
loadButton.click();
console.log('Laden-Button erfolgreich geklickt');
} else {
console.log('Laden-Button nicht gefunden');
}
} catch (error) {
console.log('Fehler beim Klicken des Buttons:', error);
}
},
@@ -216,24 +194,18 @@ export default {
action: 'fillGameCode',
code: this.match.code
}, 'https://ttde-apps.liga.nu');
console.log('PostMessage gesendet mit Code:', this.match.code);
}
} catch (error) {
console.log('Fehler beim Senden der PostMessage:', error);
}
},
startUrlMonitoring() {
console.log('🔍 Starte URL-Überwachung für iframe');
console.log('💡 Hinweis: PIN-Einfügung funktioniert am besten nach der Code-Eingabe und Weiterleitung');
console.log('📋 Verwenden Sie den "📌 PIN einfügen" Button nach der Weiterleitung zur Meeting-Seite');
// Einfache Überwachung ohne Cross-Origin-Zugriff
this.urlCheckInterval = setInterval(() => {
const iframe = this.$refs.reportIframe;
if (iframe) {
console.log('🔗 Iframe aktiv, bereit für PIN-Einfügung');
// Iframe aktiv
}
}, 10000); // Alle 10 Sekunden
@@ -241,7 +213,6 @@ export default {
setTimeout(() => {
if (this.urlCheckInterval) {
clearInterval(this.urlCheckInterval);
console.log('⏰ URL-Überwachung beendet (Timeout)');
}
}, 60000);
},
@@ -252,11 +223,8 @@ export default {
},
attemptPinInsertionAfterRedirect() {
console.log('🎯 Versuche PIN-Einfügung (manuell ausgelöst)');
const iframe = this.$refs.reportIframe;
if (!iframe || !this.match.homePin) {
console.log('❌ Iframe oder PIN nicht verfügbar');
return;
}
@@ -277,26 +245,18 @@ export default {
for (const selector of pinSelectors) {
pinField = iframeDoc.querySelector(selector);
if (pinField) {
console.log(`✅ PIN-Feld gefunden mit Selektor: ${selector}`);
break;
}
}
if (pinField) {
console.log('📝 Füge PIN ein:', this.match.homePin);
pinField.value = this.match.homePin;
pinField.dispatchEvent(new Event('input', { bubbles: true }));
pinField.dispatchEvent(new Event('change', { bubbles: true }));
pinField.dispatchEvent(new Event('blur', { bubbles: true }));
console.log('✅ PIN erfolgreich eingefügt');
} else {
console.log('❌ PIN-Feld nicht gefunden');
console.log('🔍 Verfügbare Input-Felder:', iframeDoc.querySelectorAll('input'));
}
} catch (error) {
console.log('🚫 Cross-Origin-Zugriff blockiert (erwartet)');
// Fallback: PostMessage
const message = {
action: 'fillPin',
@@ -305,14 +265,12 @@ export default {
source: 'trainingstagebuch'
};
console.log('📤 Sende PostMessage:', message);
iframe.contentWindow.postMessage(message, '*');
}
},
// Methode, die vom DialogManager aufgerufen werden kann
insertPinManually() {
console.log('🎯 PIN-Einfügung manuell ausgelöst');
this.attemptPinInsertionAfterRedirect();
},
@@ -322,11 +280,9 @@ export default {
return;
}
console.log('PostMessage empfangen:', event.data);
// Hier können wir auf Antworten von nuscore reagieren
if (event.data.action === 'codeFilled') {
console.log('Code wurde erfolgreich eingefügt');
// Code erfolgreich eingefügt
}
}
}

View File

@@ -3,7 +3,7 @@
<!-- <button @click="insertPin" class="header-action-btn" title="PIN automatisch einfügen">
📌 PIN einfügen
</button>-->
<button @click="copyPin" class="header-action-btn copy-button" title="PIN in Zwischenablage kopieren">
<button @click="copyPin($event)" class="header-action-btn copy-button" title="PIN in Zwischenablage kopieren">
📋 PIN kopieren
</button>
</div>
@@ -31,28 +31,21 @@ export default {
});
},
async copyPin() {
async copyPin(event) {
const button = event?.target;
const pin = this.match.homePin || this.match.guestPin;
if (!pin) {
console.warn('⚠️ Keine PIN verfügbar zum Kopieren');
if (button) {
this.showCopyFeedback(button, 'Keine PIN verfügbar', '#dc3545');
}
return;
}
try {
await navigator.clipboard.writeText(pin);
console.log('✅ PIN erfolgreich kopiert:', pin);
// Visuelles Feedback
const button = event.target;
const originalText = button.textContent;
button.textContent = '✅ Kopiert!';
button.style.backgroundColor = '#28a745';
setTimeout(() => {
button.textContent = originalText;
button.style.backgroundColor = '';
}, 2000);
if (button) {
this.showCopyFeedback(button, '✅ Kopiert!', '#28a745');
}
} catch (error) {
console.error('❌ Fehler beim Kopieren der PIN:', error);
@@ -64,8 +57,22 @@ export default {
document.execCommand('copy');
document.body.removeChild(textArea);
console.log('✅ PIN über Fallback kopiert:', pin);
if (button) {
this.showCopyFeedback(button, '✅ Kopiert!', '#28a745');
}
}
},
showCopyFeedback(button, text, backgroundColor) {
const originalText = button.textContent;
const originalColor = button.style.backgroundColor;
button.textContent = text;
button.style.backgroundColor = backgroundColor;
setTimeout(() => {
button.textContent = originalText;
button.style.backgroundColor = originalColor;
}, 2000);
}
}
};

View File

@@ -35,7 +35,6 @@ const checkPermission = (el, binding, vnode) => {
resource = binding.arg;
action = Object.keys(binding.modifiers)[0] || 'read';
} else {
console.warn('v-can directive requires resource and action');
el.style.display = 'none';
return;
}

View File

@@ -876,7 +876,6 @@ export default {
// Gesamtanzahl der Einträge
return participantCount + activityCount + trainingPlanCount;
} catch (error) {
console.warn(`Fehler beim Laden der Einträge für Datum ${dateId}:`, error);
return 0;
}
},

View File

@@ -469,9 +469,6 @@ export default {
const response = await apiClient.get(`/training-stats/${this.currentClub}`);
const trainingStats = response.data.members || [];
console.log('[loadTrainingParticipations] Training Stats geladen:', trainingStats.length, 'Mitglieder');
console.log('[loadTrainingParticipations] Response data:', JSON.stringify(response.data, null, 2));
// Erstelle eine Map für schnellen Zugriff: memberId -> participationTotal
// Speichere sowohl String- als auch Number-Keys, um Typ-Probleme zu vermeiden
const participationMap = new Map();
@@ -483,15 +480,10 @@ export default {
participationMap.set(idAsString, participationTotal);
participationMap.set(idAsNumber, participationTotal);
console.log(`[loadTrainingParticipations] Map gesetzt: ID "${idAsString}" (String) und ${idAsNumber} (Number) -> ${participationTotal}`);
});
console.log('[loadTrainingParticipations] Participation Map Keys:', Array.from(participationMap.keys()));
// Setze Trainingsteilnahmen für alle Testmitglieder
const testMembers = this.members.filter(m => m.testMembership);
console.log('[loadTrainingParticipations] Testmitglieder gefunden:', testMembers.length);
console.log('[loadTrainingParticipations] Testmitglieder IDs:', testMembers.map(m => ({ id: m.id, type: typeof m.id, name: `${m.firstName} ${m.lastName}` })));
testMembers.forEach(member => {
// Versuche sowohl String- als auch Number-ID
@@ -509,13 +501,10 @@ export default {
count = participationMap.get(idAsNumber);
}
console.log(`[loadTrainingParticipations] Mitglied ${member.id} (type: ${typeof member.id}) (${member.firstName} ${member.lastName}): count=${count}, map has String: ${participationMap.has(idAsString)}, map has Number: ${participationMap.has(idAsNumber)}`);
// Setze den Wert, wenn gefunden, sonst 0
const finalCount = count !== undefined ? count : 0;
// In Vue 3 ist $set nicht mehr nötig, direkte Zuweisung funktioniert
member.trainingParticipations = finalCount;
console.log(`[loadTrainingParticipations] Trainingsteilnahmen gesetzt: ${finalCount}`);
});
} catch (error) {
console.error('Fehler beim Laden der Trainingsteilnahmen:', error);

View File

@@ -233,16 +233,12 @@ export default {
const openPermissionsDialog = async (member) => {
selectedMember.value = member;
console.log('Opening dialog for member:', member.user?.email);
console.log('Member permissions from DB:', member.permissions);
// Load fresh data for this specific member to ensure we have the latest permissions
try {
const membersResponse = await apiClient.get(`/permissions/${currentClub.value}/members?t=${Date.now()}`);
const freshMember = membersResponse.data.find(m => m.userId === member.userId);
if (freshMember) {
selectedMember.value = freshMember;
console.log('Fresh member data:', freshMember.permissions);
}
} catch (err) {
console.error('Error loading fresh member data:', err);
@@ -260,7 +256,6 @@ export default {
}
}
console.log('Initialized customPermissions:', customPermissions.value);
};
const closePermissionsDialog = () => {
@@ -286,15 +281,11 @@ export default {
}
}
console.log('Saving permissions:', permissionsToSave);
const response = await apiClient.put(
`/permissions/${currentClub.value}/user/${selectedMember.value.userId}/permissions`,
{ permissions: permissionsToSave }
);
console.log('Save response:', response.data);
// Update local member data immediately
const memberIndex = members.value.findIndex(m => m.userId === selectedMember.value.userId);
if (memberIndex !== -1) {

View File

@@ -369,23 +369,19 @@ export default {
},
async openPlayerSelectionDialog(match) {
console.log('Opening player selection for match:', match);
this.playerSelectionDialog.match = match;
this.playerSelectionDialog.isOpen = true;
this.playerSelectionDialog.loading = true;
try {
// Fetch members for the current club
console.log('Fetching members for club:', this.currentClub);
const response = await apiClient.get(`/clubmembers/get/${this.currentClub}/true`);
console.log('Members response:', response.data);
const allMembers = response.data;
// Filter members by age class if league has age class info
// For now, show all active members
const activeMembers = allMembers.filter(m => m.active);
console.log('Active members count:', activeMembers.length);
this.playerSelectionDialog.members = activeMembers.map(m => ({
...m,
@@ -393,8 +389,6 @@ export default {
isPlanned: match.playersPlanned?.includes(m.id) || false,
hasPlayed: match.playersPlayed?.includes(m.id) || false
}));
console.log('Player selection members:', this.playerSelectionDialog.members.length);
} catch (error) {
console.error('Error loading members:', error);

View File

@@ -622,7 +622,7 @@ export default {
const response = await apiClient.get(`/team-documents/club-team/${team.id}`);
allDocuments.push(...response.data);
} catch (error) {
console.warn(`Fehler beim Laden der Dokumente für Team ${team.id}:`, error);
continue;
}
}
teamDocuments.value = allDocuments;

View File

@@ -209,8 +209,6 @@ export default {
if (!bestQuarter || maxTrainings === 0) return 0;
console.log('🔍 Bestes Quartal:', bestQuarter.name, 'mit', maxTrainings, 'Trainings');
const totalParticipants = this.getTotalParticipantsInPeriod(bestQuarter.year, bestQuarter.startMonth, bestQuarter.year, bestQuarter.endMonth);
return totalParticipants / maxTrainings;
},