添加期刊引用分析
This commit is contained in:
377
src/utils/exportManuscriptAuthor.js
Normal file
377
src/utils/exportManuscriptAuthor.js
Normal file
@@ -0,0 +1,377 @@
|
||||
import { AlignmentType, ImageRun, Paragraph, TextRun } from 'docx';
|
||||
import { htmlToPlainText, TABLE_FONT_SIZE, WORD_PARAGRAPH_SPACING } from '@/utils/exportTableWord';
|
||||
import orcidIconUrl from '@/assets/img/orcid.png';
|
||||
|
||||
/** 作者区字体 Calibri 六号(7.5pt) */
|
||||
const AUTHOR_FONT_NAME = 'Calibri';
|
||||
/** 标题略大 */
|
||||
const AUTHOR_TITLE_FONT_SIZE = 24;
|
||||
/** 上标 rgb(0, 112, 192) */
|
||||
const AUTHOR_SUPER_COLOR = '0070C0';
|
||||
const ORCID_ICON_SIZE = 13;
|
||||
|
||||
let orcidImageCache = null;
|
||||
|
||||
export async function loadOrcidImageData() {
|
||||
if (orcidImageCache) {
|
||||
return orcidImageCache;
|
||||
}
|
||||
if (typeof fetch === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const response = await fetch(orcidIconUrl);
|
||||
const buffer = await response.arrayBuffer();
|
||||
orcidImageCache = new Uint8Array(buffer);
|
||||
return orcidImageCache;
|
||||
}
|
||||
|
||||
export async function fetchManuscriptHeaderData(apiClient, articleId, pArticleId, resolvePArticleId) {
|
||||
if (!apiClient) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const resolvedId = await resolvePArticleId(apiClient, articleId, pArticleId);
|
||||
if (!resolvedId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const idPayload = { p_article_id: resolvedId };
|
||||
const results = await Promise.all([
|
||||
apiClient.post('api/Production/getProductionDetail', idPayload).catch(function () {
|
||||
return null;
|
||||
}),
|
||||
apiClient.post('api/Production/getAuthorlist', idPayload).catch(function () {
|
||||
return null;
|
||||
}),
|
||||
apiClient.post('api/Production/getProductionPreview', idPayload).catch(function () {
|
||||
return null;
|
||||
})
|
||||
]);
|
||||
|
||||
const detailRes = results[0];
|
||||
const authorListRes = results[1];
|
||||
const previewRes = results[2];
|
||||
|
||||
const production =
|
||||
detailRes && detailRes.code == 0 && detailRes.data && detailRes.data.production
|
||||
? detailRes.data.production
|
||||
: null;
|
||||
const authors =
|
||||
authorListRes && authorListRes.code == 0 && authorListRes.data && authorListRes.data.authors
|
||||
? authorListRes.data.authors
|
||||
: [];
|
||||
const previewAuthor =
|
||||
previewRes && previewRes.code == 0 && previewRes.data && previewRes.data.author ? previewRes.data.author : null;
|
||||
|
||||
if (!production && !authors.length && !previewAuthor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
pArticleId: resolvedId,
|
||||
production: production,
|
||||
authors: authors,
|
||||
previewAuthor: previewAuthor
|
||||
};
|
||||
}
|
||||
|
||||
function createAuthorTextRun(text, options) {
|
||||
const opts = options || {};
|
||||
const runOptions = {
|
||||
text: text || '',
|
||||
font: AUTHOR_FONT_NAME,
|
||||
size: TABLE_FONT_SIZE
|
||||
};
|
||||
|
||||
if (opts.bold) {
|
||||
runOptions.bold = true;
|
||||
}
|
||||
if (opts.italics) {
|
||||
runOptions.italics = true;
|
||||
}
|
||||
if (opts.superScript) {
|
||||
runOptions.superScript = true;
|
||||
}
|
||||
if (opts.color) {
|
||||
runOptions.color = opts.color;
|
||||
}
|
||||
if (opts.size) {
|
||||
runOptions.size = opts.size;
|
||||
}
|
||||
|
||||
return new TextRun(runOptions);
|
||||
}
|
||||
|
||||
function createOrcidImageRun(orcidImageData) {
|
||||
if (!orcidImageData) {
|
||||
return createAuthorTextRun('');
|
||||
}
|
||||
|
||||
return new ImageRun({
|
||||
type: 'png',
|
||||
data: orcidImageData,
|
||||
transformation: {
|
||||
width: ORCID_ICON_SIZE,
|
||||
height: ORCID_ICON_SIZE
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 与排版预览一致:<q> 转上标,作者之间加空格 */
|
||||
function preparePreviewAuthorHtml(html) {
|
||||
let text = String(html || '');
|
||||
text = text.replace(/<q>/gi, '<sup>');
|
||||
text = text.replace(/<\/q>/gi, '</sup>');
|
||||
text = text.replace(/<\/sup>,/gi, '</sup>, ');
|
||||
text = text.replace(/<span[^>]*margin-left:\s*8px[^>]*>\s*<\/span>/gi, ' ');
|
||||
text = text.replace(/,\s*$/, '');
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
function decodeAuthorHtmlEntities(text) {
|
||||
return String(text || '')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function htmlToAuthorLineRuns(html, orcidImageData, isAuthorNameLine) {
|
||||
const runs = [];
|
||||
const raw = String(html || '');
|
||||
|
||||
if (!raw) {
|
||||
return runs;
|
||||
}
|
||||
|
||||
if (typeof document === 'undefined') {
|
||||
runs.push(
|
||||
createAuthorTextRun(htmlToPlainText(raw), {
|
||||
bold: !!isAuthorNameLine
|
||||
})
|
||||
);
|
||||
return runs;
|
||||
}
|
||||
|
||||
const root = document.createElement('div');
|
||||
root.innerHTML = raw;
|
||||
|
||||
function appendRun(text, style) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
runs.push(
|
||||
createAuthorTextRun(text, {
|
||||
bold: style.bold,
|
||||
italics: style.italic,
|
||||
superScript: style.super,
|
||||
color: style.color
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function walk(node, style) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
appendRun(decodeAuthorHtmlEntities(node.textContent).replace(/\u00a0/g, ' '), style);
|
||||
return;
|
||||
}
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tag = node.tagName.toLowerCase();
|
||||
if (tag === 'br') {
|
||||
return;
|
||||
}
|
||||
if (tag === 'img') {
|
||||
runs.push(createOrcidImageRun(orcidImageData));
|
||||
return;
|
||||
}
|
||||
if (tag === 'span' && !node.textContent.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextStyle = {
|
||||
bold: style.bold,
|
||||
italic: style.italic,
|
||||
super: style.super,
|
||||
color: style.color
|
||||
};
|
||||
|
||||
if (tag === 'b' || tag === 'strong') {
|
||||
nextStyle.bold = true;
|
||||
}
|
||||
if (tag === 'i' || tag === 'em') {
|
||||
nextStyle.italic = true;
|
||||
}
|
||||
if (tag === 'sup') {
|
||||
nextStyle.super = true;
|
||||
nextStyle.bold = false;
|
||||
nextStyle.color = AUTHOR_SUPER_COLOR;
|
||||
}
|
||||
|
||||
Array.from(node.childNodes).forEach(function (child) {
|
||||
walk(child, nextStyle);
|
||||
});
|
||||
}
|
||||
|
||||
walk(root, {
|
||||
bold: !!isAuthorNameLine,
|
||||
italic: false,
|
||||
super: false,
|
||||
color: undefined
|
||||
});
|
||||
|
||||
if (!runs.length) {
|
||||
runs.push(
|
||||
createAuthorTextRun(htmlToPlainText(raw), {
|
||||
bold: !!isAuthorNameLine
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return runs;
|
||||
}
|
||||
|
||||
function buildAuthorHtmlParagraphs(authorHtml, orcidImageData) {
|
||||
const prepared = preparePreviewAuthorHtml(authorHtml);
|
||||
const segments = prepared.split(/<br\s*\/?>/gi).filter(function (segment) {
|
||||
return htmlToPlainText(segment).trim();
|
||||
});
|
||||
|
||||
if (!segments.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return segments.map(function (segment, index) {
|
||||
const isAuthorNameLine = index === 0;
|
||||
const runs = htmlToAuthorLineRuns(segment, orcidImageData, isAuthorNameLine);
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: WORD_PARAGRAPH_SPACING,
|
||||
children: runs.length ? runs : [createAuthorTextRun('')]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function buildAuthorListFallbackParagraph(authors, orcidImageData) {
|
||||
const runs = [];
|
||||
const list = (authors || []).filter(Boolean);
|
||||
|
||||
list.forEach(function (author, index) {
|
||||
if (index > 0) {
|
||||
runs.push(createAuthorTextRun(', '));
|
||||
}
|
||||
|
||||
const name =
|
||||
author.author_name ||
|
||||
String((author.first_name || '') + ' ' + (author.last_name || '')).trim();
|
||||
runs.push(createAuthorTextRun(name, { bold: true }));
|
||||
|
||||
const marks = [];
|
||||
if (author.is_first == 1 || author.is_first == '1') {
|
||||
marks.push('#');
|
||||
}
|
||||
if (author.is_report == 1 || author.is_report == '1') {
|
||||
marks.push('*');
|
||||
}
|
||||
if (marks.length) {
|
||||
runs.push(
|
||||
createAuthorTextRun(marks.join(''), {
|
||||
superScript: true,
|
||||
color: AUTHOR_SUPER_COLOR
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (author.orcid && String(author.orcid).trim()) {
|
||||
runs.push(createOrcidImageRun(orcidImageData));
|
||||
}
|
||||
});
|
||||
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: WORD_PARAGRAPH_SPACING,
|
||||
children: runs.length ? runs : [createAuthorTextRun('')]
|
||||
});
|
||||
}
|
||||
|
||||
function createAffiliationParagraph(index, addressText) {
|
||||
const text = String(addressText || '').trim();
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: WORD_PARAGRAPH_SPACING,
|
||||
children: [
|
||||
createAuthorTextRun(String(index + 1), {
|
||||
superScript: true,
|
||||
color: AUTHOR_SUPER_COLOR
|
||||
}),
|
||||
createAuthorTextRun(' ' + text)
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createAuthorTitleParagraph(title) {
|
||||
const text = String(title || '').trim();
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: WORD_PARAGRAPH_SPACING,
|
||||
children: [
|
||||
createAuthorTextRun(text, {
|
||||
bold: true,
|
||||
size: AUTHOR_TITLE_FONT_SIZE
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export function buildAuthorHeaderSectionChildren(headerData, orcidImageData) {
|
||||
if (!headerData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const children = [];
|
||||
const production = headerData.production || {};
|
||||
const previewAuthor = headerData.previewAuthor || {};
|
||||
const titleParagraph = createAuthorTitleParagraph(htmlToPlainText(production.title || ''));
|
||||
|
||||
if (titleParagraph) {
|
||||
children.push(titleParagraph);
|
||||
}
|
||||
|
||||
if (previewAuthor && previewAuthor.author) {
|
||||
buildAuthorHtmlParagraphs(previewAuthor.author, orcidImageData).forEach(function (paragraph) {
|
||||
children.push(paragraph);
|
||||
});
|
||||
} else if (headerData.authors && headerData.authors.length) {
|
||||
children.push(buildAuthorListFallbackParagraph(headerData.authors, orcidImageData));
|
||||
}
|
||||
|
||||
const addressList = (previewAuthor && previewAuthor.addressList) || [];
|
||||
addressList.forEach(function (address, index) {
|
||||
const paragraph = createAffiliationParagraph(index, htmlToPlainText(address));
|
||||
if (paragraph) {
|
||||
children.push(paragraph);
|
||||
}
|
||||
});
|
||||
|
||||
if (children.length) {
|
||||
children.push(
|
||||
new Paragraph({
|
||||
spacing: WORD_PARAGRAPH_SPACING,
|
||||
children: [createAuthorTextRun('')]
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
Reference in New Issue
Block a user