跳至內容
Astera Technology

續頁也要查打印欄標題

明細清單生成後,不只核第一頁的欄名。

下載完整個案資料及參考答案 ↓

訂判斷及所需輸入

題內十二行固定高度明細,欄標題為 IDENTIFIER,測試排版共三頁。標題若當普通行,只在第一頁;重複表頭才在第一、二、三頁都有。

已填本地測試工作表
情況輸入 JSON
原例測試{"rows":12,"header":"IDENTIFIER"}
下載可編輯 CSV ↓

跑所附比較

核對真正生成及抽出 PDF,逐頁查標題。此表頭示範未確立任意樣式或未知字體尺寸下的排頁。

錯誤及所需輸出
路徑輸出 JSON
錯誤路徑{"pageCount":3,"headerPages":[1]}
所需路徑{"pageCount":3,"headerPages":[1,2,3]}
下載可編輯 CSV ↓
Node24.14.1 程序;須 Playwright1.63 Chromium 及 PDF.js6.4.299
import assert from 'node:assert/strict';
const smallWhole=(x,max)=>Number.isSafeInteger(x)&&x>=0&&x<=max;
import {createRequire} from 'node:module';
import {pathToFileURL} from 'node:url';
const htmlEscape=s=>String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
async function withPage(action,options={}){
  const require=createRequire(import.meta.url);const {chromium}=require('playwright');
  const browser=await chromium.launch({headless:true});
  try{const context=await browser.newContext(options);const page=await context.newPage();
    const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
    return await action(page,context,requests);
  }finally{await browser.close();}
}
async function pdfObservation(html){
  const bytes=await withPage(async page=>{await page.setContent(html);return page.pdf({preferCSSPageSize:true,printBackground:true});});
  const require=createRequire(import.meta.url);
  const {getDocument}=await import(pathToFileURL(require.resolve('pdfjs-dist/legacy/build/pdf.mjs')).href);
  const loadingTask=getDocument({data:Uint8Array.from(bytes),useSystemFonts:true,disableFontFace:true});
  try{const document=await loadingTask.promise;const pages=[];for(let n=1;n<=document.numPages;n++){
    const page=await document.getPage(n);const content=await page.getTextContent();
    pages.push(content.items.filter(x=>typeof x.str==='string'&&x.str).map(x=>({text:x.str,x:x.transform[4],y:x.transform[5]})));
  }return {pageCount:document.numPages,pages};}finally{await loadingTask.destroy();}
}
const printStyle='<style>@page{size:100mm 100mm;margin:10mm}body{margin:0;font:10px Arial}p{margin:0}</style>';

const run=async function run(i,corrected=true){
    if(typeof i.header!=='string'||!i.header||i.header.length>40||!smallWhole(i.rows,20))return {held:true};
    const html=printStyle+'<style>table{border-collapse:collapse;width:100%}thead{display:'+(corrected?'table-header-group':'table-row-group')+'}th{padding:0;height:5mm;line-height:5mm}td{padding:0;height:15mm;line-height:15mm}</style><table><thead><tr><th>'+htmlEscape(i.header)+'</th></tr></thead><tbody>'+Array.from({length:i.rows},(_,n)=>'<tr><td>ROW'+(n+1)+'</td></tr>').join('')+'</tbody></table>';
    const out=await pdfObservation(html);return {pageCount:out.pageCount,headerPages:out.pages.map((p,n)=>p.some(x=>x.text===i.header)?n+1:null).filter(n=>n!==null)};
  };
const cases=[{"input":{"rows":12,"header":"IDENTIFIER"},"corrected":false,"expected":{"pageCount":3,"headerPages":[1]}},{"input":{"rows":12,"header":"IDENTIFIER"},"corrected":true,"expected":{"pageCount":3,"headerPages":[1,2,3]}},{"input":{"rows":3,"header":"IDENTIFIER"},"corrected":true,"expected":{"pageCount":1,"headerPages":[1]}},{"input":{"rows":12,"header":null},"corrected":true,"expected":{"held":true}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
下載可執行例子 ↓

按邊界依據作判斷

三行只一頁,一個標題就齊;所需欄名未提供便暫停,不由呈現程序自行編。

  1. 訂續頁所需欄名
  2. 打印有內容清單
  3. 逐頁查抽出結果

欄名未知,不能靠首筆資料猜。

可編輯邊界輸入及結果
條件輸入 JSON預期輸出 JSON
一頁內的清單{"rows":3,"header":"IDENTIFIER"}{"pageCount":1,"headerPages":[1]}
所需欄名未知{"rows":12,"header":null}{"held":true}
下載可編輯 CSV ↓

原例只見首頁標題截圖,可證明清單齊嗎?

查看參考答案

不能,第二、三頁也要核。更正檔案三頁都有 IDENTIFIER。

例子檔案

相關資源