fix: 问题修复
1. 编辑新增药品的信息同步his; 2. pdf调整(主要是压缩生成的pdf文件)
This commit is contained in:
parent
f1c1812516
commit
552dc546be
@ -286,6 +286,9 @@ async function addHlwDrugInfo(ctx) {
|
||||
}
|
||||
newDrug.createTime = Date.now();
|
||||
const res = await db.collection("drug-info").insertOne(newDrug);
|
||||
if (res && res.insertedId) {
|
||||
updateHisDrugInfo({ id: res.insertedId.toString() })
|
||||
}
|
||||
return { success: true, message: "新增药品成功", id: res.insertedId }
|
||||
} catch (e) {
|
||||
return { success: false, message: e.message || '新增药品失败' }
|
||||
@ -337,6 +340,7 @@ async function editHlwDrugInfo(ctx) {
|
||||
if (res.matchedCount === 0) {
|
||||
return { success: false, message: "未找到对应药品" }
|
||||
}
|
||||
updateHisDrugInfo({ id })
|
||||
return { success: true, message: "更新成功" }
|
||||
}
|
||||
return { success: true, message: "更新成功" }
|
||||
|
||||
@ -12,9 +12,15 @@ let browserPromise;
|
||||
let activeJobs = 0;
|
||||
const waiters = [];
|
||||
const cachedPdfJobs = new Map();
|
||||
const PDF_TEMPLATE_VERSION = "v7";
|
||||
const PDF_TEMPLATE_VERSION = "v11";
|
||||
const MAX_SIGNATURE_IMAGE_BYTES = 1024 * 1024;
|
||||
const SIGNATURE_DOWNLOAD_TIMEOUT_MS = 5000;
|
||||
const MAX_PRESCRIPTION_PDF_BYTES = 100 * 1024;
|
||||
const RASTER_PAGE_SIZES = {
|
||||
// A5 (148mm) 减去左右 8mm 页边距后的实际打印宽度为 132mm。
|
||||
A5: { viewport: { width: 500, height: 733, deviceScaleFactor: 1 }, contentWidth: "132mm", contentHeight: "194mm" },
|
||||
A4: { viewport: { width: 733, height: 1062, deviceScaleFactor: 1 }, contentWidth: "194mm", contentHeight: "281mm" },
|
||||
};
|
||||
const PRESCRIPTION_SEAL_IMAGE_URL = process.env.CONFIG_PRESCRIPTION_SEAL_IMAGE_URL
|
||||
|| "https://hlwyy.hnkhhospital.com/upload-files/other/stamp.png";
|
||||
|
||||
@ -96,7 +102,7 @@ async function getBrowser() {
|
||||
browserPromise = puppeteer.launch({
|
||||
executablePath: getExecutablePath(),
|
||||
headless: true,
|
||||
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"],
|
||||
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu"],
|
||||
});
|
||||
const browser = await browserPromise;
|
||||
browser.on("disconnected", () => {
|
||||
@ -273,12 +279,12 @@ function buildPrescriptionHtml(record, paperSize = "A5", signatureImages = {}) {
|
||||
<style>
|
||||
@page { size: ${size} portrait; margin: 8mm; }
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; color: #111; font-family: "Noto Sans CJK SC", "Noto Sans SC", SimSun, "Songti SC", serif; font-size: 14px; }
|
||||
html, body { margin: 0; padding: 0; color: #111; background: #fff; font-family: "Noto Sans CJK SC", "Noto Sans SC", SimSun, "Songti SC", serif; font-size: 14px; }
|
||||
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
||||
.prescription { min-height: ${size === "A5" ? "194mm" : "281mm"}; display: flex; flex-direction: column; line-height: 1.28; overflow: hidden; }
|
||||
.prescription { width: calc(100% - 1px); min-height: ${size === "A5" ? "194mm" : "281mm"}; display: flex; flex-direction: column; line-height: 1.28; overflow: hidden; }
|
||||
.header { position: relative; border-bottom: 1px solid #111; padding: 3px 0 4px; }
|
||||
.title { font-weight: 700; font-size: 17px; text-align: center; line-height: 1.4; }
|
||||
.rx-type { position: absolute; top: 0; right: 0; width: 40px; border: 1px solid #333; text-align: center; color: #666; font-size: 12px; line-height: 1.3; }
|
||||
.rx-type { position: absolute; top: 0; right: 1px; width: 40px; border: 1px solid #333; text-align: center; color: #666; font-size: 12px; line-height: 1.3; }
|
||||
.rx-number { margin-top: 5px; }
|
||||
.patient-info { padding-top: 5px; }
|
||||
.info-row { display: flex; padding: 2px; }
|
||||
@ -323,30 +329,66 @@ function buildPrescriptionHtml(record, paperSize = "A5", signatureImages = {}) {
|
||||
</body></html>`;
|
||||
}
|
||||
|
||||
function buildRasterPdfHtml(image, paperSize) {
|
||||
const size = RASTER_PAGE_SIZES[paperSize];
|
||||
return `<!doctype html><html><head><meta charset="utf-8" /><style>
|
||||
@page { size: ${paperSize} portrait; margin: 8mm; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
img { display: block; width: ${size.contentWidth}; height: ${size.contentHeight}; }
|
||||
</style></head><body><img src="${image}" alt="处方笺" /></body></html>`;
|
||||
}
|
||||
|
||||
async function generateCompactPrescriptionPdf(html, paperSize) {
|
||||
// Chrome 会为中文文本嵌入字体子集;即使没有图片,单页也约 280KB。
|
||||
// 将实际打印区域以 96dpi 截图并转为 JPEG,可保留处方可读性且避免字体嵌入。
|
||||
const browser = await getBrowser();
|
||||
const size = RASTER_PAGE_SIZES[paperSize];
|
||||
const rasterPage = await browser.newPage();
|
||||
try {
|
||||
await rasterPage.setViewport(size.viewport);
|
||||
await rasterPage.setContent(html, { waitUntil: "load" });
|
||||
await rasterPage.evaluate(() => document.fonts && document.fonts.ready);
|
||||
const screenshot = await rasterPage.screenshot({
|
||||
type: "jpeg",
|
||||
quality: 72,
|
||||
clip: { x: 0, y: 0, width: size.viewport.width, height: size.viewport.height },
|
||||
});
|
||||
const compactPage = await browser.newPage();
|
||||
try {
|
||||
await compactPage.setContent(
|
||||
buildRasterPdfHtml(`data:image/jpeg;base64,${Buffer.from(screenshot).toString("base64")}`, paperSize),
|
||||
{ waitUntil: "load" }
|
||||
);
|
||||
const pdf = Buffer.from(await compactPage.pdf({
|
||||
format: paperSize,
|
||||
preferCSSPageSize: true,
|
||||
printBackground: true,
|
||||
margin: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||
}));
|
||||
if (pdf.length > MAX_PRESCRIPTION_PDF_BYTES) {
|
||||
throw new Error(`处方 PDF 压缩后仍超过 ${MAX_PRESCRIPTION_PDF_BYTES} 字节`);
|
||||
}
|
||||
return pdf;
|
||||
} finally {
|
||||
await compactPage.close().catch(() => {});
|
||||
}
|
||||
} finally {
|
||||
await rasterPage.close().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
async function generatePrescriptionPdf(record, options = {}) {
|
||||
await acquireSlot();
|
||||
let page;
|
||||
try {
|
||||
const browser = await getBrowser();
|
||||
page = await browser.newPage();
|
||||
const [doctor, pharmacist, seal] = await Promise.all([
|
||||
loadSignatureDataImage(record.doctorSignImg),
|
||||
loadSignatureDataImage(record.pharmacistSignImg),
|
||||
loadSignatureDataImage(PRESCRIPTION_SEAL_IMAGE_URL),
|
||||
]);
|
||||
await page.setContent(
|
||||
buildPrescriptionHtml(record, options.paperSize, { doctor, pharmacist, seal }),
|
||||
{ waitUntil: "load" }
|
||||
);
|
||||
await page.evaluate(() => document.fonts && document.fonts.ready);
|
||||
return Buffer.from(await page.pdf({
|
||||
format: options.paperSize === "A4" ? "A4" : "A5",
|
||||
preferCSSPageSize: true,
|
||||
printBackground: true,
|
||||
margin: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||
}));
|
||||
const html = buildPrescriptionHtml(record, options.paperSize, { doctor, pharmacist, seal });
|
||||
const paperSize = options.paperSize === "A4" ? "A4" : "A5";
|
||||
return generateCompactPrescriptionPdf(html, paperSize);
|
||||
} finally {
|
||||
if (page) await page.close().catch(() => {});
|
||||
releaseSlot();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user