- Introduced the `report_export` widget to the dashboard, allowing users to generate structured PDF reports. - Updated widget configuration to include `report_export` in the allowed widgets and added validation for its configuration. - Enhanced the widget catalog with details for the new `report_export` entry. - Implemented API endpoints for managing report profiles and generating PDFs. - Added frontend components for configuring and displaying report settings. - Updated tests to ensure proper validation and functionality of the new report generation features. - Bumped application version to reflect the addition of the new widget and related functionalities.
70 lines
2.1 KiB
JavaScript
70 lines
2.1 KiB
JavaScript
export const DASHBOARD_PDF_CAPTURE_ROOT_ID = 'dashboard-pdf-capture-root'
|
|
|
|
/**
|
|
* @param {{ scale?: number, filenameBase?: string }} [opts]
|
|
*/
|
|
export async function exportDashboardToPdf(opts = {}) {
|
|
const scale = opts.scale ?? 2
|
|
const filenameBase = opts.filenameBase ?? 'mitai-uebersicht'
|
|
|
|
const [{ default: html2canvas }, { jsPDF }] = await Promise.all([
|
|
import('html2canvas'),
|
|
import('jspdf'),
|
|
])
|
|
|
|
const el = document.getElementById(DASHBOARD_PDF_CAPTURE_ROOT_ID)
|
|
if (!el) throw new Error('Dashboard-Inhalt nicht gefunden (interner Fehler).')
|
|
|
|
const prevScroll = window.scrollY
|
|
window.scrollTo(0, 0)
|
|
await new Promise((r) => requestAnimationFrame(r))
|
|
await new Promise((r) => requestAnimationFrame(r))
|
|
await new Promise((r) => setTimeout(r, 320))
|
|
|
|
try {
|
|
const canvas = await html2canvas(el, {
|
|
scale,
|
|
useCORS: true,
|
|
allowTaint: true,
|
|
logging: false,
|
|
backgroundColor: '#ffffff',
|
|
ignoreElements: (node) => node?.getAttribute?.('data-dashboard-pdf-exclude') === 'true',
|
|
scrollX: 0,
|
|
scrollY: 0,
|
|
width: el.scrollWidth,
|
|
height: el.scrollHeight,
|
|
windowWidth: el.scrollWidth,
|
|
windowHeight: el.scrollHeight,
|
|
})
|
|
|
|
const imgData = canvas.toDataURL('image/png', 1.0)
|
|
const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4', compress: true })
|
|
const pageW = pdf.internal.pageSize.getWidth()
|
|
const pageH = pdf.internal.pageSize.getHeight()
|
|
const margin = 8
|
|
const innerW = pageW - 2 * margin
|
|
const innerH = pageH - 2 * margin
|
|
const imgW = innerW
|
|
const imgH = (canvas.height * imgW) / canvas.width
|
|
|
|
let position = margin
|
|
|
|
pdf.addImage(imgData, 'PNG', margin, position, imgW, imgH, undefined, 'FAST')
|
|
let heightLeft = imgH - innerH
|
|
|
|
while (heightLeft > 0) {
|
|
position = margin - (imgH - heightLeft)
|
|
pdf.addPage()
|
|
pdf.addImage(imgData, 'PNG', margin, position, imgW, imgH, undefined, 'FAST')
|
|
heightLeft -= innerH
|
|
}
|
|
|
|
const safe = String(filenameBase)
|
|
.replace(/[\\/:*?"<>|]+/g, '')
|
|
.trim()
|
|
pdf.save(`${safe || 'bericht'}.pdf`)
|
|
} finally {
|
|
window.scrollTo(0, prevScroll)
|
|
}
|
|
}
|