generate-envspec.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. const fs = require("fs");
  2. const path = require("path");
  3. const {
  4. Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
  5. Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType,
  6. ShadingType, PageNumber, PageBreak,
  7. } = require("docx");
  8. const OUTPUT = path.join(__dirname, "验收环境说明.docx");
  9. const A4_WIDTH = 11906;
  10. const A4_HEIGHT = 16838;
  11. const MARGIN = 1440;
  12. const CONTENT_WIDTH = A4_WIDTH - 2 * MARGIN;
  13. const border = { style: BorderStyle.SINGLE, size: 1, color: "999999" };
  14. const borders = { top: border, bottom: border, left: border, right: border };
  15. const cellMargins = { top: 60, bottom: 60, left: 100, right: 100 };
  16. function makeTable(rows, colWidths) {
  17. if (!colWidths) {
  18. const colCount = rows[0].length;
  19. const cw = Math.floor(CONTENT_WIDTH / colCount);
  20. colWidths = Array(colCount).fill(cw);
  21. colWidths[colCount - 1] = CONTENT_WIDTH - cw * (colCount - 1);
  22. }
  23. return new Table({
  24. width: { size: CONTENT_WIDTH, type: WidthType.DXA },
  25. columnWidths: colWidths,
  26. rows: rows.map((row, rowIdx) =>
  27. new TableRow({
  28. children: row.map((cell, colIdx) =>
  29. new TableCell({
  30. borders,
  31. width: { size: colWidths[colIdx], type: WidthType.DXA },
  32. margins: cellMargins,
  33. ...(rowIdx === 0 ? { shading: { fill: "D5E8F0", type: ShadingType.CLEAR } } : {}),
  34. children: [
  35. new Paragraph({
  36. children: [
  37. new TextRun({
  38. text: cell.replace(/\*\*/g, ""),
  39. font: "SimSun",
  40. size: 22,
  41. bold: rowIdx === 0,
  42. }),
  43. ],
  44. spacing: { line: 300 },
  45. }),
  46. ],
  47. })
  48. ),
  49. })
  50. ),
  51. });
  52. }
  53. const doc = new Document({
  54. styles: {
  55. default: { document: { run: { font: "SimSun", size: 24 } } },
  56. paragraphStyles: [
  57. {
  58. id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
  59. run: { size: 44, bold: true, font: "SimHei" },
  60. paragraph: { spacing: { before: 360, after: 240 }, outlineLevel: 0 },
  61. },
  62. {
  63. id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
  64. run: { size: 32, bold: true, font: "SimHei" },
  65. paragraph: { spacing: { before: 240, after: 160 }, outlineLevel: 1 },
  66. },
  67. ],
  68. },
  69. sections: [
  70. {
  71. properties: {
  72. page: {
  73. size: { width: A4_WIDTH, height: A4_HEIGHT },
  74. margin: { top: MARGIN, right: MARGIN, bottom: MARGIN, left: MARGIN },
  75. },
  76. },
  77. headers: {
  78. default: new Header({
  79. children: [
  80. new Paragraph({
  81. children: [new TextRun({ text: "陇耘鲜达系统验收环境说明", font: "SimSun", size: 18, color: "888888" })],
  82. alignment: AlignmentType.CENTER,
  83. }),
  84. ],
  85. }),
  86. },
  87. footers: {
  88. default: new Footer({
  89. children: [
  90. new Paragraph({
  91. children: [
  92. new TextRun({ text: "第 ", font: "SimSun", size: 18, color: "888888" }),
  93. new TextRun({ children: [PageNumber.CURRENT], font: "SimSun", size: 18, color: "888888" }),
  94. new TextRun({ text: " 页", font: "SimSun", size: 18, color: "888888" }),
  95. ],
  96. alignment: AlignmentType.CENTER,
  97. }),
  98. ],
  99. }),
  100. },
  101. children: [
  102. new Paragraph({
  103. children: [new TextRun({ text: "陇耘鲜达系统验收环境说明", font: "SimHei", size: 44, bold: true })],
  104. alignment: AlignmentType.CENTER,
  105. spacing: { after: 360 },
  106. }),
  107. makeTable([
  108. ["项目", "内容"],
  109. ["文档名称", "陇耘鲜达系统验收环境说明"],
  110. ["版本", "v1.0"],
  111. ["日期", "2026-05-07"],
  112. ["关联文档", "陇耘鲜达系统操作手册 v1.0"],
  113. ]),
  114. new Paragraph({ children: [new PageBreak()] }),
  115. new Paragraph({
  116. heading: HeadingLevel.HEADING_2,
  117. children: [new TextRun({ text: "系统访问信息", font: "SimHei", size: 32, bold: true })],
  118. spacing: { before: 240, after: 160 },
  119. }),
  120. makeTable([
  121. ["项目", "地址"],
  122. ["Web 运营端", "[待填写]"],
  123. ["小程序 H5 预览", "[待填写]"],
  124. ["后端 API", "[待填写]"],
  125. ]),
  126. new Paragraph({ children: [new PageBreak()] }),
  127. new Paragraph({
  128. heading: HeadingLevel.HEADING_2,
  129. children: [new TextRun({ text: "演示账号", font: "SimHei", size: 32, bold: true })],
  130. spacing: { before: 240, after: 160 },
  131. }),
  132. makeTable([
  133. ["角色", "用户名", "密码", "说明"],
  134. ["Web 超级管理员", "[待填写]", "[待填写]", "验证运营端全部菜单与功能"],
  135. ["客户端账号", "[待填写]", "[待填写]", "验证小程序客户端下单、支付等功能"],
  136. ["供应商端账号", "[待填写]", "[待填写]", "验证小程序供应商端商品管理、接单等功能"],
  137. ["配送员端账号", "[待填写]", "[待填写]", "验证小程序配送员端接单、配送等功能"],
  138. ]),
  139. new Paragraph({ children: [new PageBreak()] }),
  140. new Paragraph({
  141. heading: HeadingLevel.HEADING_2,
  142. children: [new TextRun({ text: "客户端环境要求", font: "SimHei", size: 32, bold: true })],
  143. spacing: { before: 240, after: 160 },
  144. }),
  145. makeTable([
  146. ["项目", "要求"],
  147. ["浏览器", "Chrome 90+ 或其他现代浏览器"],
  148. ["小程序", "微信 7.0+ 或 H5 浏览器预览"],
  149. ["Web 分辨率", "1920×1080"],
  150. ["小程序模拟", "iPhone 尺寸"],
  151. ]),
  152. new Paragraph({ children: [new PageBreak()] }),
  153. new Paragraph({
  154. heading: HeadingLevel.HEADING_2,
  155. children: [new TextRun({ text: "数据说明", font: "SimHei", size: 32, bold: true })],
  156. spacing: { before: 240, after: 160 },
  157. }),
  158. new Paragraph({
  159. children: [
  160. new TextRun({ text: "演示数据范围:", font: "SimSun", size: 24, bold: true }),
  161. new TextRun({ text: "系统已预置测试区域、测试商品、测试订单等数据,覆盖操作手册所述主要业务场景。", font: "SimSun", size: 24 }),
  162. ],
  163. spacing: { line: 360 },
  164. }),
  165. new Paragraph({
  166. children: [
  167. new TextRun({ text: "截图来源:", font: "SimSun", size: 24, bold: true }),
  168. new TextRun({ text: "操作手册中的截图均取自 H5 本地预览环境,实际小程序界面以微信端为准。", font: "SimSun", size: 24 }),
  169. ],
  170. spacing: { line: 360 },
  171. }),
  172. new Paragraph({ children: [new PageBreak()] }),
  173. new Paragraph({
  174. heading: HeadingLevel.HEADING_2,
  175. children: [new TextRun({ text: "保密说明", font: "SimHei", size: 32, bold: true })],
  176. spacing: { before: 240, after: 160 },
  177. }),
  178. new Paragraph({
  179. children: [new TextRun({ text: "本文档包含系统访问地址与演示账号信息,仅供项目验收期间使用。验收完成后,相关账号应及时回收或销毁,本文档不再分发。", font: "SimSun", size: 24 })],
  180. spacing: { line: 360 },
  181. }),
  182. ],
  183. },
  184. ],
  185. });
  186. Packer.toBuffer(doc).then(buffer => {
  187. fs.writeFileSync(OUTPUT, buffer);
  188. console.log(`✅ Environment spec saved to: ${OUTPUT}`);
  189. console.log(` Size: ${(buffer.length / 1024).toFixed(1)} KB`);
  190. });