终审编委信息

This commit is contained in:
2026-07-06 09:11:20 +08:00
parent 5260ca8ea5
commit 262e634f85
24 changed files with 5529 additions and 519 deletions

View File

@@ -186,28 +186,105 @@ function applyTableCaptionCenterParagraphPr(pInner) {
return '<w:pPr><w:jc w:val="center"/></w:pPr>' + pInner;
}
/** 从 tbl 前向前收集紧邻的 w:p避免全文正则灾难性回溯 */
function collectParagraphBlocksImmediatelyBefore(xml, tblIdx, minIndex) {
const blocks = [];
let end = tblIdx;
while (end > minIndex && blocks.length < 8) {
let ws = end;
while (ws > minIndex && /\s/.test(xml.charAt(ws - 1))) {
ws -= 1;
}
if (ws <= minIndex) {
break;
}
const closeIdx = xml.lastIndexOf('</w:p>', ws - 1);
if (closeIdx < minIndex) {
break;
}
const openIdx = xml.lastIndexOf('<w:p', closeIdx);
if (openIdx < minIndex) {
break;
}
const raw = xml.slice(openIdx, ws);
if (!/<\/w:p>\s*$/i.test(raw)) {
break;
}
blocks.unshift({
start: openIdx,
raw: raw,
inner: raw.replace(/^<w:p\b[^>]*>/i, '').replace(/<\/w:p>\s*$/i, '')
});
end = openIdx;
}
return blocks;
}
function isHomePageMetadataTableBlock(block) {
const text = String(block || '');
return /Author/i.test(text) && /contributions/i.test(text) && /Abstract/i.test(text);
}
/** 正文表格标题Table N…紧挨 w:tbl 前的段落强制居中,不含首页元数据表格 */
export function patchBodyTableCaptionCenterToXml(xml) {
return xml.replace(/((?:<w:p\b[^>]*>[\s\S]*?<\/w:p>\s*)+)(\s*<w:tbl\b)/gi, function (match, paragraphGroup, tblOpen) {
const blocks = paragraphGroup.match(/<w:p\b[^>]*>[\s\S]*?<\/w:p>/gi) || [];
if (!blocks.length) {
return match;
if (!xml || xml.indexOf('<w:tbl') < 0) {
return xml;
}
const parts = [];
let cursor = 0;
const tblToken = '<w:tbl';
const closeTag = '</w:tbl>';
while (cursor < xml.length) {
const tblIdx = xml.indexOf(tblToken, cursor);
if (tblIdx < 0) {
parts.push(xml.slice(cursor));
break;
}
const firstText = extractTableCaptionParagraphPlainText(
blocks[0].replace(/^<w:p\b[^>]*>/, '').replace(/<\/w:p>$/, '')
);
if (!isBodyTableCaptionPlainText(firstText)) {
return match;
const tblEnd = xml.indexOf(closeTag, tblIdx);
if (tblEnd < 0) {
parts.push(xml.slice(cursor));
break;
}
const centered = blocks.map(function (block) {
return block.replace(/(<w:p\b[^>]*>)([\s\S]*?)(<\/w:p>)/, function (_full, open, inner, close) {
return open + applyTableCaptionCenterParagraphPr(inner) + close;
const tblEndExclusive = tblEnd + closeTag.length;
const tblBlock = xml.slice(tblIdx, tblEndExclusive);
if (isHomePageMetadataTableBlock(tblBlock)) {
parts.push(xml.slice(cursor, tblEndExclusive));
cursor = tblEndExclusive;
continue;
}
const blocks = collectParagraphBlocksImmediatelyBefore(xml, tblIdx, cursor);
const isCaption =
blocks.length &&
isBodyTableCaptionPlainText(extractTableCaptionParagraphPlainText(blocks[0].inner));
if (isCaption) {
parts.push(xml.slice(cursor, blocks[0].start));
blocks.forEach(function (entry) {
parts.push(
entry.raw.replace(/(<w:p\b[^>]*>)([\s\S]*?)(<\/w:p>)/i, function (_full, open, inner, close) {
return open + applyTableCaptionCenterParagraphPr(inner) + close;
})
);
});
});
return centered.join('') + tblOpen;
});
const afterBlocks = blocks[blocks.length - 1].start + blocks[blocks.length - 1].raw.length;
parts.push(xml.slice(afterBlocks, tblIdx));
} else {
parts.push(xml.slice(cursor, tblIdx));
}
parts.push(tblBlock);
cursor = tblEndExclusive;
}
return parts.join('');
}
/** 导出后处理:除首页表格外,正文表格标题居中 */
@@ -248,11 +325,17 @@ function ensureFigureTitleTrailingPeriod(text) {
return trimmed + '.';
}
function createFigureTitleParagraph(children) {
return createWordParagraph(children, { alignment: AlignmentType.JUSTIFIED });
function createFigureTitleParagraph(children, alignment) {
return createWordParagraph(children, { alignment: alignment || AlignmentType.CENTER });
}
function appendFigureTitleParagraphs(children, titleHtml) {
function hasFigureAnnotation(noteHtml) {
return !!htmlToPlainText(String(noteHtml || '')).trim();
}
function appendFigureTitleParagraphs(children, titleHtml, options) {
const opts = options || {};
const alignment = hasFigureAnnotation(opts.note) ? AlignmentType.JUSTIFIED : AlignmentType.CENTER;
const segments = splitHtmlSegments(titleHtml)
.map(function (segment) {
return htmlToPlainText(segment).trim();
@@ -266,16 +349,19 @@ function appendFigureTitleParagraphs(children, titleHtml) {
const text =
index === segments.length - 1 ? ensureFigureTitleTrailingPeriod(segment) : segment;
children.push(
createFigureTitleParagraph([
new TextRun({
text: text,
bold: true,
color: TITLE_COLOR,
font: FONT_NAME,
size: TITLE_FONT_SIZE,
kern: FONT_KERN_MIN_1PT
})
])
createFigureTitleParagraph(
[
new TextRun({
text: text,
bold: true,
color: TITLE_COLOR,
font: FONT_NAME,
size: TITLE_FONT_SIZE,
kern: FONT_KERN_MIN_1PT
})
],
alignment
)
);
});
}
@@ -771,6 +857,28 @@ function buildTableWordChildren(processedItem, options) {
return children;
}
/** 稿件导出:标题 + 表格 + 表注均为单栏(分节符在标题前 / 表前,双栏恢复在表注后 / 表后) */
export function buildTableWordManuscriptParts(processedItem, options) {
const blockChildren = buildTableWordChildren(processedItem, options);
const tableIndex = blockChildren.findIndex(function (child) {
return child instanceof Table;
});
if (tableIndex < 0) {
return {
titleChildren: blockChildren,
tableChildren: [],
noteChildren: []
};
}
return {
titleChildren: blockChildren.slice(0, tableIndex),
tableChildren: blockChildren.slice(tableIndex, tableIndex + 1),
noteChildren: blockChildren.slice(tableIndex + 1)
};
}
export function buildTableWordDocument(processedItem) {
return createWordDocument(buildTableWordChildren(processedItem));
}