- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
129 lines
4.2 KiB
TypeScript
129 lines
4.2 KiB
TypeScript
export interface PDFOptions {
|
|
format?: string;
|
|
landscape?: boolean;
|
|
margin?: { top: number; right: number; bottom: number; left: number };
|
|
printBackground?: boolean;
|
|
headerTemplate?: string;
|
|
footerTemplate?: string;
|
|
}
|
|
|
|
const DOC_WORKER_URL = (process.env.DOC_WORKER_URL || "http://document-worker:3000").replace(/\/+$/, "");
|
|
|
|
function getTimeout(): number {
|
|
const env = process.env.DOC_WORKER_TIMEOUT_MS;
|
|
return env ? parseInt(env, 10) : 30000;
|
|
}
|
|
|
|
/**
|
|
* Конвертирует HTML в PDF через внешний document-worker сервис.
|
|
* Возвращает Buffer или null при ошибке.
|
|
*/
|
|
export async function convertHtmlToPdf(html: string, options: PDFOptions = {}): Promise<Buffer | null> {
|
|
try {
|
|
const response = await fetch(`${DOC_WORKER_URL}/convert/pdf`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ html, options }),
|
|
signal: AbortSignal.timeout(getTimeout()),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text().catch(() => "");
|
|
console.error("[doc-worker] PDF conversion HTTP error:", response.status, text);
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data.success || !data.pdf) {
|
|
console.error("[doc-worker] PDF conversion failed:", data.error || "unknown");
|
|
return null;
|
|
}
|
|
|
|
return Buffer.from(data.pdf, "base64");
|
|
} catch (err) {
|
|
console.error("[doc-worker] PDF conversion request failed:", err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Конвертирует DOCX (Buffer) в PDF через внешний document-worker сервис.
|
|
* Возвращает Buffer или null при ошибке.
|
|
*/
|
|
export async function convertDocxToPdf(docxBuffer: Buffer): Promise<Buffer | null> {
|
|
try {
|
|
const response = await fetch(`${DOC_WORKER_URL}/convert/docx-to-pdf`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ docxBase64: docxBuffer.toString("base64") }),
|
|
signal: AbortSignal.timeout(getTimeout()),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text().catch(() => "");
|
|
console.error("[doc-worker] DOCX→PDF conversion HTTP error:", response.status, text);
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data.success || !data.pdf) {
|
|
console.error("[doc-worker] DOCX→PDF conversion failed:", data.error || "unknown");
|
|
return null;
|
|
}
|
|
|
|
return Buffer.from(data.pdf, "base64");
|
|
} catch (err) {
|
|
console.error("[doc-worker] DOCX→PDF conversion request failed:", err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Конвертирует EMF/WMF (Buffer) в PNG через внешний document-worker сервис.
|
|
* Возвращает Buffer или null при ошибке.
|
|
*/
|
|
export async function convertEmfToPng(emfBuffer: Buffer): Promise<Buffer | null> {
|
|
try {
|
|
const response = await fetch(`${DOC_WORKER_URL}/convert/emf-to-png`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ emfBase64: emfBuffer.toString("base64") }),
|
|
signal: AbortSignal.timeout(getTimeout()),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text().catch(() => "");
|
|
console.error("[doc-worker] EMF→PNG conversion HTTP error:", response.status, text);
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data.success || !data.png) {
|
|
console.error("[doc-worker] EMF→PNG conversion failed:", data.error || "unknown");
|
|
return null;
|
|
}
|
|
|
|
return Buffer.from(data.png, "base64");
|
|
} catch (err) {
|
|
console.error("[doc-worker] EMF→PNG conversion request failed:", err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Проверяет доступность document-worker сервиса.
|
|
*/
|
|
export async function checkDocumentWorkerHealth(): Promise<{ ok: boolean; error?: string }> {
|
|
try {
|
|
const response = await fetch(`${DOC_WORKER_URL}/health`, {
|
|
signal: AbortSignal.timeout(5000),
|
|
});
|
|
if (!response.ok) {
|
|
return { ok: false, error: `HTTP ${response.status}` };
|
|
}
|
|
return { ok: true };
|
|
} catch (err) {
|
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
}
|
|
}
|