render protocol by template
This commit is contained in:
parent
da219eb5f4
commit
58213923e5
8 changed files with 950 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -130,3 +130,4 @@ dist
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
export
|
804
package-lock.json
generated
804
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -32,6 +32,7 @@
|
||||||
"mysql": "^2.18.1",
|
"mysql": "^2.18.1",
|
||||||
"node-schedule": "^2.1.1",
|
"node-schedule": "^2.1.1",
|
||||||
"nodemailer": "^6.9.14",
|
"nodemailer": "^6.9.14",
|
||||||
|
"pdf-creator-node": "^2.3.5",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"socket.io": "^4.7.5",
|
"socket.io": "^4.7.5",
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { SynchronizeProtocolDecisionCommand } from "../../command/protocolDecisi
|
||||||
import { SynchronizeProtocolVotingCommand } from "../../command/protocolVotingCommand";
|
import { SynchronizeProtocolVotingCommand } from "../../command/protocolVotingCommand";
|
||||||
import { ProtocolVotingViewModel } from "../../viewmodel/admin/protocolVoting.models";
|
import { ProtocolVotingViewModel } from "../../viewmodel/admin/protocolVoting.models";
|
||||||
import ProtocolVotingCommandHandler from "../../command/protocolVotingCommandHandler";
|
import ProtocolVotingCommandHandler from "../../command/protocolVotingCommandHandler";
|
||||||
|
import { PdfExport } from "../../helpers/pdfExport";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description get all protocols
|
* @description get all protocols
|
||||||
|
@ -289,3 +290,47 @@ export async function synchronizeProtocolPrecenseById(req: Request, res: Respons
|
||||||
|
|
||||||
res.sendStatus(204);
|
res.sendStatus(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description render protocol to file by id
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function printPdf(req: Request, res: Response): Promise<any> {
|
||||||
|
let protocolId = parseInt(req.params.protocolId);
|
||||||
|
let protocol = await ProtocolService.getById(protocolId);
|
||||||
|
let agenda = await ProtocolAgendaService.getAll(protocolId);
|
||||||
|
let decisions = await ProtocolDecisionService.getAll(protocolId);
|
||||||
|
let presence = await ProtocolPresenceService.getAll(protocolId);
|
||||||
|
let votings = await ProtocolVotingService.getAll(protocolId);
|
||||||
|
|
||||||
|
await PdfExport.renderFile({
|
||||||
|
template: "protocol.template.html",
|
||||||
|
title: protocol.title,
|
||||||
|
data: {
|
||||||
|
title: protocol.title,
|
||||||
|
summary: protocol.summary,
|
||||||
|
date: new Date(protocol.date).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
}),
|
||||||
|
start: new Date(protocol.starttime).toLocaleTimeString("de-DE", {
|
||||||
|
minute: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
}),
|
||||||
|
end: new Date(protocol.endtime).toLocaleTimeString("de-DE", {
|
||||||
|
minute: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
}),
|
||||||
|
agenda,
|
||||||
|
decisions,
|
||||||
|
presence: presence.map((p) => p.member),
|
||||||
|
votings,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
34
src/helpers/pdfExport.ts
Normal file
34
src/helpers/pdfExport.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import pdf, { Options } from "pdf-creator-node";
|
||||||
|
|
||||||
|
var options = (title: string = "pdf-export Mitgliederverwaltung"): Options => ({
|
||||||
|
format: "A4",
|
||||||
|
orientation: "portrait",
|
||||||
|
border: "10mm",
|
||||||
|
header: {
|
||||||
|
height: "10mm",
|
||||||
|
contents: `<h1 style="text-align: center;">${title}</h1>`,
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
height: "5mm",
|
||||||
|
contents: {
|
||||||
|
default: '<span style="color: #444;">{{page}}</span>/<span>{{pages}}</span>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export abstract class PdfExport {
|
||||||
|
static getTemplate(template: string) {
|
||||||
|
return readFileSync(process.cwd() + "/src/templates/" + template, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
static async renderFile({ template, title, data }: { template: string; title: string; data: any }) {
|
||||||
|
let document = {
|
||||||
|
html: this.getTemplate(template),
|
||||||
|
data,
|
||||||
|
path: process.cwd() + `/export/${title}.pdf`,
|
||||||
|
};
|
||||||
|
|
||||||
|
await pdf.create(document, options(title));
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import {
|
||||||
getProtocolDecisonsById,
|
getProtocolDecisonsById,
|
||||||
getProtocolPrecenseById,
|
getProtocolPrecenseById,
|
||||||
getProtocolVotingsById,
|
getProtocolVotingsById,
|
||||||
|
printPdf,
|
||||||
synchronizeProtocolAgendaById,
|
synchronizeProtocolAgendaById,
|
||||||
synchronizeProtocolById,
|
synchronizeProtocolById,
|
||||||
synchronizeProtocolDecisonsById,
|
synchronizeProtocolDecisonsById,
|
||||||
|
@ -59,6 +60,10 @@ router.post("/:protocolId/voting", async (req: Request, res: Response) => {
|
||||||
await createProtocolVotingsById(req, res);
|
await createProtocolVotingsById(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("/:protocolId/render", async (req: Request, res: Response) => {
|
||||||
|
await printPdf(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.patch("/:id/synchronize", async (req: Request, res: Response) => {
|
router.patch("/:id/synchronize", async (req: Request, res: Response) => {
|
||||||
await synchronizeProtocolById(req, res);
|
await synchronizeProtocolById(req, res);
|
||||||
});
|
});
|
||||||
|
|
36
src/templates/protocol.template.html
Normal file
36
src/templates/protocol.template.html
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Protokoll</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
<p>Am {{date}} von {{start}} Uhr bis {{end}} Uhr</p>
|
||||||
|
<p>{{sumary}}</p>
|
||||||
|
<h2>Anwesenheit</h2>
|
||||||
|
<ul>
|
||||||
|
{{#each presence}}
|
||||||
|
<li>{{this.firstname}} {{this.lastname}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
<h2>Agenda</h2>
|
||||||
|
<ul>
|
||||||
|
{{#each agenda}}
|
||||||
|
<li>{{this}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
<h2>Entscheidungen</h2>
|
||||||
|
<ul>
|
||||||
|
{{#each decisions}}
|
||||||
|
<li>{{this}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
<h2>Abstimmungen</h2>
|
||||||
|
<ul>
|
||||||
|
{{#each votings}}
|
||||||
|
<li>{{this}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
src/types/pdf-creator-node.d.ts
vendored
Normal file
27
src/types/pdf-creator-node.d.ts
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// types/pdf-creator-node.d.ts
|
||||||
|
declare module "pdf-creator-node" {
|
||||||
|
interface Document {
|
||||||
|
html: string;
|
||||||
|
data: any;
|
||||||
|
path: string;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
format: string;
|
||||||
|
orientation: string;
|
||||||
|
border: string;
|
||||||
|
header?: {
|
||||||
|
height: string;
|
||||||
|
contents: string;
|
||||||
|
};
|
||||||
|
footer?: {
|
||||||
|
height: string;
|
||||||
|
contents: string | { [key: string]: string | number };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(document: Document, options: Options): Promise<any>;
|
||||||
|
|
||||||
|
export { create, Document, Options };
|
||||||
|
}
|
Loading…
Reference in a new issue