From 0f38e4a52cdcb5a10d2441f0d7a04b7052a36e7a Mon Sep 17 00:00:00 2001 From: augushong Date: Sun, 17 May 2026 13:30:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(typesetting):=20=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E5=A2=9E=E5=8A=A0orphan=20control=20-=20?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E4=B8=8D=E5=86=8D=E5=AD=A4=E6=82=AC=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=BA=95=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - paginateContent正常块判断增加标题orphan control - 标题(h2/h3/h4)后检查下一个块能否放入当前页 - 若放不下则回退标题到下一页开头 - 超大块处理增加标题回退逻辑 - 超大表格拆分时前面的h2标题和表格第一部分同页 --- public/static/js/phone-image.js | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/public/static/js/phone-image.js b/public/static/js/phone-image.js index dd8c48f..e7ec469 100644 --- a/public/static/js/phone-image.js +++ b/public/static/js/phone-image.js @@ -615,6 +615,15 @@ var PhoneImageEngine = (function () { // 超大块处理:单个块超过整页高度时需要拆分 if (block.estimatedHeight > contentAreaHeight) { + // 检查当前页最后一个块是否为标题,若是则回退使其与超大块第一部分同页 + var lastBlockInPage = currentPageBlocks.length > 0 ? currentPageBlocks[currentPageBlocks.length - 1] : null; + var lastBlockIsHeading = lastBlockInPage && (lastBlockInPage.type === 'h2' || lastBlockInPage.type === 'h3' || lastBlockInPage.type === 'h4'); + + if (lastBlockIsHeading) { + currentPageBlocks.pop(); + currentHeight -= lastBlockInPage.estimatedHeight; + } + // 先把当前页已有的内容推出去 if (currentPageBlocks.length > 0) { contentPages.push(generateContentPage( @@ -625,6 +634,12 @@ var PhoneImageEngine = (function () { pageNumber++; } + // 超大块拆分后,若有回退的标题,加到新页开头 + if (lastBlockIsHeading) { + currentPageBlocks = [lastBlockInPage]; + currentHeight = lastBlockInPage.estimatedHeight; + } + // 尝试拆分超大块 var splitBlocks = splitOversizedBlock(block, contentAreaHeight); for (var s = 0; s < splitBlocks.length; s++) { @@ -644,6 +659,9 @@ var PhoneImageEngine = (function () { } // 正常块:判断是否需要换页 + var isHeading = block.type === 'h2' || block.type === 'h3' || block.type === 'h4'; + var nextBlock = (i + 1 < blocks.length) ? blocks[i + 1] : null; + if (currentHeight + block.estimatedHeight > contentAreaHeight && currentPageBlocks.length > 0) { contentPages.push(generateContentPage( currentPageBlocks, pageNumber, sizeConfig, false @@ -655,6 +673,22 @@ var PhoneImageEngine = (function () { currentPageBlocks.push(block); currentHeight += block.estimatedHeight; + + // Orphan control: 标题后至少跟一个内容块,若下一个块放不下则标题移到下一页 + if (isHeading && nextBlock) { + if (currentHeight + nextBlock.estimatedHeight > contentAreaHeight) { + currentPageBlocks.pop(); + currentHeight -= block.estimatedHeight; + if (currentPageBlocks.length > 0) { + contentPages.push(generateContentPage( + currentPageBlocks, pageNumber, sizeConfig, false + )); + pageNumber++; + } + currentPageBlocks = [block]; + currentHeight = block.estimatedHeight; + } + } } // 最后一页