fix: 重建DOCX视觉一致性门禁

This commit is contained in:
SkyJourney
2026-08-03 10:09:43 +08:00
parent 842c3f1782
commit 28c88faabb
11 changed files with 811 additions and 49 deletions
@@ -113,6 +113,17 @@ function observeParagraph(
Array.from(lines[index]?.normalizedText ?? "").length ===
(matchedByLine.get(index)?.length ?? 0),
);
const visualLines = matchedLines.map((line) => ({
pageNumber: line.pageNumber,
bounds: line.line.bounds,
fontFamilies: [
...new Set(
line.line.items.flatMap((item) =>
item.fontFamily ? [item.fontFamily] : [],
),
),
].sort(),
}));
const matched = matchedCharacterCount === expectedCharacters.length;
if (matched) {
cursor.lineIndex = localCursor.lineIndex;
@@ -146,6 +157,7 @@ function observeParagraph(
? {}
: { averageBaselineGapPt }),
exclusiveGeometry,
visualLines,
};
}
@@ -192,6 +204,8 @@ function compareParagraph(
expectation: EditableParagraphExpectation,
baseline: PdfParagraphLayoutObservation,
candidate: PdfParagraphLayoutObservation,
baselineCoverPageCount: number,
candidateCoverPageCount: number,
): VisualDiffIssue[] {
const issues: VisualDiffIssue[] = [];
if (!baseline.matched || !candidate.matched) {
@@ -299,6 +313,27 @@ function compareParagraph(
},
});
}
} else if (baselineCoverPageCount > 0 || candidateCoverPageCount > 0) {
const baselineOutsideCover = baseline.pageNumbers.every(
(pageNumber) => pageNumber > baselineCoverPageCount,
);
const candidateOutsideCover = candidate.pageNumbers.every(
(pageNumber) => pageNumber > candidateCoverPageCount,
);
if (!baselineOutsideCover || !candidateOutsideCover) {
issues.push({
code: "COVER_LAYOUT_MISMATCH",
severity: "failure",
message: `${expectation.index + 1} 个正文段落回流到独立封面页`,
details: {
paragraphIndex: expectation.index,
baselinePages: baseline.pageNumbers.join(","),
candidatePages: candidate.pageNumbers.join(","),
baselineCoverPageCount,
candidateCoverPageCount,
},
});
}
}
if (baseline.exclusiveGeometry && candidate.exclusiveGeometry) {
@@ -373,6 +408,12 @@ export function comparePdfEditableParagraphLayouts(
const candidateCharacters = candidateLines.map((line) =>
Array.from(line.normalizedText),
);
const baselineCoverPageCount = baselinePageSemantics.filter(
(page) => page.kind === "cover",
).length;
const candidateCoverPageCount = candidatePageSemantics.filter(
(page) => page.kind === "cover",
).length;
const baselineCursor: MatchCursor = { lineIndex: 0, characterIndex: 0 };
const candidateCursor: MatchCursor = { lineIndex: 0, characterIndex: 0 };
@@ -393,6 +434,8 @@ export function comparePdfEditableParagraphLayouts(
expectation,
baselineObservation,
candidateObservation,
baselineCoverPageCount,
candidateCoverPageCount,
);
return {
expectation,