From 55737ce47e5758c103c8b35131db1d182ce8f708 Mon Sep 17 00:00:00 2001 From: Lixian Zhou Date: Thu, 12 Mar 2026 14:28:33 -0400 Subject: [PATCH] fix --- app/controllers/report.controller.js | 49 +++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/app/controllers/report.controller.js b/app/controllers/report.controller.js index da6601b..1372f2b 100644 --- a/app/controllers/report.controller.js +++ b/app/controllers/report.controller.js @@ -5,7 +5,7 @@ const path = require("path"); const crypto = require("crypto"); const moment = require("moment-timezone"); const archiver = require("archiver"); -const { PDFDocument } = require("pdf-lib"); +const { PDFDocument, rgb } = require("pdf-lib"); const fontkit = require("@pdf-lib/fontkit"); const Report = db.report; const RoutePath = db.route_path; @@ -162,6 +162,24 @@ const hasEnterCenterTimeByCandidate = (...candidates) => const hasInCenterStatusByCandidate = (...candidates) => candidates.some((item) => (item?.customer_route_status || "").toString() === "inCenter"); +const drawCenteredMarkInField = (pdfDoc, form, fieldName, mark, font) => { + if (!mark) return; + try { + const field = form.getTextField(fieldName); + const widgets = field?.acroField?.getWidgets?.() || []; + if (!widgets.length) return; + const page = pdfDoc.getPage(0); + widgets.forEach((widget) => { + const rect = widget.getRectangle(); + const fontSize = Math.min(Math.max(rect.height * 0.75, 10), 16); + const markWidth = font.widthOfTextAtSize(mark, fontSize); + const x = rect.x + Math.max((rect.width - markWidth) / 2, 1); + const y = rect.y + Math.max((rect.height - fontSize) / 2, 1); + page.drawText(mark, { x, y, size: fontSize, font, color: rgb(0, 0, 0) }); + }); + } catch (_err) {} +}; + const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, vehiclesMap, outboundCustomerStatuses, unicodeFontBytes, allRoutes) => { const pdfDoc = await PDFDocument.load(templateBytes); pdfDoc.registerFontkit(fontkit); @@ -210,14 +228,17 @@ const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, veh if (enterCenterTime) { safeSetField(form, `arrive_${row}`, enterCenterTime); } - safeSetField(form, `y_${row}`, "✓", { fontSize: 11 }); + safeSetField(form, `y_${row}`, ""); safeSetField(form, `n_${row}`, "", { fontSize: 11 }); + drawCenteredMarkInField(pdfDoc, form, `y_${row}`, "✓", unicodeFont); } else if (hasInCenterStatusByCandidate(customer, relativeRouteCustomer, customerInOtherRoute)) { - safeSetField(form, `y_${row}`, "✓", { fontSize: 11 }); + safeSetField(form, `y_${row}`, ""); safeSetField(form, `n_${row}`, "", { fontSize: 11 }); + drawCenteredMarkInField(pdfDoc, form, `y_${row}`, "✓", unicodeFont); } else { safeSetField(form, `y_${row}`, "", { fontSize: 11 }); - safeSetField(form, `n_${row}`, "✕", { fontSize: 11 }); + safeSetField(form, `n_${row}`, "", { fontSize: 11 }); + drawCenteredMarkInField(pdfDoc, form, `n_${row}`, "✕", unicodeFont); } const outboundStatus = findOutboundStatusByCustomerId(outboundCustomerStatuses, customer?.customer_id); @@ -370,7 +391,6 @@ exports.exportRouteReportZip = async (req, res) => { Vehicle.find(splitSite.splitSiteGet(req, { status: "active" })) ]); - const inboundRoutes = (routes || []).filter((route) => route?.type === "inbound"); const outboundRoutes = (routes || []).filter((route) => route?.type === "outbound"); const outboundCustomerStatuses = outboundRoutes.reduce((acc, route) => { const list = Array.isArray(route?.route_customer_list) ? route.route_customer_list : []; @@ -389,6 +409,25 @@ exports.exportRouteReportZip = async (req, res) => { vehicle ]) ); + const getRouteVehicleNumber = (route) => { + const vehicleId = toObjectIdText(route?.vehicle); + const vehicleNumberRaw = vehiclesMap.get(vehicleId)?.vehicle_number; + if (vehicleNumberRaw === undefined || vehicleNumberRaw === null || vehicleNumberRaw === "") { + return Number.MAX_SAFE_INTEGER; + } + const numeric = Number(vehicleNumberRaw); + if (!Number.isNaN(numeric)) return numeric; + return Number.MAX_SAFE_INTEGER; + }; + + const inboundRoutes = (routes || []) + .filter((route) => route?.type === "inbound") + .sort((a, b) => { + const numberA = getRouteVehicleNumber(a); + const numberB = getRouteVehicleNumber(b); + if (numberA !== numberB) return numberA - numberB; + return (a?.name || "").localeCompare(b?.name || ""); + }); const templateBytes = fs.readFileSync(templatePath); const unicodeFontBytes = fs.readFileSync(unicodeFontPath);