release: 发布 v0.6.2 DOCX 真实文档修复
新增能力:将 DOCX 发布验收拆分为四套独立 140,支持真实语料冻结、指纹复用、失败与基础设施错误独立统计,并为表格换行、全 JSON 围栏、代码连续性和长文档分页建立通用门禁。 问题修复:冻结 Paged.js 分片前的逻辑表格列轨并传递打印几何,统一 Markdown 表格换行、代码、段落与 OOXML 翻译;改进 PDF 文本流排序、语义块映射、颜色与栅格比较,消除窄字符重叠和跨行范围符号误报。 兼容与部署:版本统一为 0.6.2;正式 Docker 镜像内置固定 Chromium、Pandoc 3.9.0.2 和 Serif/Sans/Mono 字体;Desktop NSIS 与 ZIP 继续直接内置字体,无需系统字体安装。 验证结果:合成基线与长庆严格 280/280,M4N 140/140;健康数据残余误报 6/115(5.22%),均核查为重复表头自动对齐/取样误报且基础设施错误为 0。全项目测试、类型检查、生产构建和 git diff --check 通过;正式 Docker、NSIS、ZIP、离线镜像、部署包、清单及 SHA-256 均已生成并校验。
This commit is contained in:
@@ -37,7 +37,11 @@ import { renderMermaidDefinitions } from "./mermaid-renderer.js";
|
||||
import { replaceMermaidSvgWithImages } from "./mermaid-static-image.js";
|
||||
import type { MermaidOutputMode } from "./mermaid-static-image.js";
|
||||
import { enablePrintMediaForPreview } from "./preview-styles.js";
|
||||
import "./paged-table-handler.js";
|
||||
import {
|
||||
forcePagedTableRowsToNextPage,
|
||||
missingPagedTableRowIds,
|
||||
stabilizePagedTableColumns
|
||||
} from "./paged-table-handler.js";
|
||||
import {
|
||||
buildPagedMediaCss,
|
||||
continuousDocumentGeometryCss,
|
||||
@@ -61,6 +65,7 @@ export interface PagedDocumentRenderOptions {
|
||||
target: PagedRenderTarget;
|
||||
shouldContinue?: () => boolean;
|
||||
mermaidOutput?: MermaidOutputMode;
|
||||
allowIncompleteTableGeometry?: boolean;
|
||||
}
|
||||
|
||||
export interface ContinuousDocumentRenderOptions {
|
||||
@@ -75,6 +80,33 @@ export interface PreviewEngineStyles {
|
||||
echartsCss: string;
|
||||
}
|
||||
|
||||
export function protectFittableInlineCodeParagraphs(
|
||||
root: ParentNode,
|
||||
pageContentHeightPx: number
|
||||
) {
|
||||
if (!Number.isFinite(pageContentHeightPx) || pageContentHeightPx <= 0) {
|
||||
return 0;
|
||||
}
|
||||
let protectedCount = 0;
|
||||
for (const paragraph of root.querySelectorAll<HTMLElement>(
|
||||
"#write > p.md-inline-code-paragraph"
|
||||
)) {
|
||||
const height = paragraph.getBoundingClientRect().height;
|
||||
if (!(height > 0 && height <= pageContentHeightPx)) {
|
||||
continue;
|
||||
}
|
||||
paragraph.style.setProperty("break-inside", "avoid", "important");
|
||||
paragraph.style.setProperty(
|
||||
"page-break-inside",
|
||||
"avoid",
|
||||
"important"
|
||||
);
|
||||
paragraph.dataset.mdtpInlineCodeKeepWhole = "true";
|
||||
protectedCount += 1;
|
||||
}
|
||||
return protectedCount;
|
||||
}
|
||||
|
||||
export const DEFAULT_IMAGE_READY_TIMEOUT_MS = 10_000;
|
||||
|
||||
function waitForImage(
|
||||
@@ -699,6 +731,7 @@ export class PagedDocumentRuntime {
|
||||
payload.features.includes("echarts") ||
|
||||
content.querySelector(".mermaid svg") ||
|
||||
content.querySelector("img.md-document-image") ||
|
||||
content.querySelector("table") ||
|
||||
content.querySelector('[data-semantic-region="cover"]')
|
||||
) {
|
||||
const measurement = mountMeasurementContainer(
|
||||
@@ -710,6 +743,14 @@ export class PagedDocumentRuntime {
|
||||
);
|
||||
try {
|
||||
await documentRef.fonts.ready;
|
||||
protectFittableInlineCodeParagraphs(
|
||||
measurement.host,
|
||||
getPageContentDimensions(payload.exportConfig).height
|
||||
);
|
||||
stabilizePagedTableColumns(
|
||||
measurement.host,
|
||||
getPageContentDimensions(payload.exportConfig).height
|
||||
);
|
||||
constrainSemanticCoversToPage(
|
||||
measurement.host,
|
||||
getPageContentDimensions(payload.exportConfig).height
|
||||
@@ -816,6 +857,51 @@ export class PagedDocumentRuntime {
|
||||
stylesheets,
|
||||
this.root
|
||||
);
|
||||
const maximumTableRowRecoveryAttempts = 3;
|
||||
for (
|
||||
let attempt = 0;
|
||||
attempt < maximumTableRowRecoveryAttempts;
|
||||
attempt += 1
|
||||
) {
|
||||
const missingRowIds = missingPagedTableRowIds(
|
||||
repaginationSource,
|
||||
this.root
|
||||
);
|
||||
if (missingRowIds.length === 0) {
|
||||
break;
|
||||
}
|
||||
const recoveredCount = forcePagedTableRowsToNextPage(
|
||||
repaginationSource,
|
||||
missingRowIds
|
||||
);
|
||||
if (recoveredCount !== missingRowIds.length) {
|
||||
throw new Error(
|
||||
`分页表格行恢复标记不完整:缺失 ${missingRowIds.length} 行,` +
|
||||
`仅定位 ${recoveredCount} 行`
|
||||
);
|
||||
}
|
||||
previewer.chunker.destroy();
|
||||
previewer.polisher.destroy();
|
||||
previewer = new Previewer();
|
||||
this.activePreviewer = previewer;
|
||||
flow = await previewer.preview(
|
||||
repaginationSource.cloneNode(true) as DocumentFragment,
|
||||
stylesheets,
|
||||
this.root
|
||||
);
|
||||
}
|
||||
const unresolvedTableRowIds = missingPagedTableRowIds(
|
||||
repaginationSource,
|
||||
this.root
|
||||
);
|
||||
if (
|
||||
unresolvedTableRowIds.length > 0 &&
|
||||
!options.allowIncompleteTableGeometry
|
||||
) {
|
||||
throw new Error(
|
||||
`分页后表格正文行缺失:${unresolvedTableRowIds.join(", ")}`
|
||||
);
|
||||
}
|
||||
const mediaIds = getMediaBackfillIdsInDocumentOrder(
|
||||
repaginationSource
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user