Fixed schedule PDF

This commit is contained in:
Torsten Schulz
2025-07-16 17:15:19 +02:00
parent f5deb343a8
commit ad2ab3cae8
5 changed files with 1135 additions and 373 deletions

View File

@@ -1,4 +1,5 @@
import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
import html2canvas from 'html2canvas';
class PDFGenerator {
@@ -17,6 +18,7 @@ class PDFGenerator {
this.COLUMN_GROUP = margin + 100;
this.COLUMN_DURATION = margin + 150;
this.LINE_HEIGHT = 7;
this.cursorY = margin;
}
async addSchedule(element) {
@@ -59,6 +61,23 @@ class PDFGenerator {
this.isLeftColumn = true;
}
addTitle(text) {
// remember old settings
const oldFont = this.pdf.getFont();
const oldStyle = this.pdf.getFont().fontStyle;
const oldSize = this.pdf.getFontSize();
// set new
this.pdf.setFont('helvetica', 'bold');
this.pdf.setFontSize(14);
this.pdf.text(text, this.margin, this.cursorY);
this.cursorY += 10;
// restore
this.pdf.setFont(oldFont.fontName, oldStyle);
this.pdf.setFontSize(oldSize);
}
addHeader(clubName, formattedDate, formattedStartTime, formattedEndTime) {
this.pdf.setFontSize(14);
this.pdf.setFont('helvetica', 'bold');
@@ -196,11 +215,9 @@ class PDFGenerator {
if (!this.addressY) {
this.addressY = 30;
}
this.pdf.setFontSize(14);
this.pdf.setFont(undefined, 'bold');
this.pdf.text(clubName, 20, this.addressY);
this.pdf.setFontSize(12);
this.pdf.setFont(undefined, 'normal');
addressLines.forEach(line => {
@@ -210,6 +227,44 @@ class PDFGenerator {
this.addressY += 10; // Abstand zur nächsten Adresse
}
async addScreenshot(element) {
const canvas = await html2canvas(element, { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const imgWidth = this.pageWidth;
const imgHeight = (canvas.height * imgWidth) / canvas.width;
this.pdf.addImage(imgData, 'PNG', this.margin, this.cursorY, imgWidth, imgHeight);
this.cursorY += imgHeight + 10;
if (this.cursorY > this.pdf.internal.pageSize.height - this.margin) {
this.pdf.addPage();
this.cursorY = this.margin;
}
}
addTable(tableId, highlightName = '') {
this.pdf.setFontSize(11);
console.log(highlightName);
autoTable(this.pdf, {
html: `#${tableId}`,
startY: this.cursorY,
margin: { left: this.margin, right: this.margin },
styles: { fontSize: this.pdf.getFontSize() },
headStyles: { fillColor: [220, 220, 220], textColor: 0, halign: 'left' },
theme: 'grid',
didParseCell: (data) => {
const cellText = Array.isArray(data.cell.text)
? data.cell.text.join(' ')
: String(data.cell.text);
if (highlightName && cellText.includes(highlightName)) {
data.cell.styles.fontStyle = 'bold';
}
},
didDrawPage: (data) => {
this.cursorY = data.cursor.y + 10;
}
});
}
}
export default PDFGenerator;

View File

@@ -16,7 +16,7 @@
<button @click="generatePDF">Download PDF</button>
<div v-if="matches.length > 0">
<h3>Spiele für {{ selectedLeague }}</h3>
<table>
<table id="schedule-table">
<thead>
<tr>
<th>Datum</th>
@@ -59,8 +59,6 @@
<script>
import { mapGetters } from 'vuex';
import apiClient from '../apiClient.js';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
import PDFGenerator from '../components/PDFGenerator.js';
export default {
@@ -97,7 +95,7 @@ export default {
formData.append('clubId', this.currentClub);
try {
const response = await apiClient.post('/matches/import', formData, {
await apiClient.post('/matches/import', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
@@ -130,8 +128,12 @@ export default {
}
},
formatDate(date) {
const d = new Date(date);
const weekdays = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
const wd = weekdays[d.getDay()];
const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
return new Date(date).toLocaleDateString('de-DE', options);
const day = d.toLocaleDateString('de-DE', options);
return `${wd} ${day}`;
},
highlightClubName(teamName) {
const clubName = this.currentClubName;
@@ -141,18 +143,24 @@ export default {
return teamName;
},
getCurrentClubName() {
const club = this.clubs.find(club => club.id === this.currentClub);
const clubIdNum = Number(this.currentClub);
const club = this.clubs.find(c => c.id === clubIdNum);
return club ? club.name : '';
},
async generatePDF() {
const element = this.$el.querySelector('.flex-item > div');
const highlightName = this.getCurrentClubName();
if (element) {
const pdfGen = new PDFGenerator();
await pdfGen.addSchedule(element);
pdfGen.addTitle(`Spiele für ${highlightName} in ${this.selectedLeague}`);
pdfGen.addTable('schedule-table', highlightName);
pdfGen.addNewPage();
const uniqueLocations = this.getUniqueLocations();
uniqueLocations.forEach((addressLines, clubName) => {
pdfGen.addAddress(clubName, addressLines);
if (!clubName.includes(highlightName)) {
console.log(clubName, highlightName);
pdfGen.addAddress(clubName, addressLines);
}
});
pdfGen.save('Spielpläne.pdf');