fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 34s

This commit is contained in:
2026-03-12 13:20:06 -04:00
parent 6799cdf954
commit 39108e56ae
5 changed files with 60 additions and 6 deletions

Binary file not shown.

View File

@@ -5,6 +5,7 @@ const path = require("path");
const moment = require("moment-timezone");
const archiver = require("archiver");
const { PDFDocument } = require("pdf-lib");
const fontkit = require("@pdf-lib/fontkit");
const Report = db.report;
const RoutePath = db.route_path;
const Employee = db.employee;
@@ -44,6 +45,26 @@ const findTemplatePathBySite = (site) => {
return candidatePaths.find((candidate) => fs.existsSync(candidate)) || "";
};
const findUnicodeFontPath = (site) => {
const safeSite = [1, 2, 3].includes(Number(site)) ? Number(site) : 1;
const fileName = "NotoSansCJKsc-Regular.otf";
const cwd = process.cwd();
const candidatePaths = [
path.join(ROOT_DIR, "app", "assets", "fonts", fileName),
path.join(ROOT_DIR, "app", "views", "upload", fileName),
path.join(ROOT_DIR, "client", "build", "upload", fileName),
path.join(ROOT_DIR, "client", "public", "upload", fileName),
path.join(cwd, "app", "assets", "fonts", fileName),
path.join(cwd, "app", "views", "upload", fileName),
path.join(cwd, "client", "build", "upload", fileName),
path.join(cwd, "client", "public", "upload", fileName),
path.join("/www/wwwroot/upload", fileName),
path.join(`/www/wwwroot/worldshine${safeSite}`, "app", "assets", "fonts", fileName),
path.join(`/www/wwwroot/worldshine${safeSite}-tspt`, "app", "assets", "fonts", fileName)
];
return candidatePaths.find((candidate) => fs.existsSync(candidate)) || "";
};
const formatUtcToLocalHm = (dateLike) => {
if (!dateLike) return "";
const parsed = moment.utc(dateLike);
@@ -74,8 +95,10 @@ const findOutboundStatusByCustomerId = (outboundCustomerStatuses, customerId) =>
return outboundCustomerStatuses.find((item) => toObjectIdText(item?.customer_id) === targetId) || {};
};
const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, vehiclesMap, outboundCustomerStatuses) => {
const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, vehiclesMap, outboundCustomerStatuses, unicodeFontBytes) => {
const pdfDoc = await PDFDocument.load(templateBytes);
pdfDoc.registerFontkit(fontkit);
const unicodeFont = await pdfDoc.embedFont(unicodeFontBytes, { subset: true });
const form = pdfDoc.getForm();
const routeName = route?.name || "";
const scheduleDate = route?.schedule_date || "";
@@ -107,11 +130,11 @@ const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, veh
const enterCenterTime = formatUtcToLocalHm(customer?.customer_enter_center_time);
if (enterCenterTime) {
safeSetField(form, `arrive_${row}`, enterCenterTime);
safeSetField(form, `y_${row}`, "Y");
safeSetField(form, `y_${row}`, "");
} else if (customer?.customer_route_status === "inCenter") {
safeSetField(form, `y_${row}`, "Y");
safeSetField(form, `y_${row}`, "");
} else {
safeSetField(form, `n_${row}`, "N");
safeSetField(form, `n_${row}`, "");
}
const outboundStatus = findOutboundStatusByCustomerId(outboundCustomerStatuses, customer?.customer_id);
@@ -121,6 +144,8 @@ const buildRoutePdfBuffer = async (templateBytes, route, seqNum, driversMap, veh
if (dropoffTime) safeSetField(form, `drop_${row}`, dropoffTime);
});
// Rebuild form appearances with a Unicode font so UTF-8 (e.g., Chinese) renders correctly.
form.updateFieldAppearances(unicodeFont);
form.flatten();
return pdfDoc.save();
};
@@ -248,9 +273,13 @@ exports.exportRouteReportZip = async (req, res) => {
const site = splitSite.findSiteNumber(req);
const templatePath = findTemplatePathBySite(site);
const unicodeFontPath = findUnicodeFontPath(site);
if (!templatePath) {
return res.status(500).send({ message: `Missing PDF template for site ${site}.` });
}
if (!unicodeFontPath) {
return res.status(500).send({ message: "Missing Unicode font file: NotoSansCJKsc-Regular.otf" });
}
const [routes, drivers, vehicles] = await Promise.all([
RoutePath.find(splitSite.splitSiteGet(req, { schedule_date: date, status: { $ne: "disabled" } })),
@@ -278,6 +307,7 @@ exports.exportRouteReportZip = async (req, res) => {
])
);
const templateBytes = fs.readFileSync(templatePath);
const unicodeFontBytes = fs.readFileSync(unicodeFontPath);
const filenameDate = (date || "").replace(/\//g, "-");
const zipName = `route_report_${filenameDate || "date"}.zip`;
@@ -303,7 +333,8 @@ exports.exportRouteReportZip = async (req, res) => {
i + 1,
driversMap,
vehiclesMap,
outboundCustomerStatuses
outboundCustomerStatuses,
unicodeFontBytes
);
const base = sanitizeFileName(route?.name || `route_${i + 1}`) || `route_${i + 1}`;
const existingCount = filenameCounter.get(base) || 0;

View File

@@ -5,6 +5,8 @@ const rootDir = path.resolve(__dirname, "..");
const sourceDir = path.join(rootDir, "public", "upload");
const targetDir = path.join(rootDir, "build", "upload");
const templates = ["pdf_templete1.pdf", "pdf_templete2.pdf", "pdf_templete3.pdf"];
const unicodeFontFile = "NotoSansCJKsc-Regular.otf";
const appFontSourcePath = path.join(rootDir, "..", "app", "assets", "fonts", unicodeFontFile);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
@@ -19,4 +21,8 @@ templates.forEach((templateName) => {
fs.copyFileSync(sourcePath, targetPath);
});
console.log("Route report PDF templates copied to build/upload.");
if (fs.existsSync(appFontSourcePath)) {
fs.copyFileSync(appFontSourcePath, path.join(targetDir, unicodeFontFile));
}
console.log("Route report PDF templates and Unicode font copied to build/upload.");

16
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@pdf-lib/fontkit": "^1.1.1",
"archiver": "^7.0.1",
"axios": "^0.27.2",
"bcryptjs": "^2.4.3",
@@ -733,6 +734,21 @@
"sparse-bitfield": "^3.0.3"
}
},
"node_modules/@pdf-lib/fontkit": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pdf-lib/fontkit/-/fontkit-1.1.1.tgz",
"integrity": "sha512-KjMd7grNapIWS/Dm0gvfHEilSyAmeLvrEGVcqLGi0VYebuqqzTbgF29efCx7tvx+IEbG3zQciRSWl3GkUSvjZg==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.6"
}
},
"node_modules/@pdf-lib/fontkit/node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/@pdf-lib/standard-fonts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",

View File

@@ -16,6 +16,7 @@
"author": "yangli",
"license": "ISC",
"dependencies": {
"@pdf-lib/fontkit": "^1.1.1",
"archiver": "^7.0.1",
"axios": "^0.27.2",
"bcryptjs": "^2.4.3",