/** * 将健康/异常报告模板写入 templates/ * 用法:node scripts/prepareReportTemplates.mjs */ import path from "path"; import fs from "fs"; import { fileURLToPath } from "url"; import PizZip from "pizzip"; import { HEALTH_IMAGE_MARKERS, applyHealthTemplateXmlPatches, patchAnomalyTemplateXml, patchTemplateXml, removeAllFooters, } from "../src/server/reportService/docxReportBuilder.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.join(__dirname, ".."); const templatesDir = path.join(root, "templates"); const publicHealthCandidates = [ path.join( root, "src", "public", "file", "风电机组健康评估_风场级自动报告模板_V3.0(2).docx", ), path.join( root, "src", "public", "file", "风电机组健康评估_风场级自动报告模板_V2.0.docx", ), path.join( root, "..", "public", "files", "风电机组健康评估_风场级自动报告模板_V1.0.docx", ), ]; const publicHealth = publicHealthCandidates.find((item) => fs.existsSync(item)); const publicAnomalyCandidates = [ path.join( root, "src", "public", "file", "异常检测数据分析报告模板(大唐版)_修订版_人工对齐版_业务化.docx", ), path.join( root, "src", "public", "file", "异常检测数据分析报告模板(大唐版)_修订版_人工对齐版.docx", ), path.join( root, "src", "public", "file", "异常检测数据分析报告模板(大唐版).docx", ), ]; const publicAnomaly = publicAnomalyCandidates.find((item) => fs.existsSync(item), ); function writeTemplate(zip, targetName) { fs.mkdirSync(templatesDir, { recursive: true }); const outPath = path.join(templatesDir, targetName); if (fs.existsSync(outPath)) { try { fs.chmodSync(outPath, 0o644); } catch (_e) { // ignore } fs.unlinkSync(outPath); } fs.writeFileSync(outPath, zip.generate({ type: "nodebuffer" }), { mode: 0o644, }); return outPath; } function patchAndWrite(sourcePath, targetName, patchFn) { if (!fs.existsSync(sourcePath)) { throw new Error(`源模板不存在: ${sourcePath}`); } const content = fs.readFileSync(sourcePath, "binary"); const zip = new PizZip(content); const documentFile = zip.file("word/document.xml"); if (!documentFile) throw new Error("模板缺少 word/document.xml"); if (targetName === "health-report-template.docx") { applyHealthTemplateXmlPatches(zip); } else { zip.file("word/document.xml", patchFn(documentFile.asText())); } removeAllFooters(zip); return writeTemplate(zip, targetName); } fs.mkdirSync(templatesDir, { recursive: true }); if (fs.existsSync(publicHealth)) { const healthOut = patchAndWrite( publicHealth, "health-report-template.docx", (xml) => patchTemplateXml(xml, HEALTH_IMAGE_MARKERS), ); console.log("健康模板已写入并插入图片占位:", healthOut, "源:", publicHealth); } else { console.warn("未找到健康模板,跳过:", publicHealthCandidates.join(" | ")); } if (publicAnomaly) { const anomalyOut = patchAndWrite( publicAnomaly, "异常检测数据分析报告模板(大唐版)_修订版_人工对齐版.docx", (xml) => patchAnomalyTemplateXml(xml), ); patchAndWrite(publicAnomaly, "anomaly-report-template.docx", (xml) => patchAnomalyTemplateXml(xml), ); console.log("异常模板已写入并补齐 image 占位:", anomalyOut); } else { console.warn("未找到异常模板,跳过:", publicAnomalyCandidates.join(" | ")); } console.log("完成。重启 downLoadServer 后即可生成报告。");