', openIdx)
@@ -186,6 +186,7 @@ function takeBalancedDiv(
const end = nextClose + 6
return {
full: html.slice(openIdx, end),
+ openTag: html.slice(openIdx, openTagEnd + 1),
inner: html.slice(openTagEnd + 1, nextClose),
end
}
@@ -196,6 +197,63 @@ function takeBalancedDiv(
return null
}
+function collectTopLevelDivChildren(
+ innerHtml: string
+): Array<{ openTag: string; inner: string }> {
+ const children: Array<{ openTag: string; inner: string }> = []
+ let pos = 0
+ const lower = innerHtml.toLowerCase()
+ while (pos < innerHtml.length) {
+ const divIdx = lower.indexOf('
]*style\s*=\s*["'][^"']*display:\s*flex)[^>]*>/gi
+ const opens: number[] = []
+ let m: RegExpExecArray | null
+ while ((m = openRe.exec(html)) !== null) {
+ opens.push(m.index)
+ }
+
+ let out = html
+ for (let oi = opens.length - 1; oi >= 0; oi -= 1) {
+ const index = opens[oi]
+ const flex = takeBalancedDiv(out, index)
+ if (!flex) continue
+ // 底部供需方双栏用 space-between,交给 normalizePartyFlexLayoutForDocx
+ if (/justify-content:\s*space-between/i.test(flex.openTag)) continue
+
+ const children = collectTopLevelDivChildren(flex.inner)
+ if (children.length !== 2) continue
+
+ const [left, right] = children
+ const absoluteRight =
+ /position:\s*absolute/i.test(right.openTag) && /right:\s*/i.test(right.openTag)
+ const labelPair =
+ (left.inner.includes('供方') && right.inner.includes('合同编号')) ||
+ (left.inner.includes('需方') && right.inner.includes('签订地点'))
+ if (!absoluteRight && !labelPair) continue
+ // 避免误伤底部签署区(含「单位名称」等字段)
+ if (left.inner.includes('单位名称') || right.inner.includes('单位名称')) continue
+
+ const table = `
| ${left.inner} | ${right.inner} |
`
+ out = out.slice(0, index) + table + out.slice(flex.end)
+ }
+
+ return out
+}
+
/**
* 合同底部供方/需方在预览里是 flex 左右栏;Word 不认 flex,导出前改为双列表格。
*/
@@ -214,22 +272,11 @@ export function normalizePartyFlexLayoutForDocx(html: string): string {
const flex = takeBalancedDiv(out, index)
if (!flex) continue
- const children: string[] = []
- let pos = 0
- const innerLower = flex.inner.toLowerCase()
- while (pos < flex.inner.length && children.length < 2) {
- const divIdx = innerLower.indexOf('
| ${children[0]} | ${children[1]} |