feat: enhance table generation in PDF with optional cell pinning for teams
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 51s

This commit is contained in:
Torsten Schulz (local)
2026-07-17 14:28:12 +02:00
parent f83e3986b7
commit 51b620f496
2 changed files with 51 additions and 11 deletions

View File

@@ -384,7 +384,7 @@ class PDFGenerator {
}
}
addTable(tableId, highlightName = '', excludeColumns = []) {
addTable(tableId, highlightName = '', excludeColumns = [], getCellPin = null) {
this.pdf.setFontSize(11);
// Wenn Spalten ausgeschlossen werden sollen, parse die Tabelle manuell
@@ -398,10 +398,15 @@ class PDFGenerator {
.map(h => h.text);
const rows = Array.from(table.querySelectorAll('tbody tr')).map(tr => {
return Array.from(tr.querySelectorAll('td'))
.map((td, index) => ({ text: td.textContent.trim(), index }))
const sourceCells = Array.from(tr.querySelectorAll('td'))
.map((td, index) => ({ text: td.textContent.trim(), index }));
return sourceCells
.filter(cell => !excludeColumns.includes(cell.index))
.map(cell => cell.text);
.map(cell => {
const pin = getCellPin ? getCellPin(sourceCells, cell.index) : null;
return pin ? { content: cell.text, pin } : cell.text;
});
});
autoTable(this.pdf, {
@@ -425,6 +430,31 @@ class PDFGenerator {
},
didDrawPage: (data) => {
this.cursorY = data.cursor.y + 10;
},
didDrawCell: (data) => {
const pin = data.cell.raw?.pin;
if (!pin || data.section !== 'body') return;
const fontSize = 7;
const teamText = Array.isArray(data.cell.text)
? data.cell.text.join(' ')
: String(data.cell.text || '');
const pinText = `(${pin})`;
const padding = data.cell.padding('left');
const teamWidth = this.pdf.getTextWidth(teamText);
const pinWidth = this.pdf.getTextWidth(pinText) * (fontSize / this.pdf.getFontSize());
const pinX = data.cell.x + padding + teamWidth + 1;
const pinY = data.cell.y + data.cell.height - 3;
this.pdf.setFontSize(fontSize);
this.pdf.setTextColor(90);
if (pinX + pinWidth <= data.cell.x + data.cell.width - data.cell.padding('right')) {
this.pdf.text(pinText, pinX, pinY);
} else {
this.pdf.text(pinText, data.cell.x + padding, pinY);
}
this.pdf.setFontSize(11);
this.pdf.setTextColor(0);
}
});
} else {

View File

@@ -2504,19 +2504,29 @@ export default {
const pdfGen = new PDFGenerator(20, 10, this.$t);
pdfGen.addTitle(`${this.$t('schedule.gamesFor')} ${highlightName} ${this.$t('common.in')} ${this.selectedLeague}`);
// Bestimme die auszuschließenden Spalten
// Spaltenstruktur: Datum, Uhrzeit, Heimmannschaft, Gastmannschaft, Ergebnis, [Altersklasse], Code, Heim-PIN, Gast-PIN
// Die Ortsliste steht auf Seite 2. In der Spieltabelle bleiben Datum,
// Uhrzeit, Heim- und Gastmannschaft sowie ggf. die Altersklasse.
// Spaltenstruktur: Ort, Datum, Uhrzeit, Heim, Gast, Ergebnis,
// [Altersklasse], Code, Heim-PIN, Gast-PIN
const hasAgeClass = this.selectedLeague === this.$t('schedule.overallSchedule') || this.selectedLeague === this.$t('schedule.adultSchedule');
let excludeColumns;
if (hasAgeClass) {
// Mit Altersklasse: Ergebnis=4, Code=6, Heim-PIN=7, Gast-PIN=8
excludeColumns = [4, 6, 7, 8];
// Mit Altersklasse: Ort=0, Ergebnis=5, Code=7, Heim-PIN=8, Gast-PIN=9
excludeColumns = [0, 5, 7, 8, 9];
} else {
// Ohne Altersklasse: Ergebnis=4, Code=5, Heim-PIN=6, Gast-PIN=7
excludeColumns = [4, 5, 6, 7];
// Ohne Altersklasse: Ort=0, Ergebnis=5, Code=6, Heim-PIN=7, Gast-PIN=8
excludeColumns = [0, 5, 6, 7, 8];
}
pdfGen.addTable('schedule-table', highlightName, excludeColumns);
const homePinIndex = hasAgeClass ? 8 : 7;
const guestPinIndex = hasAgeClass ? 9 : 8;
const getOwnTeamPin = (cells, index) => {
if (this.friendlyOnly || (index !== 3 && index !== 4)) return null;
const teamName = cells[index]?.text || '';
const pin = cells[index === 3 ? homePinIndex : guestPinIndex]?.text || '';
return teamName.includes(highlightName) && pin !== '-' ? pin : null;
};
pdfGen.addTable('schedule-table', highlightName, excludeColumns, getOwnTeamPin);
pdfGen.addNewPage();
const uniqueLocations = this.getUniqueLocations();
uniqueLocations.forEach((addressLines, clubName) => {