| | |
| | | const floatingPositionPattern = /<w:tblpPr\b[^>]*\/>/ |
| | | const tableIndentPattern = /<w:tblInd\b[^>]*\/>/ |
| | | const runFontsPattern = /<w:rFonts\b[^>]*\/>/g |
| | | const tableRowPattern = /<w:tr(?:\s[^>]*)?>[\s\S]*?<\/w:tr>/g |
| | | const tableCellPattern = /<w:tc(?:\s[^>]*)?>[\s\S]*?<\/w:tc>/g |
| | | |
| | | function fitCoverCustomer(xml) { |
| | | let changed = false |
| | | const normalized = xml.replace(tableRowPattern, row => { |
| | | if (changed) return row |
| | | const cells = [...row.matchAll(tableCellPattern)] |
| | | if (cells.length !== 2) return row |
| | | const cellText = cell => [...cell.matchAll(/<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>/g)] |
| | | .map(match => match[1]).join('') |
| | | if (cellText(cells[0][0]).replace(/[\s::]/g, '') !== '委托单位') return row |
| | | |
| | | const valueCell = cells[1][0] |
| | | const customer = cellText(valueCell) |
| | | const widthTag = valueCell.match(/<w:tcW\b[^>]*>/)?.[0] |
| | | const widthTwips = Number(widthTag?.match(/\bw:w="(\d+)"/)?.[1]) |
| | | const fontHalfPoints = Number(valueCell.match(/<w:sz\b[^>]*\bw:val="(\d+)"/)?.[1]) |
| | | if (!customer || customer.includes('{{') || !widthTwips || fontHalfPoints !== 32) return row |
| | | |
| | | // 封面下划线是单元格底边框。16 磅的长单位名称刚好占满列宽时, |
| | | // PDF 排版器可能将段落结束符挤到第二行,导致表格行和下划线下移。 |
| | | const units = [...customer].reduce((sum, char) => sum + |
| | | (/\s/.test(char) ? 0.35 : char.codePointAt(0) > 0x2e80 ? 1 : 0.6), 0) |
| | | const availablePoints = widthTwips / 20 - 10 |
| | | if (units * fontHalfPoints / 2 <= availablePoints) return row |
| | | const fittedHalfPoints = Math.max(24, Math.floor(availablePoints / units * 2)) |
| | | const fittedCell = valueCell.replace(/<w:sz(?:Cs)?\b[^>]*\/>/g, tag => |
| | | tag.replace(/\bw:val="32"/, `w:val="${fittedHalfPoints}"`)) |
| | | if (fittedCell === valueCell) return row |
| | | changed = true |
| | | return row.replace(valueCell, fittedCell) |
| | | }) |
| | | return changed ? normalized : null |
| | | } |
| | | |
| | | function alignReportHeader(xml, reportCode) { |
| | | // 旧检验报告把页码放在浮动文本框中;SuperDoc 重新分页时会丢失 Word 的横向锚点。 |
| | |
| | | const themeXml = themePart ? await themePart.async('string') : '' |
| | | const themeFonts = { major: chineseThemeFont(themeXml, 'major'), minor: chineseThemeFont(themeXml, 'minor') } |
| | | let normalizedXml = alignResultTable(documentXml) || documentXml |
| | | normalizedXml = fitCoverCustomer(normalizedXml) || normalizedXml |
| | | normalizedXml = materializeChineseThemeFonts(normalizedXml, themeFonts) || normalizedXml |
| | | let changed = normalizedXml !== documentXml |
| | | if (changed) zip.file('word/document.xml', normalizedXml) |