终审编委信息
This commit is contained in:
@@ -17,8 +17,15 @@ import {
|
||||
import JSZip from 'jszip';
|
||||
import { htmlToPlainText, TABLE_FONT_SIZE, FONT_KERN_MIN_1PT, FONT_KERN_MIN_XIAO_ER, FONT_NAME, PAGE_MARGINS, WORD_PARAGRAPH_SPACING } from '@/utils/exportTableWord';
|
||||
import { formatAuthorFirstName, formatAuthorLastName } from '@/utils/productionSubmissionImport';
|
||||
import { PAGE_HEIGHT_TWIPS, PAGE_WIDTH_TWIPS, getDocumentGridProperties } from '@/utils/exportWordLayout';
|
||||
import {
|
||||
PAGE_HEADER_MARGIN_TWIPS,
|
||||
PAGE_FOOTER_MARGIN_TWIPS,
|
||||
PAGE_HEIGHT_TWIPS,
|
||||
PAGE_WIDTH_TWIPS,
|
||||
getDocumentGridProperties
|
||||
} from '@/utils/exportWordLayout';
|
||||
import orcidIconUrl from '@/assets/img/orcid.png';
|
||||
import { createTmrLogoImageRun } from '@/utils/exportManuscriptWordHeader';
|
||||
|
||||
/** 标题:阿里巴巴普惠体 H / Calibri,四号 14pt */
|
||||
const TITLE_FONT_EAST_ASIA = '阿里巴巴普惠体 H';
|
||||
@@ -378,6 +385,25 @@ export async function fetchManuscriptHeaderData(apiClient, articleId, pArticleId
|
||||
}
|
||||
}
|
||||
|
||||
let stageInfo = null;
|
||||
if (production && production.journal_id && production.journal_stage_id) {
|
||||
const stagesRes = await withPromiseTimeout(
|
||||
apiClient
|
||||
.post('api/Typeset/getStagesOnline', { journal_id: production.journal_id })
|
||||
.catch(function () {
|
||||
return null;
|
||||
}),
|
||||
12000
|
||||
);
|
||||
if (stagesRes && stagesRes.code == 0 && stagesRes.data && stagesRes.data.stages) {
|
||||
const targetStageId = production.journal_stage_id;
|
||||
stageInfo =
|
||||
stagesRes.data.stages.find(function (item) {
|
||||
return String(item.journal_stage_id) === String(targetStageId);
|
||||
}) || null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!production && !authors.length && !previewAuthor) {
|
||||
return {
|
||||
pArticleId: resolvedId,
|
||||
@@ -386,7 +412,8 @@ export async function fetchManuscriptHeaderData(apiClient, articleId, pArticleId
|
||||
previewAuthor: null,
|
||||
journal: journal,
|
||||
organList: organList,
|
||||
finalReview: finalReview
|
||||
finalReview: finalReview,
|
||||
stageInfo: stageInfo
|
||||
};
|
||||
}
|
||||
|
||||
@@ -397,7 +424,8 @@ export async function fetchManuscriptHeaderData(apiClient, articleId, pArticleId
|
||||
previewAuthor: previewAuthor,
|
||||
journal: journal,
|
||||
organList: organList,
|
||||
finalReview: finalReview
|
||||
finalReview: finalReview,
|
||||
stageInfo: stageInfo
|
||||
};
|
||||
}
|
||||
|
||||
@@ -884,7 +912,19 @@ function createAffiliationParagraph(index, addressText) {
|
||||
});
|
||||
}
|
||||
|
||||
function createAuthorTitleParagraph(title) {
|
||||
function buildTitleParagraphChildren(contentRuns, logoImageData) {
|
||||
const children = [];
|
||||
const logoRun = logoImageData && createTmrLogoImageRun(logoImageData);
|
||||
if (logoRun) {
|
||||
children.push(logoRun);
|
||||
}
|
||||
if (contentRuns && contentRuns.length) {
|
||||
children.push.apply(children, contentRuns);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
function createAuthorTitleParagraph(title, logoImageData) {
|
||||
const text = String(title || '').trim();
|
||||
if (!text) {
|
||||
return null;
|
||||
@@ -896,41 +936,49 @@ function createAuthorTitleParagraph(title) {
|
||||
widowControl: false,
|
||||
overflowPunctuation: true,
|
||||
autoSpaceEastAsianText: true,
|
||||
children: [
|
||||
createStyledTextRun(text, {
|
||||
fontEastAsia: TITLE_FONT_EAST_ASIA,
|
||||
fontAscii: TITLE_FONT_ASCII,
|
||||
size: TITLE_FONT_SIZE,
|
||||
bold: true,
|
||||
kern: FONT_KERN_MIN_XIAO_ER
|
||||
})
|
||||
]
|
||||
children: buildTitleParagraphChildren(
|
||||
[
|
||||
createStyledTextRun(text, {
|
||||
fontEastAsia: TITLE_FONT_EAST_ASIA,
|
||||
fontAscii: TITLE_FONT_ASCII,
|
||||
size: TITLE_FONT_SIZE,
|
||||
bold: true,
|
||||
kern: FONT_KERN_MIN_XIAO_ER
|
||||
})
|
||||
],
|
||||
logoImageData
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
function createMissingTitleParagraph() {
|
||||
function createMissingTitleParagraph(logoImageData) {
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: TITLE_PARAGRAPH_SPACING,
|
||||
widowControl: false,
|
||||
overflowPunctuation: true,
|
||||
autoSpaceEastAsianText: true,
|
||||
children: [
|
||||
createStyledTextRun(MISSING_DATA_PLACEHOLDER, {
|
||||
fontEastAsia: TITLE_FONT_EAST_ASIA,
|
||||
fontAscii: TITLE_FONT_ASCII,
|
||||
size: TITLE_FONT_SIZE,
|
||||
bold: true,
|
||||
color: MISSING_DATA_COLOR,
|
||||
kern: FONT_KERN_MIN_XIAO_ER
|
||||
})
|
||||
]
|
||||
children: buildTitleParagraphChildren(
|
||||
[
|
||||
createStyledTextRun(MISSING_DATA_PLACEHOLDER, {
|
||||
fontEastAsia: TITLE_FONT_EAST_ASIA,
|
||||
fontAscii: TITLE_FONT_ASCII,
|
||||
size: TITLE_FONT_SIZE,
|
||||
bold: true,
|
||||
color: MISSING_DATA_COLOR,
|
||||
kern: FONT_KERN_MIN_XIAO_ER
|
||||
})
|
||||
],
|
||||
logoImageData
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
function createManuscriptTitleParagraph(headerData) {
|
||||
function createManuscriptTitleParagraph(headerData, logoImageData) {
|
||||
const text = resolveManuscriptDisplayTitle(headerData);
|
||||
return text ? createAuthorTitleParagraph(text) : createMissingTitleParagraph();
|
||||
return text
|
||||
? createAuthorTitleParagraph(text, logoImageData)
|
||||
: createMissingTitleParagraph(logoImageData);
|
||||
}
|
||||
|
||||
function stripParagraphPropertyTag(pPrInner, tagName) {
|
||||
@@ -1623,7 +1671,8 @@ export function buildMinimalManuscriptHeaderData(pArticleId) {
|
||||
previewAuthor: null,
|
||||
journal: null,
|
||||
organList: [],
|
||||
finalReview: null
|
||||
finalReview: null,
|
||||
stageInfo: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2148,6 +2197,96 @@ function patchMetadataTableBlock(tblBlock) {
|
||||
return block;
|
||||
}
|
||||
|
||||
function isHomePageSingleColumnSectPrInner(sectPrInner) {
|
||||
return /<w:cols\b[^>]*\bw:num="1"/i.test(String(sectPrInner || '')) && !/<w:cols\b[^>]*\bw:num="2"/i.test(String(sectPrInner || ''));
|
||||
}
|
||||
|
||||
function isHomePageDualColumnSectPrInner(sectPrInner) {
|
||||
return /<w:cols\b[^>]*\bw:num="2"/i.test(String(sectPrInner || ''));
|
||||
}
|
||||
|
||||
function replaceSectPrInnerColsWithSingle(sectPrInner) {
|
||||
let next = String(sectPrInner || '')
|
||||
.replace(/<w:cols\b[^>]*\/>/g, '')
|
||||
.replace(/<w:cols\b[^>]*>[\s\S]*?<\/w:cols>/g, '');
|
||||
return next + '<w:cols w:num="1"/>';
|
||||
}
|
||||
|
||||
/** 首页元数据表格节结束位置:含表格后空行,不含正文双栏分节符 */
|
||||
export function findHomePageMetadataTableSectionEndIndex(xml, bounds) {
|
||||
if (!bounds) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let end = bounds.end;
|
||||
let cursor = bounds.end;
|
||||
const limit = Math.min(xml.length, bounds.end + 8000);
|
||||
|
||||
while (cursor < limit) {
|
||||
const slice = xml.slice(cursor, limit);
|
||||
const match = slice.match(/^\s*(<w:p\b[^>]*>[\s\S]*?<\/w:p>)/);
|
||||
if (!match) {
|
||||
break;
|
||||
}
|
||||
|
||||
const block = match[1];
|
||||
const blockEnd = cursor + match[0].length;
|
||||
const sectMatch = block.match(/<w:sectPr>([\s\S]*?)<\/w:sectPr>/);
|
||||
|
||||
if (sectMatch && isHomePageDualColumnSectPrInner(sectMatch[1])) {
|
||||
break;
|
||||
}
|
||||
|
||||
end = blockEnd;
|
||||
cursor = blockEnd;
|
||||
|
||||
if (sectMatch) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (/\bIntroduction\b/i.test(block) || /<v:roundrect\b[^>]*fillcolor="#DEEBF7"/i.test(block)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
/** 强制首页元数据表格(Abstract 等)所在节为单栏 */
|
||||
export function patchHomePageMetadataTableSingleColumnToXml(xml) {
|
||||
let bounds = findHomePageMetadataTableBounds(xml);
|
||||
if (!bounds) {
|
||||
return xml;
|
||||
}
|
||||
|
||||
let result = xml;
|
||||
const beforeTableSlice = result.slice(Math.max(0, bounds.start - 8000), bounds.start);
|
||||
const hasSingleBreakBeforeTable = /<w:sectPr>[\s\S]*?<w:cols\b[^>]*\bw:num="1"/i.test(beforeTableSlice);
|
||||
|
||||
if (!hasSingleBreakBeforeTable) {
|
||||
const breakXml = buildHomePageSectionBreakParagraphXml(buildHomePageContinuousSectPrInner());
|
||||
result = result.slice(0, bounds.start) + breakXml + result.slice(bounds.start);
|
||||
bounds = findHomePageMetadataTableBounds(result);
|
||||
if (!bounds) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const corrMatch = findCorrespondenceParagraphMatch(result);
|
||||
const regionStart = corrMatch ? corrMatch.index + corrMatch[0].length : 0;
|
||||
const tableSectionEnd = findHomePageMetadataTableSectionEndIndex(result, bounds);
|
||||
|
||||
return result.replace(/<w:sectPr>([\s\S]*?)<\/w:sectPr>/g, function (full, inner, offset) {
|
||||
if (offset < regionStart || offset >= tableSectionEnd) {
|
||||
return full;
|
||||
}
|
||||
if (isHomePageSingleColumnSectPrInner(inner)) {
|
||||
return full;
|
||||
}
|
||||
return '<w:sectPr>' + replaceSectPrInnerColsWithSingle(inner) + '</w:sectPr>';
|
||||
});
|
||||
}
|
||||
|
||||
function buildHomePageContinuousSectPrInner() {
|
||||
const grid = getDocumentGridProperties();
|
||||
return (
|
||||
@@ -2165,7 +2304,11 @@ function buildHomePageContinuousSectPrInner() {
|
||||
PAGE_MARGINS.bottom +
|
||||
'" w:left="' +
|
||||
PAGE_MARGINS.left +
|
||||
'" w:header="708" w:footer="708" w:gutter="0"/>' +
|
||||
'" w:header="' +
|
||||
PAGE_HEADER_MARGIN_TWIPS +
|
||||
'" w:footer="' +
|
||||
PAGE_FOOTER_MARGIN_TWIPS +
|
||||
'" w:gutter="0"/>' +
|
||||
'<w:pgNumType/>' +
|
||||
'<w:cols w:num="1"/>' +
|
||||
'<w:docGrid w:linePitch="' +
|
||||
@@ -2219,9 +2362,9 @@ function patchSectPrBetweenCorrespondenceAndHomePageTable(xml) {
|
||||
return xml;
|
||||
}
|
||||
|
||||
const continuousSectPrInner = buildHomePageContinuousSectPrInner();
|
||||
const singleSectPrInner = buildHomePageContinuousSectPrInner();
|
||||
const between = xml.slice(start, tblIdx).replace(/<w:sectPr>[\s\S]*?<\/w:sectPr>/g, function () {
|
||||
return '<w:sectPr>' + continuousSectPrInner + '</w:sectPr>';
|
||||
return '<w:sectPr>' + singleSectPrInner + '</w:sectPr>';
|
||||
});
|
||||
|
||||
return xml.slice(0, start) + between + xml.slice(tblIdx);
|
||||
@@ -2249,11 +2392,11 @@ function patchCorrespondenceDoubleSectionBreaks(xml) {
|
||||
return patchSectPrBetweenCorrespondenceAndHomePageTable(xml);
|
||||
}
|
||||
|
||||
const continuousSectPrInner = buildHomePageContinuousSectPrInner();
|
||||
const singleSectPrInner = buildHomePageContinuousSectPrInner();
|
||||
const doubleBreakBlock =
|
||||
buildHomePageSectionBreakParagraphXml(continuousSectPrInner) +
|
||||
buildHomePageSectionBreakParagraphXml(singleSectPrInner) +
|
||||
buildHomePageEmptyLineParagraphXml() +
|
||||
buildHomePageSectionBreakParagraphXml(continuousSectPrInner);
|
||||
buildHomePageSectionBreakParagraphXml(singleSectPrInner);
|
||||
|
||||
return xml.slice(0, start) + doubleBreakBlock + xml.slice(tblIdx);
|
||||
}
|
||||
@@ -2291,19 +2434,57 @@ export async function patchHomePageDoubleSectionBreaks(blob) {
|
||||
});
|
||||
}
|
||||
|
||||
function isHomePageMetadataTableBlock(block) {
|
||||
const text = String(block || '');
|
||||
return /Author/i.test(text) && /contributions/i.test(text) && /Abstract/i.test(text);
|
||||
}
|
||||
|
||||
/** 线性扫描定位首页表格(Abstract + Author contributions),避免全文正则灾难性回溯 */
|
||||
export function findHomePageMetadataTableBounds(xml) {
|
||||
if (!xml || !/Author/i.test(xml) || !/contributions/i.test(xml) || !/Abstract/.test(xml)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tblToken = '<w:tbl';
|
||||
const closeTag = '</w:tbl>';
|
||||
let searchFrom = 0;
|
||||
|
||||
while (searchFrom < xml.length) {
|
||||
const tblStart = xml.indexOf(tblToken, searchFrom);
|
||||
if (tblStart < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tblEnd = xml.indexOf(closeTag, tblStart);
|
||||
if (tblEnd < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tblEndExclusive = tblEnd + closeTag.length;
|
||||
const block = xml.slice(tblStart, tblEndExclusive);
|
||||
if (isHomePageMetadataTableBlock(block)) {
|
||||
return {
|
||||
start: tblStart,
|
||||
end: tblEndExclusive,
|
||||
block: block
|
||||
};
|
||||
}
|
||||
|
||||
searchFrom = tblEndExclusive;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 补齐元数据表格(Abstract + Author contributions)Word 表格属性(图五) */
|
||||
export function patchMetadataTablePropertiesToXml(xml) {
|
||||
if (!xml || !/Author/i.test(xml) || !/contributions/i.test(xml) || !/Abstract/.test(xml)) {
|
||||
const bounds = findHomePageMetadataTableBounds(xml);
|
||||
if (!bounds) {
|
||||
return xml;
|
||||
}
|
||||
|
||||
const match = xml.match(/<w:tbl\b[\s\S]*?>[\s\S]*?Author[\s\S]*?contributions[\s\S]*?Abstract[\s\S]*?<\/w:tbl>/i);
|
||||
if (!match || match.index == null) {
|
||||
return xml;
|
||||
}
|
||||
|
||||
const patched = patchMetadataTableBlock(match[0]);
|
||||
return xml.slice(0, match.index) + patched + xml.slice(match.index + match[0].length);
|
||||
const patched = patchMetadataTableBlock(bounds.block);
|
||||
return xml.slice(0, bounds.start) + patched + xml.slice(bounds.end);
|
||||
}
|
||||
|
||||
/** 补齐元数据表格(Abstract + Author contributions)Word 表格属性(图五) */
|
||||
@@ -2329,7 +2510,7 @@ export async function patchMetadataTableProperties(blob) {
|
||||
}
|
||||
|
||||
function buildHomePageTableSectionChildren(headerData) {
|
||||
return [buildMetadataTable(headerData), createHeaderBlockEmptyLineParagraph(EMPTY_LINE_AFTER_AFFILIATION)];
|
||||
return [buildMetadataTable(headerData)];
|
||||
}
|
||||
|
||||
function buildMetadataSectionChildren(headerData) {
|
||||
@@ -2340,14 +2521,18 @@ function buildMetadataColumnChildren(headerData) {
|
||||
return buildMetadataSectionChildren(headerData);
|
||||
}
|
||||
|
||||
function buildTitleBlockChildren(headerData, orcidImageData) {
|
||||
function buildTitleBlockChildren(headerData, orcidImageData, tmrLogoImageData) {
|
||||
const children = [];
|
||||
const previewAuthor = headerData.previewAuthor || {};
|
||||
const authors = headerData.authors || [];
|
||||
const organIndexMap = buildOrganIndexMap(headerData.organList || []);
|
||||
const addressList = getAddressList(headerData);
|
||||
|
||||
pushTitleBlockModule(children, createManuscriptTitleParagraph(headerData), EMPTY_LINE_AFTER_TITLE);
|
||||
pushTitleBlockModule(
|
||||
children,
|
||||
createManuscriptTitleParagraph(headerData, tmrLogoImageData),
|
||||
EMPTY_LINE_AFTER_TITLE
|
||||
);
|
||||
|
||||
let authorParagraph = null;
|
||||
if (authors.length) {
|
||||
@@ -2392,12 +2577,12 @@ function buildTitleBlockChildren(headerData, orcidImageData) {
|
||||
return children;
|
||||
}
|
||||
|
||||
export function buildAuthorHeaderSectionGroups(headerData, orcidImageData) {
|
||||
export function buildAuthorHeaderSectionGroups(headerData, orcidImageData, tmrLogoImageData) {
|
||||
if (!headerData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const titleBlockChildren = buildTitleBlockChildren(headerData, orcidImageData);
|
||||
const titleBlockChildren = buildTitleBlockChildren(headerData, orcidImageData, tmrLogoImageData);
|
||||
if (!titleBlockChildren.length) {
|
||||
return [];
|
||||
}
|
||||
@@ -2407,7 +2592,7 @@ export function buildAuthorHeaderSectionGroups(headerData, orcidImageData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/** 首页:标题块 → 2 个连续分节符(中间空行 ¶)→ 首页表格(一栏)→ 连续分节符 → 正文双栏 */
|
||||
/** 首页:标题块(单栏)→ 连续分节符 → 首页元数据表格(单栏)→ 连续分节符 → 正文双栏 */
|
||||
return [
|
||||
{
|
||||
columnCount: 1,
|
||||
|
||||
Reference in New Issue
Block a user