使用PDFKit生成带自动分页的多页装箱单PDF遇问题求助
PDFKit装箱单分页问题修复方案
针对你用PDFKit生成装箱单时分页不生效的问题,先梳理原代码的核心错误,再给出修正后的完整代码:
原代码核心问题
- 分页判断逻辑错误:用未定义的
nfs.length判断,且错误以总数据长度作为分页触发条件,正确应该是当前页面已渲染40条时新增页面 - 模板字符串失效:单引号包裹的字符串无法解析
${data}这类变量,需改用反引号 - 表头数据无法传递:
generateHeader函数未接收参数,无法动态填充运输车辆等信息 - 分页后缺少表头:新增页面未重新生成表头,导致新页无标题信息
- 索引与位置计算错误:分页后索引重置逻辑错误,导致条目位置偏移
- 核心函数未调用:漏了执行
generateInnerPdf(doc),导致整个生成逻辑未启动
修正后的完整代码
var doc = new PDFDocument({ size: 'A4'}); var stream = doc.pipe(blobStream()); const layoutX = { align: 'center' } const layoutY = 20 const PAGE_ITEM_LIMIT = 40; // 每页最大条目数 let currentPageItems = 0; // 当前页面已渲染条目数 let tableStartY = layoutY + 40; // 表头下方开始渲染条目的Y坐标,预留表头空间 // 模拟当前日期(按巴西格式生成) const currentDate = new Date().toLocaleDateString('pt-BR'); function generateInnerPdf(doc) { const notes = [ { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 01 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 02 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 03 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 04 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 05 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 06 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 07 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 08 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 09 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 10 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 11 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 12 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 13 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 14 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 15 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 16 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 17 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 18 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 19 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 20 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 21 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 22 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 23 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 24 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 25 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 26 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 27 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 28 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 29 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 30 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 31 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 32 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 33 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 34 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 35 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 36 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 37 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 38 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 39 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 40 }, { vehiclePlate: 'MTG7200', logisticName: 'PAC', numNf: 41 } ]; // 生成第一页表头 generateHeader(doc, notes[0].vehiclePlate, notes[0].logisticName); // 渲染条目 notes.forEach((item, index) => { // 计算当前条目的Y坐标:表头下方 + 条目索引*行高 const itemY = tableStartY + (currentPageItems * 20); // 渲染当前条目 generateTableBody(doc, itemY, item.numNf, item.logisticName); currentPageItems++; // 达到每页最大条目数时,新增页面并重置计数器、重新生成表头 if (currentPageItems === PAGE_ITEM_LIMIT && index !== notes.length - 1) { doc.addPage(); currentPageItems = 0; generateHeader(doc, item.vehiclePlate, item.logisticName); } }); // 生成最后一页页脚 generateFooter(doc); } function generateHeader(doc, vehiclePlate, logisticName) { doc .fontSize(11) .text( `Lupo S.A Notas fiscais liberadas para despacho em ${currentDate}`, layoutX, layoutY ) .text( `Transportador: ${vehiclePlate} - ${logisticName}`, layoutX, layoutY + 20 ); } function generateTableBody(doc, y, numNf, logisticName) { doc .fontSize(10) .text(numNf, 50, y) .text(logisticName, 150, y); } function generateFooter(doc){ doc .fontSize(11) .text( 'Declaro ter recebido as notas fiscais acima relacionadas e suas respectivas mercadorias em perfeitas condições', layoutX, layoutY + 660 ) .text(`Araraquara, ${currentDate}`, layoutX, layoutY + 690) .text( '____________________________________________________________', layoutX, layoutY + 720 ) .text('Assinatura', layoutX, layoutY + 735); } // 启动生成并渲染到iframe generateInnerPdf(doc); doc.end(); stream.on('finish', function() { iframe.src = stream.toBlobURL('application/pdf'); });
关键修改点说明
- 新增分页控制变量:用
PAGE_ITEM_LIMIT定义每页最大条目数,currentPageItems追踪当前页面已渲染数量,避免硬编码 - 修正分页判断逻辑:当当前页面条目数达到40,且不是最后一条数据时,新增页面并重置计数器,同时重新生成表头
- 修复模板字符串:所有包含变量的字符串改用反引号包裹,确保变量正常解析
- 传递表头数据:
generateHeader函数接收车辆牌号和物流公司参数,动态填充内容 - 修复位置计算:条目Y坐标基于当前页面已渲染数量计算,分页后自动从新页面表头下方开始
- 补全函数调用:添加
generateInnerPdf(doc)执行生成逻辑
内容的提问来源于stack exchange,提问作者Wilton Santos
相关产品推荐
相关产品推荐

