diff --git a/ReportEngine/renderers/html_renderer.py b/ReportEngine/renderers/html_renderer.py index 72198b1..b2a001e 100644 --- a/ReportEngine/renderers/html_renderer.py +++ b/ReportEngine/renderers/html_renderer.py @@ -2062,6 +2062,12 @@ body.exporting {{ margin: 0; font-size: 1rem; }} +.exporting *, +.exporting *::before, +.exporting *::after {{ + animation: none !important; + transition: none !important; +}} .export-progress {{ width: 220px; height: 6px; @@ -2121,6 +2127,10 @@ ul, ol {{ margin-left: 1.5em; padding-left: 0; }} +img, canvas, svg {{ + max-width: 100%; + height: auto; +}} .meta-card {{ background: rgba(0,0,0,0.02); border-radius: 12px; @@ -2344,21 +2354,38 @@ pre.code-block {{ }} .chapter > *, .hero-section, - .callout, - .chart-card, - .kpi-grid, - .table-wrap, - figure, - blockquote {{ - break-inside: avoid; - page-break-inside: avoid; - }} - .chapter h2, - .chapter h3, - .chapter h4 {{ - break-after: avoid; - page-break-after: avoid; - }} +.callout, +.chart-card, +.kpi-grid, +.table-wrap, +figure, +blockquote {{ + break-inside: avoid; + page-break-inside: avoid; +}} +.chapter h2, +.chapter h3, +.chapter h4 {{ + break-after: avoid; + page-break-after: avoid; + break-inside: avoid; +}} +.chart-card, +.table-wrap {{ + overflow: visible !important; +}} +.chart-card canvas {{ + width: 100% !important; + height: auto !important; +}} +.table-wrap table {{ + table-layout: fixed; + width: 100%; +}} +.table-wrap table th, +.table-wrap table td {{ + word-break: break-word; +}} }} """ @@ -2821,6 +2848,7 @@ function exportPdf() { exportBtn.disabled = true; } showExportOverlay('正在导出PDF,请稍候...'); + document.body.classList.add('exporting'); const pdf = new jspdf.jsPDF('p', 'mm', 'a4'); try { if (window.pdfFontData) { @@ -2832,14 +2860,25 @@ function exportPdf() { console.warn('Custom PDF font setup failed, fallback to default', err); } const pageWidth = pdf.internal.pageSize.getWidth(); - const pxWidth = Math.max(target.scrollWidth, document.documentElement.scrollWidth); + const pxWidth = Math.max( + target.scrollWidth, + document.documentElement.scrollWidth, + Math.round(pageWidth * 3.78) + ); const restoreButton = () => { if (exportBtn) { exportBtn.disabled = false; } + document.body.classList.remove('exporting'); }; let renderTask; try { + // force charts to rerender at full width before capture + chartRegistry.forEach(chart => { + if (chart && typeof chart.resize === 'function') { + chart.resize(); + } + }); renderTask = pdf.html(target, { x: 8, y: 12, @@ -2847,14 +2886,24 @@ function exportPdf() { margin: [12, 12, 20, 12], autoPaging: 'text', windowWidth: pxWidth, + html2canvas: { + scale: Math.min(1.2, Math.max(0.8, pageWidth / (target.clientWidth || pageWidth))), + useCORS: true, + scrollX: 0, + scrollY: -window.scrollY, + logging: false + }, pagebreak: { mode: ['css', 'legacy'], - avoid: ['.chapter > *', '.callout', '.chart-card', '.table-wrap', '.kpi-grid', '.hero-section'] - }, - html2canvas: { - scale: 0.72, - useCORS: true, - logging: false + avoid: [ + '.chapter > *', + '.callout', + '.chart-card', + '.table-wrap', + '.kpi-grid', + '.hero-section' + ], + before: '.chapter-divider' }, callback: (doc) => doc.save('report.pdf') });