Implementiert die Funktion zur Generierung eines Teilnehmer-PDFs in OfficialTournaments.vue. Fügt die Methode addParticipantsSummary in PDFGenerator.js hinzu, um eine Zusammenfassung der Teilnehmerdaten in einem PDF-Dokument darzustellen. Integriert die Logik zur Gruppierung und Formatierung der Teilnehmerinformationen basierend auf ihrem Anmeldestatus und der Teilnahme.
This commit is contained in:
@@ -264,6 +264,77 @@ class PDFGenerator {
|
||||
});
|
||||
}
|
||||
|
||||
addParticipantsSummary(tournamentTitle, tournamentDateText, groups) {
|
||||
// Header
|
||||
const title = tournamentTitle || 'Offizielles Turnier';
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
this.pdf.setFontSize(14);
|
||||
this.pdf.text(title, this.margin, this.cursorY);
|
||||
this.cursorY += 8;
|
||||
if (tournamentDateText) {
|
||||
this.pdf.setFont('helvetica', 'normal');
|
||||
this.pdf.setFontSize(12);
|
||||
this.pdf.text(String(tournamentDateText), this.margin, this.cursorY);
|
||||
this.cursorY += 8;
|
||||
}
|
||||
|
||||
// Tabelle mit Gruppierung
|
||||
const head = [['Mitglied', 'Konkurrenz', 'Startzeit', 'Status', 'Platzierung']];
|
||||
const body = [];
|
||||
const rowStyles = [];
|
||||
|
||||
for (const group of groups) {
|
||||
for (let i = 0; i < group.items.length; i++) {
|
||||
const item = group.items[i];
|
||||
const rowData = [
|
||||
i === 0 ? group.memberName : '', // Name nur in erster Zeile
|
||||
item.competitionName,
|
||||
item.start || '–',
|
||||
item.statusText || '',
|
||||
item.placement || ''
|
||||
];
|
||||
body.push(rowData);
|
||||
rowStyles.push({
|
||||
isFirstRow: i === 0,
|
||||
memberStyle: group.memberStyle,
|
||||
competitionName: item.competitionName,
|
||||
statusStyle: item.statusStyle
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.pdf.setFontSize(11);
|
||||
autoTable(this.pdf, {
|
||||
startY: this.cursorY,
|
||||
margin: { left: this.margin, right: this.margin },
|
||||
head,
|
||||
body,
|
||||
theme: 'grid',
|
||||
styles: { fontSize: 11 },
|
||||
headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left' },
|
||||
didParseCell: (data) => {
|
||||
if (data.section !== 'body') return;
|
||||
const rowStyle = rowStyles[data.row.index];
|
||||
|
||||
// Formatierung für Mitgliedsname (erste Spalte, erste Zeile der Gruppe)
|
||||
if (data.column.index === 0 && rowStyle.isFirstRow) {
|
||||
if (rowStyle.memberStyle === 'bold') data.cell.styles.fontStyle = 'bold';
|
||||
else if (rowStyle.memberStyle === 'italic') data.cell.styles.fontStyle = 'italic';
|
||||
else data.cell.styles.fontStyle = 'normal';
|
||||
}
|
||||
// Formatierung für Konkurrenzname (zweite Spalte)
|
||||
else if (data.column.index === 1) {
|
||||
if (rowStyle.statusStyle === 'bold') data.cell.styles.fontStyle = 'bold';
|
||||
else if (rowStyle.statusStyle === 'italic') data.cell.styles.fontStyle = 'italic';
|
||||
else data.cell.styles.fontStyle = 'normal';
|
||||
}
|
||||
},
|
||||
didDrawPage: (data) => {
|
||||
this.cursorY = data.cursor.y + 10;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addMemberCompetitions(tournamentTitle, memberName, recommendedRows = [], otherRows = [], venues = []) {
|
||||
let y = this.margin;
|
||||
this.pdf.setFont('helvetica', 'bold');
|
||||
|
||||
@@ -154,6 +154,8 @@
|
||||
<option value="registered">Angemeldet</option>
|
||||
<option value="participated">Hat gespielt</option>
|
||||
</select>
|
||||
<div style="flex:1;"></div>
|
||||
<button class="btn-primary" :disabled="!participantsRows.length" @click="generateParticipantsPdf">Teilnehmer-PDF</button>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -448,6 +450,119 @@ export default {
|
||||
if (byFirst !== 0) return byFirst;
|
||||
return this.collator.compare(lnA, lnB);
|
||||
},
|
||||
generateParticipantsPdf() {
|
||||
if (!this.parsed) return;
|
||||
const title = this.parsed?.parsedData?.title || 'Offizielles Turnier';
|
||||
const dateText = this.parsed?.parsedData?.termin || '';
|
||||
// Alle Teilnehmer unabhängig vom Filter
|
||||
const comps = (this.parsed?.parsedData?.competitions) || [];
|
||||
const compById = Object.fromEntries(comps.map(c => [String(c.id), c]));
|
||||
const allRows = [];
|
||||
const seen = new Set();
|
||||
const merged = [];
|
||||
if (Array.isArray(this.parsed?.participation)) {
|
||||
for (const e of this.parsed.participation) {
|
||||
const competitionId = String(e.competitionId);
|
||||
const memberId = String(e.memberId);
|
||||
const key = `${competitionId}-${memberId}`;
|
||||
seen.add(key);
|
||||
merged.push({ competitionId, memberId });
|
||||
}
|
||||
}
|
||||
for (const [key, p] of Object.entries(this.participationMap || {})) {
|
||||
if (seen.has(key)) continue;
|
||||
const [competitionId, memberId] = key.split('-');
|
||||
merged.push({ competitionId: String(competitionId), memberId: String(memberId) });
|
||||
}
|
||||
for (const e of merged) {
|
||||
const competitionId = String(e.competitionId);
|
||||
const memberId = String(e.memberId);
|
||||
const c = compById[competitionId];
|
||||
if (!c) continue;
|
||||
const current = this.getParticipation(competitionId, memberId);
|
||||
const mname = this.memberNameById(memberId);
|
||||
const start = String(c.startTime || c.startzeit || '–');
|
||||
let statusStyle = 'normal';
|
||||
let statusText = '';
|
||||
if (current.participated) {
|
||||
statusStyle = 'normal';
|
||||
statusText = 'gespielt';
|
||||
} else if (current.registered) {
|
||||
statusStyle = 'italic';
|
||||
statusText = 'angemeldet';
|
||||
} else if (current.wants) {
|
||||
statusStyle = 'bold';
|
||||
statusText = 'möchte teilnehmen (Anmeldung fehlt)';
|
||||
}
|
||||
allRows.push({
|
||||
memberName: mname,
|
||||
competitionName: c.ageClassCompetition || c.altersklasseWettbewerb || '',
|
||||
start,
|
||||
placement: current.placement || '',
|
||||
statusStyle,
|
||||
statusText,
|
||||
wants: current.wants,
|
||||
registered: current.registered,
|
||||
participated: current.participated,
|
||||
});
|
||||
}
|
||||
// Nach Mitglied und Konkurrenz sortieren
|
||||
allRows.sort((a, b) => {
|
||||
const m = this.collator.compare(a.memberName, b.memberName);
|
||||
if (m !== 0) return m;
|
||||
return this.collator.compare(a.competitionName, b.competitionName);
|
||||
});
|
||||
|
||||
// Gruppierung nach Mitglied mit korrekter Formatierungslogik
|
||||
const groups = [];
|
||||
const byMember = new Map();
|
||||
for (const row of allRows) {
|
||||
const key = row.memberName;
|
||||
if (!byMember.has(key)) byMember.set(key, []);
|
||||
byMember.get(key).push(row);
|
||||
}
|
||||
|
||||
for (const [memberName, items] of byMember.entries()) {
|
||||
items.sort((a, b) => this.collator.compare(a.competitionName, b.competitionName));
|
||||
|
||||
// Bestimme Formatierung für den Spielernamen basierend auf allen Konkurrenzen
|
||||
let memberStyle = 'normal';
|
||||
let memberStatusText = '';
|
||||
|
||||
const hasPlayed = items.some(item => item.participated);
|
||||
const wantsToPlay = items.some(item => item.wants);
|
||||
const allRegistered = items.every(item => !item.wants || item.registered);
|
||||
const hasUnregistered = items.some(item => item.wants && !item.registered);
|
||||
|
||||
if (hasPlayed) {
|
||||
memberStyle = 'normal';
|
||||
memberStatusText = 'hat gespielt';
|
||||
} else if (wantsToPlay && hasUnregistered) {
|
||||
memberStyle = 'bold';
|
||||
memberStatusText = 'Anmeldung fehlt';
|
||||
} else if (wantsToPlay && allRegistered) {
|
||||
memberStyle = 'italic';
|
||||
memberStatusText = 'angemeldet';
|
||||
} else {
|
||||
// Fallback für Spieler ohne Teilnahmewünsche
|
||||
memberStyle = 'normal';
|
||||
memberStatusText = '';
|
||||
}
|
||||
|
||||
groups.push({
|
||||
memberName,
|
||||
memberId: items[0]?.memberName || memberName,
|
||||
memberStyle,
|
||||
memberStatusText,
|
||||
items,
|
||||
});
|
||||
}
|
||||
groups.sort((a, b) => this.collator.compare(a.memberName, b.memberName));
|
||||
|
||||
const pdf = new PDFGenerator();
|
||||
pdf.addParticipantsSummary(title, dateText, groups);
|
||||
pdf.save('teilnehmer.pdf');
|
||||
},
|
||||
clubParticipationRows() {
|
||||
if (this.clubParticipationRowsData && this.clubParticipationRowsData.length) {
|
||||
return this.clubParticipationRowsData;
|
||||
|
||||
Reference in New Issue
Block a user