import type { jsPDFOptions } from 'jspdf';
|
|
import html2canvas from '@wtto00/html2canvas';
|
import { jsPDF as JsPdf } from 'jspdf';
|
|
export interface LabelPdfOptions {
|
fileName: string;
|
html: string;
|
paperHeight: number;
|
paperWidth: number;
|
}
|
|
interface LabelPdfDependencies {
|
createCanvas: typeof html2canvas;
|
createPdf: (options: jsPDFOptions) => Pick<JsPdf, 'addImage' | 'addPage' | 'save'>;
|
}
|
|
const defaultDependencies: LabelPdfDependencies = {
|
createCanvas: html2canvas,
|
createPdf: (options) => new JsPdf(options),
|
};
|
|
function waitForImage(image: HTMLImageElement) {
|
if (image.complete) return Promise.resolve();
|
return new Promise<void>((resolve) => {
|
image.addEventListener('load', () => resolve(), { once: true });
|
image.addEventListener('error', () => resolve(), { once: true });
|
});
|
}
|
|
async function waitForAssets(container: HTMLElement) {
|
const fonts = (document as Document & { fonts?: { ready?: Promise<unknown> } }).fonts;
|
await Promise.all([fonts?.ready, ...[...container.querySelectorAll('img')].map((image) => waitForImage(image))].filter(Boolean));
|
}
|
|
export async function exportLabelLayoutPdf(options: LabelPdfOptions, dependencies: LabelPdfDependencies = defaultDependencies) {
|
const { fileName, html, paperHeight, paperWidth } = options;
|
if (!html.trim()) throw new Error('标签拼版内容为空,无法导出 PDF');
|
if (!(paperWidth > 0) || !(paperHeight > 0)) throw new Error('PDF 纸张宽高必须大于 0');
|
|
const staging = document.createElement('div');
|
staging.setAttribute('aria-hidden', 'true');
|
staging.style.cssText = 'position:fixed;left:-100000px;top:0;background:#fff;pointer-events:none;';
|
staging.innerHTML = html;
|
document.body.append(staging);
|
|
try {
|
const sheets = [...staging.querySelectorAll<HTMLElement>('.jnpf-label-sheet')];
|
if (!sheets.length) throw new Error('未找到可导出的标签页面');
|
await waitForAssets(staging);
|
|
const pdf = dependencies.createPdf({
|
format: [paperWidth, paperHeight],
|
orientation: paperWidth > paperHeight ? 'landscape' : 'portrait',
|
unit: 'mm',
|
});
|
for (const [index, sheet] of sheets.entries()) {
|
if (index > 0) pdf.addPage([paperWidth, paperHeight], paperWidth > paperHeight ? 'landscape' : 'portrait');
|
const canvas = await dependencies.createCanvas(sheet, {
|
backgroundColor: '#fff',
|
logging: false,
|
scale: 2,
|
useCORS: true,
|
});
|
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, 0, paperWidth, paperHeight, undefined, 'FAST');
|
}
|
pdf.save(`${fileName}.pdf`);
|
} finally {
|
staging.remove();
|
}
|
}
|