Minimales Beispiel
Folgend ein Action Script welches auf ein Button gelegt wurde um ein Report zu generieren. In diesem Script können
reportName, reportRoute, reportData angepasst werden um mit dem nachfolgend aufgeführten NodeRed Flow zu interagieren.
const CONNECTOR_API_URL = fyzPlatform.env.get().config.connectorApiUrl;
// Set The NodeRed Endpoint you have chosen
const reportRoute = 'generateReport';
// Set the file name you want the user to have when downloading
const reportDate = "2025-09-01"
const reportName = `${reportDate}_report`;
// Set the date you want to use inside the endpoint
const reportData = {
test: "1234",
testArray: [
{ id: `1`, name: "content1" },
{ id: `2`, name: "content2" }
]
}
// execute the report
generateReport(reportRoute, reportName, reportData);
// helper function - call the node red endpoint
function generateReport(route, name, data) {
fyzUtils.httpApi
.executeRequestsAsync([{
action: 'POST',
url: CONNECTOR_API_URL + '/api/data/connect',
body: {
Configuration: {
Endpoint: 'FLYZE_NODE_RED',
Route: `${route}`,
Authentication: false
},
ApiConfig: data
},
responseType: "arraybuffer"
}], (res) => {
if (res && res[0]) {
makeBrowserDownload(res[0], name);
}
})
}
// helper function - download the file to browser
function makeBrowserDownload(fileData, fileName) {
// Create a blob from the response
const blob = new Blob([fileData], { type: "application/pdf" });
// Create a temporary download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${fileName}.pdf`; // filename
document.body.appendChild(a);
a.click();
// Clean up
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
Damit das obige Script funktioniert, kann folgender NodeRed Flow verwendet werden:
[
{
"id": "26ecfdaf11c9fd26",
"type": "tab",
"label": "Test Report",
"disabled": false,
"info": "",
"env": []
},
{
"id": "30185f1ee6edfa2a",
"type": "http in",
"z": "26ecfdaf11c9fd26",
"name": "[/generateReport] Endpoint",
"url": "/generateReport",
"method": "post",
"upload": false,
"skipBodyParsing": false,
"swaggerDoc": "",
"x": 310,
"y": 540,
"wires": [
[
"9eaf35c32f79644b"
]
]
},
{
"id": "dc1d843cef0e8697",
"type": "http request",
"z": "26ecfdaf11c9fd26",
"name": "Send Request to Reporting Api",
"method": "POST",
"ret": "bin",
"paytoqs": "ignore",
"url": "http://reporting-api:8080/export",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 1530,
"y": 540,
"wires": [
[
"5cad433444728aa4"
]
]
},
{
"id": "5cad433444728aa4",
"type": "http response",
"z": "26ecfdaf11c9fd26",
"name": "",
"statusCode": "",
"headers": {},
"x": 1750,
"y": 540,
"wires": []
},
{
"id": "e2667eff7ac96456",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Generate Report Configuration",
"func": "const reportData = msg.payload.reportData;\nconst reportTempate = msg.payload.reportTemplate;\n\nmsg.payload = {\n template: reportTempate.body,\n data: JSON.stringify(reportData),\n marginOptions: {\n top: \"5mm\",\n bottom: \"5mm\",\n left: \"10mm\",\n right: \"10mm\"\n },\n headerFooterOptions: {\n \"setHeaderFooter\": true,\n \"headerTemplate\": reportTempate.header,\n \"footerTemplate\": reportTempate.footer\n },\n Landscape: false,\n config: {\n dynamic: true,\n type: `PDF`,\n typeConfig: {\n filename: \"Check Car Report.pdf\"\n }\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1230,
"y": 540,
"wires": [
[
"dc1d843cef0e8697"
]
]
},
{
"id": "9eaf35c32f79644b",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Logo",
"func": "const myLogo = `<svg width=\"121\" height=\"117\" viewBox=\"0 0 121 117\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M38.1709 10.1491C16.7402 17.5182 17.9957 39.5376 17.9957 39.5376H8V56.5897H17.9077V108.309H35.652V56.5897H45.4757V39.5376H35.652V39.174C35.692 37.3197 36.3237 29.2512 44.2363 26.3859C47.079 25.3549 50.8534 24.9872 55.8792 25.8184V108.309H73.5715V12.9984C73.5515 12.9984 73.5915 12.9984 73.5715 12.9984V10.0652C57.6824 7.01202 46.3074 7.60347 38.1709 10.1491Z\" fill=\"black\"/>\n<path d=\"M112.743 84.6641H89.0973V108.294H112.743V84.6641Z\" fill=\"#0F6FFF\"/>\n</svg>\n`;\n\nmsg.payload = {\n ...msg.payload,\n logo: myLogo\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 850,
"y": 540,
"wires": [
[
"fc909feaa1445631"
]
]
},
{
"id": "7101b4b5b9b53c8d",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Endpoint Of Your Report",
"info": "# Test With:\n\nSyntax: `nodered-domain`/`endpointName`\nExample: `nodered.sub1.flyze.io/generateReport`",
"x": 310,
"y": 500,
"wires": []
},
{
"id": "b6dd5751c0789aef",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Page Footer",
"func": "const footerTemplate = `\n<style>\n /* Footer Styles */\n .page-footer {\n font-size: 8px;\n width: 100%;\n padding: 0 10mm;\n \n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n }\n .page-footer-logo {\n margin-right: 24px;\n }\n .page-footer-print-info {\n text-align: right;\n flex-grow: 1;\n }\n</style>\n<div class=\"page-footer\">\n <div class=\"page-footer-logo\">\n ${msg.payload.logo}\n </div>\n <div class=\"page-footer-print-info\">\n ${new Date().toLocaleDateString()}\n </div>\n</div>\n`\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n footer: footerTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 780,
"wires": [
[
"e2667eff7ac96456",
"f5285380de5542c3"
]
]
},
{
"id": "e8364391bb625c9e",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Page Header",
"func": "const headerTemplate = `\n<style>\n .page-header {\n font-size: 8px;\n width: 100%;\n padding: 0 10mm;\n\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n }\n\n #matrixNumber{\n margin: 0;\n }\n\n #system{\n margin: 0 0 0.5rem 0;\n }\n\n #description{\n \n }\n \n #tuev-info{\n font-size: 12px;\n color: red;\n align-self: center;\n }\n</style>\n<div class=\"page-header\">\n <div>\n <h3 id=\"matrixNumber\">\n FOO\n </h3>\n <h4 id=\"system\">\n BAR\n </h4>\n <p id=\"description\">\n BATZ\n </p>\n </div>\n <div id=\"tuev-info\">\n Die rot gekennzeichneten Punkte müssen alle 2 Jahre vom BB-TÜV überprüft werden<br />\n Bezug auf Vorschrift <a href=\"https://www.umwelt-online.de/recht/t_regeln/trb/trb800/801_26.htm#:~:text=1.1%20Diese%20TRB%20801%20Nr,insoweit%20den%20anderen%20TRB%20vor.\" target=\"_blank\">BetrSichV TRB801 Nr. 25</a>\n </div>\n <div>Seite <span class=\"pageNumber\"></span> von <span class=\"totalPages\"></span></div>\n</div>\n`;\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n header: headerTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 660,
"wires": [
[
"b4421ea9f1efe6b1"
]
]
},
{
"id": "b4421ea9f1efe6b1",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "PDF BODY",
"func": "const data = msg.payload;\n\nconst styles = `\n html {\n -webkit-print-color-adjust: exact;\n font-family: \"Calibri\", sans-serif;\n }\n .page-footer-logo {\n /*background-color: #ff44ff;\n margin: 16px;\n padding: 16px;\n */\n }\n\n body { \n /*background-color: #ff44ff;*/\n }\n`;\n\nconst content = `\n<div>\n Show If value of test equals 123, else show [No Content]\n ${data.test === \"123\" ? data.test : \"No Content\"}\n</div>\n\n<div ngFor=\"let test of testArray\" style=\"page-break-after: always;\">\n <div>Id: {{test.id}}</div>\n <div>Name: {{test.name}}</div>\n</div>\n\n<div class=\"page-footer-logo\" style=\"margin-right: 24px;\">\n ${data.logo}\n</div>\n<div class=\"page-footer-logo\" style=\"margin-right: 24px;\">\n {{logo}}\n</div>\n`;\n\nconst htmlTemplate = `\n<html>\n <title>Test</title>\n <style>\n ${styles}\n </style>\n\n <body>\n ${content}\n </body>\n</html>`\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n body: htmlTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 720,
"wires": [
[
"b6dd5751c0789aef"
]
]
},
{
"id": "037ad02b188af2e4",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Change Functions to Design PDF",
"info": "",
"x": 930,
"y": 500,
"wires": []
},
{
"id": "93960a29cd64e284",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Scripting Example",
"info": "# Call from Scripting\n\n``` javascript\nconst CONNECTOR_API_URL = fyzPlatform.env.get().config.connectorApiUrl;\n\n// Set The NodeRed Endpoint you have chosen \nconst reportRoute = 'generateReport';\n\n// Set the file name you want the user to have when downloading\nconst reportDate = \"2025-09-01\"\nconst reportName = `${reportDate}_report`;\n\n// Set the date you want to use inside the endpoint\nconst reportData = {\n test: \"1234\",\n testArray: [\n { id: `1`, name: \"content1\" },\n { id: `2`, name: \"content2\" }\n ]\n}\n\n// execute the report\ngenerateReport(reportRoute, reportName, reportData);\n\n\n// helper function - call the node red endpoint\nfunction generateReport(route, name, data) {\n fyzUtils.httpApi\n .executeRequestsAsync([{\n action: 'POST',\n url: CONNECTOR_API_URL + '/api/data/connect',\n body: {\n Configuration: {\n Endpoint: 'FLYZE_NODE_RED',\n Route: `${route}`,\n Authentication: false\n },\n ApiConfig: data\n },\n responseType: \"arraybuffer\"\n }], (res) => {\n if (res && res[0]) {\n makeBrowserDownload(res[0], name);\n }\n })\n}\n\n// helper function - download the file to browser\nfunction makeBrowserDownload(fileData, fileName) {\n // Create a blob from the response\n const blob = new Blob([fileData], { type: \"application/pdf\" });\n\n // Create a temporary download link\n const url = window.URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${fileName}.pdf`; // filename\n document.body.appendChild(a);\n a.click();\n\n // Clean up\n setTimeout(() => {\n document.body.removeChild(a);\n window.URL.revokeObjectURL(url);\n }, 0);\n}\n```",
"x": 290,
"y": 440,
"wires": []
},
{
"id": "fc909feaa1445631",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Report Data",
"func": "\nmsg.payload = {\n reportData: {\n ...msg.payload\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 600,
"wires": [
[
"e8364391bb625c9e"
]
]
},
{
"id": "b1119e7cbcccb861",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Report Configuration",
"info": "",
"x": 1190,
"y": 500,
"wires": []
},
{
"id": "95a29bd092ef79ae",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Add a logo",
"info": "",
"x": 720,
"y": 540,
"wires": []
},
{
"id": "89c1f931f118ec0b",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Pass Data",
"info": "",
"x": 720,
"y": 600,
"wires": []
},
{
"id": "23765e2d90ba3882",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define Header Design",
"info": "",
"x": 680,
"y": 660,
"wires": []
},
{
"id": "67a0070037431d40",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define Footer Design",
"info": "",
"x": 680,
"y": 780,
"wires": []
},
{
"id": "4356b43a505d4ba7",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define PDF Design",
"info": "",
"x": 690,
"y": 720,
"wires": []
},
{
"id": "f5285380de5542c3",
"type": "debug",
"z": "26ecfdaf11c9fd26",
"name": "debug 4",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 1160,
"y": 600,
"wires": []
}
]