const fs = require("fs"); const path = require("path"); const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType, ShadingType, PageNumber, PageBreak, } = require("docx"); const OUTPUT = path.join(__dirname, "验收环境说明.docx"); const A4_WIDTH = 11906; const A4_HEIGHT = 16838; const MARGIN = 1440; const CONTENT_WIDTH = A4_WIDTH - 2 * MARGIN; const border = { style: BorderStyle.SINGLE, size: 1, color: "999999" }; const borders = { top: border, bottom: border, left: border, right: border }; const cellMargins = { top: 60, bottom: 60, left: 100, right: 100 }; function makeTable(rows, colWidths) { if (!colWidths) { const colCount = rows[0].length; const cw = Math.floor(CONTENT_WIDTH / colCount); colWidths = Array(colCount).fill(cw); colWidths[colCount - 1] = CONTENT_WIDTH - cw * (colCount - 1); } return new Table({ width: { size: CONTENT_WIDTH, type: WidthType.DXA }, columnWidths: colWidths, rows: rows.map((row, rowIdx) => new TableRow({ children: row.map((cell, colIdx) => new TableCell({ borders, width: { size: colWidths[colIdx], type: WidthType.DXA }, margins: cellMargins, ...(rowIdx === 0 ? { shading: { fill: "D5E8F0", type: ShadingType.CLEAR } } : {}), children: [ new Paragraph({ children: [ new TextRun({ text: cell.replace(/\*\*/g, ""), font: "SimSun", size: 22, bold: rowIdx === 0, }), ], spacing: { line: 300 }, }), ], }) ), }) ), }); } const doc = new Document({ styles: { default: { document: { run: { font: "SimSun", size: 24 } } }, paragraphStyles: [ { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, run: { size: 44, bold: true, font: "SimHei" }, paragraph: { spacing: { before: 360, after: 240 }, outlineLevel: 0 }, }, { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, run: { size: 32, bold: true, font: "SimHei" }, paragraph: { spacing: { before: 240, after: 160 }, outlineLevel: 1 }, }, ], }, sections: [ { properties: { page: { size: { width: A4_WIDTH, height: A4_HEIGHT }, margin: { top: MARGIN, right: MARGIN, bottom: MARGIN, left: MARGIN }, }, }, headers: { default: new Header({ children: [ new Paragraph({ children: [new TextRun({ text: "陇耘鲜达系统验收环境说明", font: "SimSun", size: 18, color: "888888" })], alignment: AlignmentType.CENTER, }), ], }), }, footers: { default: new Footer({ children: [ new Paragraph({ children: [ new TextRun({ text: "第 ", font: "SimSun", size: 18, color: "888888" }), new TextRun({ children: [PageNumber.CURRENT], font: "SimSun", size: 18, color: "888888" }), new TextRun({ text: " 页", font: "SimSun", size: 18, color: "888888" }), ], alignment: AlignmentType.CENTER, }), ], }), }, children: [ new Paragraph({ children: [new TextRun({ text: "陇耘鲜达系统验收环境说明", font: "SimHei", size: 44, bold: true })], alignment: AlignmentType.CENTER, spacing: { after: 360 }, }), makeTable([ ["项目", "内容"], ["文档名称", "陇耘鲜达系统验收环境说明"], ["版本", "v1.0"], ["日期", "2026-05-07"], ["关联文档", "陇耘鲜达系统操作手册 v1.0"], ]), new Paragraph({ children: [new PageBreak()] }), new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: "系统访问信息", font: "SimHei", size: 32, bold: true })], spacing: { before: 240, after: 160 }, }), makeTable([ ["项目", "地址"], ["Web 运营端", "[待填写]"], ["小程序 H5 预览", "[待填写]"], ["后端 API", "[待填写]"], ]), new Paragraph({ children: [new PageBreak()] }), new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: "演示账号", font: "SimHei", size: 32, bold: true })], spacing: { before: 240, after: 160 }, }), makeTable([ ["角色", "用户名", "密码", "说明"], ["Web 超级管理员", "[待填写]", "[待填写]", "验证运营端全部菜单与功能"], ["客户端账号", "[待填写]", "[待填写]", "验证小程序客户端下单、支付等功能"], ["供应商端账号", "[待填写]", "[待填写]", "验证小程序供应商端商品管理、接单等功能"], ["配送员端账号", "[待填写]", "[待填写]", "验证小程序配送员端接单、配送等功能"], ]), new Paragraph({ children: [new PageBreak()] }), new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: "客户端环境要求", font: "SimHei", size: 32, bold: true })], spacing: { before: 240, after: 160 }, }), makeTable([ ["项目", "要求"], ["浏览器", "Chrome 90+ 或其他现代浏览器"], ["小程序", "微信 7.0+ 或 H5 浏览器预览"], ["Web 分辨率", "1920×1080"], ["小程序模拟", "iPhone 尺寸"], ]), new Paragraph({ children: [new PageBreak()] }), new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: "数据说明", font: "SimHei", size: 32, bold: true })], spacing: { before: 240, after: 160 }, }), new Paragraph({ children: [ new TextRun({ text: "演示数据范围:", font: "SimSun", size: 24, bold: true }), new TextRun({ text: "系统已预置测试区域、测试商品、测试订单等数据,覆盖操作手册所述主要业务场景。", font: "SimSun", size: 24 }), ], spacing: { line: 360 }, }), new Paragraph({ children: [ new TextRun({ text: "截图来源:", font: "SimSun", size: 24, bold: true }), new TextRun({ text: "操作手册中的截图均取自 H5 本地预览环境,实际小程序界面以微信端为准。", font: "SimSun", size: 24 }), ], spacing: { line: 360 }, }), new Paragraph({ children: [new PageBreak()] }), new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: "保密说明", font: "SimHei", size: 32, bold: true })], spacing: { before: 240, after: 160 }, }), new Paragraph({ children: [new TextRun({ text: "本文档包含系统访问地址与演示账号信息,仅供项目验收期间使用。验收完成后,相关账号应及时回收或销毁,本文档不再分发。", font: "SimSun", size: 24 })], spacing: { line: 360 }, }), ], }, ], }); Packer.toBuffer(doc).then(buffer => { fs.writeFileSync(OUTPUT, buffer); console.log(`✅ Environment spec saved to: ${OUTPUT}`); console.log(` Size: ${(buffer.length / 1024).toFixed(1)} KB`); });