berichtsheft 20. April 2024

Berichtsheft PDF Generator

Automatische PDF-Generierung für Ausbildungsnachweise mit Puppeteer und HTML Templates.

node.jspuppeteerpdftypescript

PDF Generation Service

Ausbildungsnachweise als PDF generieren aus strukturierten Daten mit HTML-Template.

import puppeteer from 'puppeteer';

interface BerichtsheftEntry {
  week: number;
  startDate: string;
  endDate: string;
  department: string;
  activities: string[];
  schoolTopics?: string[];
}

export async function generateBerichtsheftPdf(
  entries: BerichtsheftEntry[],
  trainee: { name: string; profession: string; year: number }
): Promise<Buffer> {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  const html = buildTemplate(entries, trainee);
  await page.setContent(html, { waitUntil: 'networkidle0' });

  const pdf = await page.pdf({
    format: 'A4',
    margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
    printBackground: true,
  });

  await browser.close();
  return Buffer.from(pdf);
}

function buildTemplate(entries: BerichtsheftEntry[], trainee: { name: string; profession: string; year: number }): string {
  return `
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        body { font-family: Arial, sans-serif; font-size: 11pt; }
        .header { text-align: center; margin-bottom: 20px; border-bottom: 2px solid #333; padding-bottom: 10px; }
        .entry { page-break-inside: avoid; margin-bottom: 16px; border: 1px solid #ddd; padding: 12px; border-radius: 4px; }
        .entry-header { font-weight: bold; margin-bottom: 8px; color: #333; }
        .activities li { margin-bottom: 4px; }
        .meta { color: #666; font-size: 9pt; }
      </style>
    </head>
    <body>
      <div class="header">
        <h2>Ausbildungsnachweis</h2>
        <p class="meta">${trainee.name}${trainee.profession}${trainee.year}. Ausbildungsjahr</p>
      </div>
      ${entries.map((entry) => `
        <div class="entry">
          <div class="entry-header">KW ${entry.week} | ${entry.startDate}${entry.endDate} | ${entry.department}</div>
          <strong>Betriebliche Tätigkeiten:</strong>
          <ul class="activities">
            ${entry.activities.map((a) => `<li>${a}</li>`).join('')}
          </ul>
          ${entry.schoolTopics ? `
            <strong>Berufsschule:</strong>
            <ul>${entry.schoolTopics.map((t) => `<li>${t}</li>`).join('')}</ul>
          ` : ''}
        </div>
      `).join('')}
    </body>
    </html>
  `;
}