validate-health-template.mjs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import fs from "fs";
  2. import PizZip from "pizzip";
  3. import Docxtemplater from "docxtemplater";
  4. import ImageModule from "docxtemplater-image-module-free";
  5. import {
  6. HEALTH_IMAGE_MARKERS,
  7. patchTemplateXml,
  8. } from "../src/server/reportService/docxReportBuilder.js";
  9. const zip = new PizZip(fs.readFileSync("templates/health-report-template.docx"));
  10. let xml = zip.file("word/document.xml").asText();
  11. console.log(
  12. "p open/close",
  13. (xml.match(/<w:p(?:\s|>)/g) || []).length,
  14. (xml.match(/<\/w:p>/g) || []).length,
  15. );
  16. const wt = [];
  17. xml.replace(/<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>/g, (_, t) => {
  18. wt.push(t);
  19. return _;
  20. });
  21. const bad = wt.filter(
  22. (t) => (t.match(/{/g) || []).length !== (t.match(/}/g) || []).length,
  23. );
  24. console.log("unbalanced w:t", bad.length);
  25. bad.slice(0, 10).forEach((t) => console.log(JSON.stringify(t.slice(0, 120))));
  26. xml = patchTemplateXml(xml, HEALTH_IMAGE_MARKERS);
  27. zip.file("word/document.xml", xml);
  28. const empty = Buffer.from(
  29. "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
  30. "base64",
  31. );
  32. const imageModule = new ImageModule({
  33. centered: true,
  34. getImage: () => empty,
  35. getSize: () => [100, 60],
  36. });
  37. const doc = new Docxtemplater(zip, {
  38. paragraphLoop: true,
  39. linebreaks: true,
  40. modules: [imageModule],
  41. nullGetter: () => "",
  42. });
  43. doc.render({
  44. farm_name: "测试",
  45. field_id: "F1",
  46. create_time: "t",
  47. source_datetime: "2026-09-01",
  48. eval_start_date: "2026-08-03",
  49. eval_end_date: "2026-09-01",
  50. eval_date_range: "2026-08-03至2026-09-01(滚动30天)",
  51. turbine_count: "1",
  52. valid_turbine_count: "1",
  53. turbine_types: "x",
  54. overall_score: "80",
  55. system_score: "70",
  56. component_score: "70",
  57. "structure_score/未评估": "70",
  58. excellent_count: "1",
  59. good_count: "0",
  60. fair_count: "0",
  61. poor_count: "0",
  62. overall_level_text: "良",
  63. main_level: "良",
  64. level_distribution_text: "x",
  65. overall_summary_text: "x",
  66. focus_engine_list: "A",
  67. chart_fig1: "a",
  68. chart_fig2: "b",
  69. turbine_rows: [
  70. {
  71. index: 1,
  72. engine_name: "A1",
  73. machine_type: "T",
  74. overall: "80",
  75. level: "良",
  76. system: "70",
  77. component: "70",
  78. structure: "70",
  79. yaw: "1",
  80. pitch: "1",
  81. mcs: "1",
  82. hpu: "1",
  83. generator: "1",
  84. converter: "1",
  85. gearbox: "1",
  86. shaft: "1",
  87. rotor: "1",
  88. tower: "1",
  89. },
  90. ],
  91. focus_rows: [
  92. {
  93. index: 1,
  94. engine_name: "A1",
  95. machine_type: "T",
  96. overall: "80",
  97. level: "中",
  98. system: "70",
  99. component: "70",
  100. structure: "70",
  101. low_item: "系统健康",
  102. },
  103. ],
  104. turbine_trends: [
  105. {
  106. engine_title: "A1 趋势",
  107. charts: [
  108. { chart_title: "综合健康评分趋势图", trend_image: "a" },
  109. { chart_title: "结构健康趋势图", trend_image: "a" },
  110. ],
  111. },
  112. ],
  113. });
  114. console.log("docxtemplater compile+render ok");