feat: Add certificate templates for Scrum, ITIL, and PRINCE2 courses
- Add 3 new HTML templates: ScrumGeneric, ITIL, PRINCE2 - Add 3 background images: blue (Scrum), green (ITIL), orange (PRINCE2) - Extract and add signatures: Gablas, Husam - Update certificate.service.js to support multiple templates with different backgrounds Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
BIN
src/assets/certificate/background-blue.jpeg
Normal file
BIN
src/assets/certificate/background-blue.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 800 KiB |
BIN
src/assets/certificate/background-green.jpeg
Normal file
BIN
src/assets/certificate/background-green.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 326 KiB |
BIN
src/assets/certificate/background-orange.jpeg
Normal file
BIN
src/assets/certificate/background-orange.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 373 KiB |
BIN
src/assets/certificate/signature-gablas.png
Normal file
BIN
src/assets/certificate/signature-gablas.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/certificate/signature-husam.png
Normal file
BIN
src/assets/certificate/signature-husam.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -20,13 +20,26 @@ export const CERTIFICATE_TEMPLATES = {
|
|||||||
name: 'AI Certifikát',
|
name: 'AI Certifikát',
|
||||||
file: 'AIcertifikat.html',
|
file: 'AIcertifikat.html',
|
||||||
description: 'Osvedčenie o absolvovaní AI kurzu',
|
description: 'Osvedčenie o absolvovaní AI kurzu',
|
||||||
|
background: 'background.jpeg',
|
||||||
|
},
|
||||||
|
ScrumGeneric: {
|
||||||
|
name: 'Scrum (Gablas)',
|
||||||
|
file: 'ScrumGeneric.html',
|
||||||
|
description: 'Scrum Master / Product Owner - lektor Gablas',
|
||||||
|
background: 'background-blue.jpeg',
|
||||||
|
},
|
||||||
|
ITIL: {
|
||||||
|
name: 'ITIL (Husam)',
|
||||||
|
file: 'ITIL.html',
|
||||||
|
description: 'ITIL Foundation - lektor Husam',
|
||||||
|
background: 'background-green.jpeg',
|
||||||
|
},
|
||||||
|
PRINCE2: {
|
||||||
|
name: 'PRINCE2 (Gablas)',
|
||||||
|
file: 'PRINCE2.html',
|
||||||
|
description: 'PRINCE2 Foundation/Practitioner - lektor Gablas',
|
||||||
|
background: 'background-orange.jpeg',
|
||||||
},
|
},
|
||||||
// Add more templates here in the future
|
|
||||||
// participation: {
|
|
||||||
// name: 'Potvrdenie o účasti',
|
|
||||||
// file: 'participation.html',
|
|
||||||
// description: 'Potvrdenie o účasti na školení',
|
|
||||||
// },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,9 +70,12 @@ const generateCertificateId = (registraciaId) => {
|
|||||||
/**
|
/**
|
||||||
* Load assets as base64 for embedding in HTML
|
* Load assets as base64 for embedding in HTML
|
||||||
*/
|
*/
|
||||||
const loadAssets = async () => {
|
const loadAssets = async (templateName) => {
|
||||||
|
const template = CERTIFICATE_TEMPLATES[templateName];
|
||||||
|
const backgroundFile = template?.background || 'background.jpeg';
|
||||||
|
|
||||||
const [background, signatureGablasova, signatureZdarilek] = await Promise.all([
|
const [background, signatureGablasova, signatureZdarilek] = await Promise.all([
|
||||||
fs.readFile(path.join(ASSETS_DIR, 'background.jpeg')),
|
fs.readFile(path.join(ASSETS_DIR, backgroundFile)),
|
||||||
fs.readFile(path.join(ASSETS_DIR, 'signature-gablasova.png')),
|
fs.readFile(path.join(ASSETS_DIR, 'signature-gablasova.png')),
|
||||||
fs.readFile(path.join(ASSETS_DIR, 'signature-zdarilek.png')),
|
fs.readFile(path.join(ASSETS_DIR, 'signature-zdarilek.png')),
|
||||||
]);
|
]);
|
||||||
@@ -196,7 +212,7 @@ export const generateCertificate = async (registraciaId, templateName = 'AIcerti
|
|||||||
// Load template and assets
|
// Load template and assets
|
||||||
const [templateHtml, assets] = await Promise.all([
|
const [templateHtml, assets] = await Promise.all([
|
||||||
loadTemplate(templateName),
|
loadTemplate(templateName),
|
||||||
loadAssets(),
|
loadAssets(templateName),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Generate certificate data
|
// Generate certificate data
|
||||||
|
|||||||
120
src/templates/certificates/ITIL.html
Normal file
120
src/templates/certificates/ITIL.html
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="sk">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Osvedčenie - {{participantName}}</title>
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap');
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: A4 landscape;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Open Sans', Arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
position: relative;
|
||||||
|
background-image: url('{{backgroundImage}}');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
top: 42mm;
|
||||||
|
left: 15mm;
|
||||||
|
right: 15mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-title {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 8mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-dates {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 3mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-hours {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-section {
|
||||||
|
position: absolute;
|
||||||
|
top: 58%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-name {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-date {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32mm;
|
||||||
|
left: 20mm;
|
||||||
|
font-size: 11pt;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate-id {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8mm;
|
||||||
|
right: 15mm;
|
||||||
|
font-size: 7pt;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="certificate">
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="course-title">{{courseTitle}}</h2>
|
||||||
|
{{#if dateRange}}
|
||||||
|
<p class="course-dates">{{dateRange}}</p>
|
||||||
|
{{/if}}
|
||||||
|
{{#if courseHours}}
|
||||||
|
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="participant-section">
|
||||||
|
<h3 class="participant-name">{{participantName}}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="issue-date">{{issueDate}}</div>
|
||||||
|
<div class="certificate-id">ID: {{certificateId}}</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
120
src/templates/certificates/PRINCE2.html
Normal file
120
src/templates/certificates/PRINCE2.html
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="sk">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Osvedčenie - {{participantName}}</title>
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap');
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: A4 landscape;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Open Sans', Arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
position: relative;
|
||||||
|
background-image: url('{{backgroundImage}}');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
top: 42mm;
|
||||||
|
left: 15mm;
|
||||||
|
right: 15mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-title {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 8mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-dates {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 3mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-hours {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-section {
|
||||||
|
position: absolute;
|
||||||
|
top: 58%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-name {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-date {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32mm;
|
||||||
|
left: 20mm;
|
||||||
|
font-size: 11pt;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate-id {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8mm;
|
||||||
|
right: 15mm;
|
||||||
|
font-size: 7pt;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="certificate">
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="course-title">{{courseTitle}}</h2>
|
||||||
|
{{#if dateRange}}
|
||||||
|
<p class="course-dates">{{dateRange}}</p>
|
||||||
|
{{/if}}
|
||||||
|
{{#if courseHours}}
|
||||||
|
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="participant-section">
|
||||||
|
<h3 class="participant-name">{{participantName}}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="issue-date">{{issueDate}}</div>
|
||||||
|
<div class="certificate-id">ID: {{certificateId}}</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
126
src/templates/certificates/ScrumGeneric.html
Normal file
126
src/templates/certificates/ScrumGeneric.html
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="sk">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Osvedčenie - {{participantName}}</title>
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap');
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: A4 landscape;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Open Sans', Arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate {
|
||||||
|
width: 297mm;
|
||||||
|
height: 210mm;
|
||||||
|
position: relative;
|
||||||
|
background-image: url('{{backgroundImage}}');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
top: 42mm;
|
||||||
|
left: 15mm;
|
||||||
|
right: 15mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-title {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 8mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-dates {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 3mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-hours {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-section {
|
||||||
|
position: absolute;
|
||||||
|
top: 58%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-name {
|
||||||
|
font-size: 28pt;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-birthdate {
|
||||||
|
font-size: 12pt;
|
||||||
|
color: #333;
|
||||||
|
margin-top: 2mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.issue-date {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32mm;
|
||||||
|
left: 20mm;
|
||||||
|
font-size: 11pt;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certificate-id {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8mm;
|
||||||
|
right: 15mm;
|
||||||
|
font-size: 7pt;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="certificate">
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="course-title">{{courseTitle}}</h2>
|
||||||
|
{{#if dateRange}}
|
||||||
|
<p class="course-dates">{{dateRange}}</p>
|
||||||
|
{{/if}}
|
||||||
|
{{#if courseHours}}
|
||||||
|
<p class="course-hours">v rozsahu {{courseHours}} hodín</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="participant-section">
|
||||||
|
<h3 class="participant-name">{{participantName}}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="issue-date">{{issueDate}}</div>
|
||||||
|
<div class="certificate-id">ID: {{certificateId}}</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user