mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-24 22:36:38 +02:00
fix(core): PDF-Export — Timeline-Linien korrekt und Faehigkeiten in linke Spalte
- BERUFSERFAHRUNG: Timeline-Linie wird jetzt NACH dem Content gezeichnet (entryStartY gespeichert, Linie von entryStartY+8 bis yRight-4) Damit stimmt die Laenge exakt mit der tatsaechlichen Eintraghoehe ueberein - Seitenumbruch-Flag (pageBreakOccurred): Linie wird nicht gezeichnet wenn der Content ueber eine Seite hinausgeht - FAEHIGKEITEN: aus dem full-width Bereich am Seitenende entfernt und in die linke Spalte nach ERFAHRUNG verschoben (kleinere Chips: 7pt, 16px, 5px Pad) - Alte full-width FAEHIGKEITEN-Sektion entfernt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
41d944312c
commit
ed24c061c4
1 changed files with 38 additions and 53 deletions
|
|
@ -313,6 +313,34 @@ export class ProfileExportService {
|
|||
}
|
||||
}
|
||||
|
||||
// --- FÄHIGKEITEN (linke Spalte, nach Erfahrungen) ---
|
||||
if (profile && profile.skills.length > 0) {
|
||||
yLeft += 6;
|
||||
yLeft = this.pdfSectionTitle(doc, 'FÄHIGKEITEN', leftColX, yLeft, leftColWidth, accentColor);
|
||||
const skillStartX = leftColX;
|
||||
const skillMaxX = leftColX + leftColWidth;
|
||||
let skillX = skillStartX;
|
||||
let skillY = yLeft;
|
||||
const skillChipH = 16;
|
||||
const skillChipPad = 5;
|
||||
const skillChipGap = 4;
|
||||
const skillBg = lightenColor(accentColor, 0.85);
|
||||
for (const skill of profile.skills) {
|
||||
doc.font('Helvetica').fontSize(7);
|
||||
const tw = doc.widthOfString(skill);
|
||||
const cw = tw + skillChipPad * 2;
|
||||
if (skillX + cw > skillMaxX) {
|
||||
skillX = skillStartX;
|
||||
skillY += skillChipH + skillChipGap;
|
||||
}
|
||||
doc.roundedRect(skillX, skillY, cw, skillChipH, 7).fill(skillBg);
|
||||
doc.font('Helvetica').fontSize(7).fillColor(accentColor);
|
||||
doc.text(skill, skillX + skillChipPad, skillY + 4, { width: tw, lineBreak: false });
|
||||
skillX += cw + skillChipGap;
|
||||
}
|
||||
yLeft = skillY + skillChipH + 4;
|
||||
}
|
||||
|
||||
// --- SEITE 1: Rechte Spalte — BERUFSERFAHRUNG ---
|
||||
if (profile && profile.projects.length > 0) {
|
||||
yRight = this.pdfSectionTitle(doc, 'BERUFSERFAHRUNG', rightColX, yRight, rightColWidth, accentColor);
|
||||
|
|
@ -331,14 +359,11 @@ export class ProfileExportService {
|
|||
yRight = this.pdfSectionTitle(doc, 'BERUFSERFAHRUNG (Forts.)', rightColX, yRight, rightColWidth, accentColor);
|
||||
}
|
||||
|
||||
// Timeline-Punkt
|
||||
doc.circle(timelineX, yRight + 4, 3.5).fill(accentColor);
|
||||
let pageBreakOccurred = false;
|
||||
const entryStartY = yRight;
|
||||
|
||||
// Timeline-Linie (bis zum nächsten Eintrag)
|
||||
if (i < profile.projects.length - 1) {
|
||||
doc.moveTo(timelineX, yRight + 8).lineTo(timelineX, yRight + 70)
|
||||
.strokeColor(accentColor).lineWidth(1).stroke();
|
||||
}
|
||||
// Timeline-Punkt
|
||||
doc.circle(timelineX, entryStartY + 4, 3.5).fill(accentColor);
|
||||
|
||||
// Zeitraum (fett, größer)
|
||||
const dateRange = this.formatDateRange(proj.fromMonth, proj.fromYear, proj.toMonth, proj.toYear, proj.isCurrent);
|
||||
|
|
@ -367,6 +392,7 @@ export class ProfileExportService {
|
|||
if (yRight > pageBottom) {
|
||||
doc.addPage();
|
||||
yRight = 40;
|
||||
pageBreakOccurred = true;
|
||||
}
|
||||
const raw = task.trim();
|
||||
const hasBullet = /^[•\u2022]\s/.test(raw) || /^\d+\.\s/.test(raw);
|
||||
|
|
@ -380,7 +406,11 @@ export class ProfileExportService {
|
|||
|
||||
yRight += 12;
|
||||
|
||||
// Aktualisiere Timeline-Linie (Länge basiert auf tatsächlicher Position)
|
||||
// Timeline-Linie (korrekte Länge basiert auf tatsächlicher Höhe)
|
||||
if (i < profile.projects.length - 1 && !pageBreakOccurred) {
|
||||
doc.moveTo(timelineX, entryStartY + 8).lineTo(timelineX, yRight - 4)
|
||||
.strokeColor(accentColor).lineWidth(1).stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,51 +463,6 @@ export class ProfileExportService {
|
|||
}
|
||||
}
|
||||
|
||||
// --- FÄHIGKEITEN (Skills als Chips) ---
|
||||
if (profile && profile.skills.length > 0) {
|
||||
let y = Math.max(yLeft, yRight);
|
||||
if (y > pageBottom - 60) {
|
||||
doc.addPage();
|
||||
y = 40;
|
||||
} else {
|
||||
y += 10;
|
||||
}
|
||||
|
||||
y = this.pdfSectionTitle(doc, 'FÄHIGKEITEN', 40, y, pageWidth - 80, accentColor);
|
||||
|
||||
const chipStartX = 40;
|
||||
const maxX = pageWidth - 40;
|
||||
let chipX = chipStartX;
|
||||
const chipHeight = 20;
|
||||
const chipPadding = 10;
|
||||
const chipGap = 6;
|
||||
const lightBg = lightenColor(accentColor, 0.85);
|
||||
|
||||
for (const skill of profile.skills) {
|
||||
doc.font('Helvetica').fontSize(8);
|
||||
const textWidth = doc.widthOfString(skill);
|
||||
const chipWidth = textWidth + chipPadding * 2;
|
||||
|
||||
if (chipX + chipWidth > maxX) {
|
||||
chipX = chipStartX;
|
||||
y += chipHeight + chipGap;
|
||||
if (y > pageBottom) {
|
||||
doc.addPage();
|
||||
y = 40;
|
||||
}
|
||||
}
|
||||
|
||||
// Chip-Hintergrund (abgerundetes Rechteck)
|
||||
doc.roundedRect(chipX, y, chipWidth, chipHeight, 10).fill(lightBg);
|
||||
|
||||
// Chip-Text
|
||||
doc.font('Helvetica').fontSize(8).fillColor(accentColor);
|
||||
doc.text(skill, chipX + chipPadding, y + 5.5, { width: textWidth, lineBreak: false });
|
||||
|
||||
chipX += chipWidth + chipGap;
|
||||
}
|
||||
}
|
||||
|
||||
// --- ANHÄNGE (Bild-Anhänge als zusätzliche Seiten) ---
|
||||
const attachments = profile?.attachments ?? [];
|
||||
for (const att of attachments) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue