fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
68
server/documents/worker/pdf-converter.service.ts
Normal file
68
server/documents/worker/pdf-converter.service.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { chromium, type Browser, type Page } from 'playwright';
|
||||
|
||||
export interface PDFOptions {
|
||||
format?: string;
|
||||
landscape?: boolean;
|
||||
margin?: { top: number; right: number; bottom: number; left: number };
|
||||
printBackground?: boolean;
|
||||
headerTemplate?: string;
|
||||
footerTemplate?: string;
|
||||
}
|
||||
|
||||
export class PDFConverterService {
|
||||
private browser: Browser | null = null;
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
if (this.browser) return;
|
||||
|
||||
const launchOptions: Record<string, unknown> = {
|
||||
headless: true,
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
||||
};
|
||||
|
||||
if (process.env.PLAYWRIGHT_CHROMIUM_PATH) {
|
||||
launchOptions.executablePath = process.env.PLAYWRIGHT_CHROMIUM_PATH;
|
||||
}
|
||||
|
||||
this.browser = await chromium.launch(launchOptions);
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
if (this.browser) {
|
||||
await this.browser.close();
|
||||
this.browser = null;
|
||||
}
|
||||
}
|
||||
|
||||
async convert(html: string, options: PDFOptions = {}): Promise<Buffer> {
|
||||
await this.initialize();
|
||||
if (!this.browser) throw new Error('PDF converter not initialized');
|
||||
|
||||
const page: Page = await this.browser.newPage();
|
||||
try {
|
||||
await page.setContent(html, { waitUntil: 'networkidle' });
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const pdf = await page.pdf({
|
||||
format: options.format as any || 'A4',
|
||||
landscape: options.landscape || false,
|
||||
printBackground: options.printBackground !== false,
|
||||
margin: options.margin
|
||||
? {
|
||||
top: `${options.margin.top / 1440}in`,
|
||||
right: `${options.margin.right / 1440}in`,
|
||||
bottom: `${options.margin.bottom / 1440}in`,
|
||||
left: `${options.margin.left / 1440}in`,
|
||||
}
|
||||
: undefined,
|
||||
displayHeaderFooter: !!(options.headerTemplate || options.footerTemplate),
|
||||
headerTemplate: options.headerTemplate || '<div></div>',
|
||||
footerTemplate: options.footerTemplate || '<div></div>',
|
||||
});
|
||||
|
||||
return pdf;
|
||||
} finally {
|
||||
await page.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user