mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-25 00:16:41 +02:00
fix(core): PDF-Export — Footer-Leerseite behoben und Logo ueber Profilfoto
- Footer: doc.page.margins.bottom temporaer auf 0 gesetzt beim Footer-Zeichnen verhindert PDFKit Auto-Pagination (footerTextY > maxY wuerde sonst eine leere zweite Seite erzeugen) - Logo: Platform-Branding-Logo (aus Redis platform_branding_logo) wird oben in der linken Spalte ueber dem Profilfoto gerendert (fit 180x50px) - Firmendaten + Branding parallel via Promise.all aus Redis geladen Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
46ced98bf4
commit
f5d83dc1c3
1 changed files with 35 additions and 8 deletions
|
|
@ -192,12 +192,16 @@ export class ProfileExportService {
|
|||
const data = await this.expertProfileService.getExportData(userId) as ExportData;
|
||||
const profile = data.expertProfile;
|
||||
|
||||
// Firmendaten für PDF-Footer laden
|
||||
// Firmendaten + Branding-Logo parallel laden
|
||||
let companyFooterText = '';
|
||||
let platformLogo: Buffer | null = null;
|
||||
try {
|
||||
const raw = await this.redis.get('platform_company_settings');
|
||||
if (raw) {
|
||||
const c = JSON.parse(raw) as Record<string, unknown>;
|
||||
const [companyRaw, brandingRaw] = await Promise.all([
|
||||
this.redis.get('platform_company_settings'),
|
||||
this.redis.get('platform_branding_logo'),
|
||||
]);
|
||||
if (companyRaw) {
|
||||
const c = JSON.parse(companyRaw) as Record<string, unknown>;
|
||||
const address = [c['street'], [c['postalCode'], c['city']].filter(Boolean).join(' ')].filter(Boolean).join(', ');
|
||||
companyFooterText = [
|
||||
c['name'],
|
||||
|
|
@ -207,7 +211,13 @@ export class ProfileExportService {
|
|||
c['website'],
|
||||
].filter(Boolean).join(' | ');
|
||||
}
|
||||
} catch { /* Firmendaten nicht verfügbar — kein Footer */ }
|
||||
if (brandingRaw) {
|
||||
const b = JSON.parse(brandingRaw) as Record<string, unknown>;
|
||||
if (typeof b['logo'] === 'string' && b['logo']) {
|
||||
platformLogo = this.base64ToBuffer(b['logo']);
|
||||
}
|
||||
}
|
||||
} catch { /* Einstellungen nicht verfügbar */ }
|
||||
const fullName = `${data.firstName} ${data.lastName}`;
|
||||
const { firstName, lastName } = data;
|
||||
|
||||
|
|
@ -236,6 +246,19 @@ export class ProfileExportService {
|
|||
|
||||
// --- SEITE 1: Linke Spalte ---
|
||||
|
||||
// Platform-Logo (über dem Profilfoto)
|
||||
if (platformLogo) {
|
||||
try {
|
||||
doc.image(platformLogo, leftColX, yLeft, {
|
||||
fit: [leftColWidth, 50],
|
||||
align: 'center',
|
||||
});
|
||||
yLeft += 58;
|
||||
} catch (err) {
|
||||
this.logger.warn('Platform-Logo konnte nicht gerendert werden', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Avatar (rundes Bild)
|
||||
if (data.avatar) {
|
||||
try {
|
||||
|
|
@ -497,16 +520,20 @@ export class ProfileExportService {
|
|||
|
||||
// --- FOOTER: Firmendaten auf jeder Seite ---
|
||||
if (companyFooterText) {
|
||||
const pageHeight = doc.page.height;
|
||||
const footerLineY = pageHeight - 32;
|
||||
const footerTextY = pageHeight - 26;
|
||||
const range = doc.bufferedPageRange();
|
||||
for (let p = range.start; p < range.start + range.count; p++) {
|
||||
doc.switchToPage(p);
|
||||
// Bottom-Margin temporär auf 0, damit PDFKit keine Leerseite erzeugt
|
||||
const origBottom = doc.page.margins.bottom;
|
||||
doc.page.margins.bottom = 0;
|
||||
const pageH = doc.page.height;
|
||||
const footerLineY = pageH - 32;
|
||||
const footerTextY = pageH - 26;
|
||||
doc.moveTo(40, footerLineY).lineTo(pageWidth - 40, footerLineY)
|
||||
.strokeColor('#cccccc').lineWidth(0.5).stroke();
|
||||
doc.font('Helvetica').fontSize(7).fillColor('#999999');
|
||||
doc.text(companyFooterText, 40, footerTextY, { width: pageWidth - 80, align: 'center', lineBreak: false });
|
||||
doc.page.margins.bottom = origBottom;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue