相关性代码调整

This commit is contained in:
2026-06-24 16:52:24 +08:00
parent 5a1bbb0894
commit 5260ca8ea5
29 changed files with 6330 additions and 568 deletions

View File

@@ -2,14 +2,14 @@
//记得切换
//正式
const mediaUrl = '/public/';
const baseUrl = '/';
// const mediaUrl = '/public/';
// const baseUrl = '/';
//正式环境
// const mediaUrl = 'https://submission.tmrjournals.com/public/';
// // const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
// const baseUrl = '/api'
const mediaUrl = 'https://submission.tmrjournals.com/public/';
// const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
const baseUrl = '/api'
//测试环境

View File

@@ -382,7 +382,9 @@ const en = {
unsubscribeSwitchOff: 'Subscribed',
unsubscribeMissingId: 'Missing expert ID, unable to switch unsubscribe status',
unsubscribeUpdateSuccess: 'Unsubscribe status updated',
unsubscribeUpdateFailed: 'Failed to update unsubscribe status'
unsubscribeUpdateFailed: 'Failed to update unsubscribe status',
lastContactTime: 'Last contact time: {time}',
lastContactTimeEmpty: 'No contact record'
},
countryManagement: {
title: 'Country Management',
@@ -1146,10 +1148,12 @@ const en = {
AnnotationList: 'Annotation List',
Annotations: 'Comments',
exportWord: 'Generate Word file',
exportWordShort: 'Word',
exportManuscriptEmpty: 'No content to export.',
exportManuscriptSuccess: 'Word downloaded.',
exportManuscriptFail: 'Failed to export Word.',
citeRelevanceDetect: 'Download relevance HTML',
citeRelevanceDetectShort: 'Relevance',
citeRelevanceTitle: 'Citation relevance check',
citeRelevanceTitleProgress: 'Citation relevance ({current}/{total})',
citeRelevanceEmpty: 'No citations to review.',
@@ -1182,8 +1186,34 @@ const en = {
citeRelevanceCopyGroup: 'Copy paragraph',
citeRelevanceDownloadHtml: 'Download HTML',
citeRelevanceDownloadHtmlSuccess: 'HTML downloaded',
refHtmlCopy: 'Copy references',
refHtmlCopyShort: 'Copy',
refHtmlCopySuccess: 'References copied (numbering, italic journal, blue DOI, Available at line break)',
parseBookReference: 'Parse Book',
parseBookReferenceSuccess: 'Book fields parsed successfully',
parseBookReferenceEmpty: 'Could not parse book from Content. Expected: Author. Title. Publication Details. ISBN',
parseBookReferenceContentEmpty: 'Content cannot be empty',
refHtmlDownload: 'Download references HTML',
refHtmlDownloadSuccess: 'References HTML downloaded',
refHtmlDownloadShort: 'Ref HTML',
refHtmlDownloadSuccess: 'References HTML downloaded. After editing, click "Upload references" then "Generate Word file".',
refHtmlUpload: 'Upload references',
refHtmlUploadShort: 'Upload',
refHtmlUploadSuccess: '{n} reference(s) loaded. Click "Generate Word file".',
refHtmlUploadConfirm: 'Confirm load',
refHtmlUploadLoadedTip: '{n} reference(s) loaded — click "Generate Word file" to export',
exportWordWithUploadedRefs: 'Generate Word with {n} uploaded reference(s)',
exportWordWithUploadedRefsSuccess: 'Word generated with {n} uploaded reference(s)',
refHtmlPaste: 'Paste references',
refHtmlPasteTitle: 'Paste full references',
refHtmlPasteTip: 'Paste the complete references below — no need to edit one by one. Separate entries with blank lines or numbering (1. 2. …); HTML tags such as <i> are supported.',
refHtmlPastePlaceholder: 'Paste full references here…',
refHtmlPasteParsed: '{n} reference(s) detected',
refHtmlPasteParseEmpty: 'No references detected. Use the format from "Copy references" (1. 2. numbering + Available at line break).',
refHtmlPasteExport: 'Export Word',
refHtmlPasteCancel: 'Cancel',
refHtmlImportHtml: 'Import HTML file',
refHtmlImportSuccess: 'Imported into the editor. Click "Export Word" when ready.',
refHtmlBulkHint: 'Edit all references as one block, or paste AI output here. Separate entries with blank lines or 1. 2. numbering.',
refHtmlToWord: 'References HTML to Word',
refHtmlToWordSuccess: 'Word exported with edited references',
refHtmlToWordFail: 'Failed to convert references HTML to Word',
@@ -1192,8 +1222,8 @@ const en = {
refHtmlParseEmpty: 'No reference entries found in HTML. Please use the HTML downloaded from this system.',
refHtmlPageTitle: 'References editor',
refHtmlReferencesTitle: 'References',
refHtmlIntro: 'Edit each reference directly, or paste AI output (supports <i> italics and other HTML). When done, click "Download edited HTML", then use "References HTML to Word" on the typesetting page.',
refHtmlSaveTip: 'Tip: save the HTML after editing, then import it on the typesetting page to export Word.',
refHtmlIntro: 'Download to edit all references in one block, or paste AI output (supports <i> italics and other HTML). Save the HTML when done, or use "Paste references" on the typesetting page to export Word.',
refHtmlSaveTip: 'Tip: save the HTML after editing the full block, or copy the content and use "Paste references" on the typesetting page.',
refHtmlDownloadEdited: 'Download edited HTML',
refHtmlDownloadFileName: 'references-edited.html',
exportImg: 'Export PNG',
@@ -1264,6 +1294,8 @@ const en = {
Row: "Row",
addRow: "Add Row",
Uncheck: 'Uncheck the paragraph',
selectAll: 'Select All',
selectAllShort: 'All',
ManuscirptAIProofreading: 'Manuscript AI Proofreading',
AIProofreading: 'AI Proofreading',
Association: 'Association',

View File

@@ -371,7 +371,9 @@ const zh = {
unsubscribeSwitchOff: '已订阅',
unsubscribeMissingId: '缺少专家 ID无法切换退订状态',
unsubscribeUpdateSuccess: '退订状态更新成功',
unsubscribeUpdateFailed: '退订状态更新失败'
unsubscribeUpdateFailed: '退订状态更新失败',
lastContactTime: '最近一次联系时间:{time}',
lastContactTimeEmpty: '暂无联系记录'
},
countryManagement: {
title: '国家信息维护',
@@ -1132,10 +1134,12 @@ const zh = {
AnnotationList: '批注列表',
Annotations: '批注',
exportWord: '生成 Word 文件',
exportWordShort: 'Word',
exportManuscriptEmpty: '没有可导出的内容。',
exportManuscriptSuccess: 'Word 已下载。',
exportManuscriptFail: 'Word 导出失败。',
citeRelevanceDetect: '下载相关性 HTML',
citeRelevanceDetectShort: '相关性',
citeRelevanceTitle: '引文相关性核查',
citeRelevanceTitleProgress: '引文相关性核查 ({current}/{total})',
citeRelevanceEmpty: '当前没有可核查的引文。',
@@ -1168,8 +1172,34 @@ const zh = {
citeRelevanceCopyGroup: '复制本段',
citeRelevanceDownloadHtml: '下载 HTML',
citeRelevanceDownloadHtmlSuccess: 'HTML 已下载',
refHtmlCopy: '复制参考文献',
refHtmlCopyShort: '复制',
refHtmlCopySuccess: '参考文献已复制(含编号、期刊斜体、蓝色 DOI、Available at 换行)',
parseBookReference: '解析书籍',
parseBookReferenceSuccess: '书籍字段已按规则解析',
parseBookReferenceEmpty: '无法从 Content 中解析书籍信息请检查格式Author. Title. Publication Details. ISBN',
parseBookReferenceContentEmpty: 'Content 不能为空',
refHtmlDownload: '下载参考文献 HTML',
refHtmlDownloadSuccess: '参考文献 HTML 已下载',
refHtmlDownloadShort: 'Ref HTML',
refHtmlDownloadSuccess: '参考文献 HTML 已下载,改完后请点「上传参考文献」再点「生成 Word 文件」',
refHtmlUpload: '上传参考文献',
refHtmlUploadShort: '上传',
refHtmlUploadSuccess: '已加载 {n} 条参考文献,请点击「生成 Word 文件」',
refHtmlUploadConfirm: '确认加载',
refHtmlUploadLoadedTip: '已加载 {n} 条参考文献,点击「生成 Word 文件」导出',
exportWordWithUploadedRefs: '将使用已上传的 {n} 条参考文献生成 Word',
exportWordWithUploadedRefsSuccess: 'Word 已生成(含上传的 {n} 条参考文献)',
refHtmlPaste: '粘贴参考文献',
refHtmlPasteTitle: '粘贴完整参考文献',
refHtmlPasteTip: '将整段参考文献粘贴到下方即可,无需逐条修改。支持 1. 2. 编号分隔,或条目之间空一行;也支持 <i> 斜体等 HTML 标签。',
refHtmlPastePlaceholder: '在此粘贴完整参考文献内容…',
refHtmlPasteParsed: '已识别 {n} 条参考文献',
refHtmlPasteParseEmpty: '暂未识别到参考文献请使用「复制参考文献」的格式1. 2. 编号 + Available at 换行)',
refHtmlPasteExport: '导出 Word',
refHtmlPasteCancel: '取消',
refHtmlImportHtml: '从 HTML 文件导入',
refHtmlImportSuccess: '已导入到编辑框,确认后点击「导出 Word」',
refHtmlBulkHint: '以下为整段参考文献,可整体替换或粘贴 AI 返回的完整内容;条目之间用空行或 1. 2. 编号分隔。',
refHtmlToWord: '参考文献 HTML 转 Word',
refHtmlToWordSuccess: 'Word 已导出(含编辑后的参考文献)',
refHtmlToWordFail: '参考文献 HTML 转 Word 失败',
@@ -1178,8 +1208,8 @@ const zh = {
refHtmlParseEmpty: 'HTML 中未找到参考文献条目,请使用本系统下载的参考文献 HTML',
refHtmlPageTitle: '参考文献编辑',
refHtmlReferencesTitle: 'References',
refHtmlIntro: '可直接编辑每条文献,或粘贴 AI 返回的内容(支持 <i> 斜体等 HTML 标签)。编辑完成后点击「下载编辑后的 HTML」,再在排版页使用「参考文献 HTML 转 Word。',
refHtmlSaveTip: '提示:编辑后点击上方按钮保存 HTML也可在排版页导入该文件导出 Word。',
refHtmlIntro: '下载后可在一个大文本框里整体编辑全部参考文献,或粘贴 AI 返回的完整内容(支持 <i> 斜体等 HTML 标签)。编辑完成后保存 HTML,或在排版页使用「粘贴参考文献」导出 Word。',
refHtmlSaveTip: '提示:整段编辑后点击上方按钮保存 HTML也可复制内容后在排版页「粘贴参考文献」导出 Word。',
refHtmlDownloadEdited: '下载编辑后的 HTML',
refHtmlDownloadFileName: 'references-edited.html',
exportImg: '导出 图片',
@@ -1249,6 +1279,8 @@ const zh = {
Row:"空行",
addRow:"新增空行",
Uncheck:'取消勾选段落',
selectAll: '全选',
selectAllShort: '全选',
ManuscirptAIProofreading:'稿件AI校对',
AIProofreading:'AI校对',
Association:'关联',

View File

@@ -416,7 +416,8 @@
type="content"
@openLatexEditor="openLatexEditor"
v-if="addContentVisible"
:enable-import-word-math="true"
:enable-import-word-math="zyModeEnabled"
:article-id="articleId"
ref="addContent"
style="margin-left: -115px"
></common-content>
@@ -445,6 +446,7 @@ import { LATEX_DATA_HTML_DATA, MATH_FORMULA_TABLE_TITLE } from '@/utils/mathForm
import Tinymce from '@/components/page/components/Tinymce';
import bottomTinymce from '@/components/page/components/Tinymce';
import catalogue from '@/components/page/components/table/catalogue.vue';
import { isZyModeEnabled } from '@/utils/zyMode';
export default {
data() {
return {
@@ -578,6 +580,9 @@ export default {
catalogue
},
computed: {
zyModeEnabled() {
return isZyModeEnabled(this.$route);
},
combinedValue() {
// 将两个值组合成一个新的值,可以是字符串、数组、对象等
// return `${this.isFirstComponentLoaded}-${this.isWordComponentLoaded}`;
@@ -726,17 +731,7 @@ export default {
this.saveContent(content, this.currentContent.am_id);
} else if (type == 'addcontent') {
var hasTable = /<table[\s\S]*?>[\s\S]*?<\/table>/i.test(content);
if (hasTable) {
this.$message({
type: 'warning',
message: 'Table content is not supported!'
});
return false;
}
var list = this.$commonJS.cleanAndParseWordContent(content);
this.saveContentList(list, this.currentId);
} else if (type == 'table') {

View File

@@ -726,17 +726,7 @@ export default {
this.saveContent(content, this.currentContent.am_id);
} else if (type == 'addcontent') {
var hasTable = /<table[\s\S]*?>[\s\S]*?<\/table>/i.test(content);
if (hasTable) {
this.$message({
type: 'warning',
message: 'Table content is not supported!'
});
return false;
}
var list = this.$commonJS.cleanAndParseWordContent(content);
this.saveContentList(list, this.currentId);
} else if (type == 'table') {

View File

@@ -1182,7 +1182,7 @@ import {
getAuthorDisplayName,
getAuthorAffiliationPreview
} from '@/utils/productionSubmissionImport';
import { isZyModeEnabled } from '@/utils/zyMode';
import { isZyModeEnabled, isZySkipCheckEnabled } from '@/utils/zyMode';
export default {
data() {
return {
@@ -2892,39 +2892,19 @@ export default {
// 6----创建文章
EstaBlish() {
if (isZySkipCheckEnabled(this.$route)) {
this.doTypeSettingNewDirect();
return;
}
this.$api
.post('api/Production/checkRefer', {
p_article_id: this.p_article_id
})
.then((res) => {
if (res.code == 0) {
const loading = this.$loading({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$api
.post('api/Production/doTypeSettingNew', {
article_id: this.detailMes.article_id
})
.then((res) => {
if (res.code == 0) {
this.getWorldPdf();
this.$message.success('Successfully generated manuscript!');
loading.close();
} else {
this.$message.error(res.msg);
loading.close();
}
})
.catch((err) => {
this.$message.error(err);
loading.close();
});
this.doTypeSettingNewDirect();
} else {
this.$message.error(res.msg);
return;
}
})
.catch((err) => {
@@ -2932,6 +2912,32 @@ export default {
});
},
doTypeSettingNewDirect() {
const loading = this.$loading({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$api
.post('api/Production/doTypeSettingNew', {
article_id: this.detailMes.article_id
})
.then((res) => {
if (res.code == 0) {
this.getWorldPdf();
this.$message.success('Successfully generated manuscript!');
} else {
this.$message.error(res.msg);
}
loading.close();
})
.catch((err) => {
this.$message.error(err);
loading.close();
});
},
// 6----校对文章
htmlContet() {
this.$api

View File

@@ -11,6 +11,7 @@ import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; //
import html2canvas from 'html2canvas';
import { extractHexImagesFromRTF, hexToBlob } from '@/utils/rtfParser';
import { tableStyle } from '@/utils/tinymceStyles';
import { normalizeEditorPasteHtml, isStructuredDataTable, normalizeSpacesAroundBlueTags } from '@/utils/wordMathImport';
export default {
name: 'tinymce',
components: {},
@@ -63,6 +64,11 @@ export default {
},
articleId: {
default: ''
},
/** Word 批量导入:保留 base64 图片,不自动上传 */
keepInlineImages: {
type: Boolean,
default: false
}
},
data() {
@@ -698,6 +704,8 @@ export default {
plugins: 'texttransform noneditable table image', // 启用 forecolor 和 code 插件
// plugins: 'forecolor code paste table image mathType searchreplace raw', // 启用 forecolor 和 code 插件
end_container_on_empty_block: true,
automatic_uploads: !_this.keepInlineImages,
paste_data_images: true,
content_css: 'default', // 加载 TinyMCE 默认样式表
mathjax: {
// 配置 MathJax 用于渲染数学公式
@@ -707,6 +715,19 @@ export default {
// automatic_uploads: false,
images_upload_handler: function (blobInfo, progress) {
return new Promise((resolve, reject) => {
const inlineUri = blobInfo.blobUri ? blobInfo.blobUri() : '';
if (_this.keepInlineImages && inlineUri && /^data:/i.test(inlineUri)) {
resolve(inlineUri);
return;
}
if (!_this.articleId) {
if (inlineUri) {
resolve(inlineUri);
return;
}
reject('Upload Error: Please select an article');
return;
}
const xhr = new XMLHttpRequest();
const formData = new FormData();
const file = blobInfo.blob();
@@ -926,23 +947,28 @@ export default {
e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>');
});
},
paste_preprocess: function (plugin, args) {
paste_preprocess: function (editor, args) {
let imgIdx = 0;
const silentPlaceholder = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
let content = args.content.replace(/(<img[^>]*?)src="file:\/\/\/[^" ]*"/gi, (match, p1) => {
// 保留 data-idx Word 里的尺寸
let content = String(args.content || '').replace(/(<img[^>]*?)src="file:\/\/\/[^" ]*"/gi, (match, p1) => {
return `${p1}src="${silentPlaceholder}" class="word-img-placeholder" data-idx="${imgIdx++}"`;
});
let tempDiv = document.createElement('div');
tempDiv.innerHTML = content;
if (tempDiv.querySelector('table')) {
if (_this.type == 'table') {
_this.$commonJS.parseTableToArray(content, (tableList) => {
var contentHtml = `
const tableEl = tempDiv.querySelector('table');
const isRealDataTable =
tableEl &&
_this.type === 'table' &&
_this.isAutomaticUpdate &&
isStructuredDataTable(tableEl);
if (isRealDataTable) {
_this.$commonJS.parseTableToArray(content, (tableList) => {
if (!tableList || !tableList.length) return;
const contentHtml = `
<div class="thumbnailTableBox wordTableHtml table_Box table_Box3333" style="">
<table border="1" style="width: auto; border-collapse: collapse; text-align: center;">
${tableList
@@ -965,12 +991,10 @@ export default {
</table>
</div>
`;
const container = document.createElement('div');
container.innerHTML = contentHtml;
args.content = container.innerHTML; // 更新处理后的内容
});
}
const container = document.createElement('div');
container.innerHTML = contentHtml;
args.content = normalizeEditorPasteHtml(container.innerHTML);
});
} else {
const plainText = (tempDiv.textContent || tempDiv.innerText || '').trim();
const builtPlain = _this.buildWmathHtmlFromLatexText(plainText);
@@ -987,18 +1011,18 @@ export default {
}
}
if (args.event) {
args.event.preventDefault();
args.event.stopPropagation();
}
if (_this.isAutomaticUpdate) {
args.content = _this.$commonJS.transformHtmlString(content); // 更新处理后的内容
} else {
args.content = content;
if (!isRealDataTable) {
const normalized = normalizeEditorPasteHtml(content);
if (_this.isAutomaticUpdate) {
args.content = _this.$commonJS.transformHtmlString(normalized);
} else {
args.content = normalized;
}
}
setTimeout(() => {
window.renderMathJax(_this.tinymceId);
if (typeof window.renderMathJax === 'function') {
window.renderMathJax(_this.tinymceId);
}
}, 10);
},
clear_custom_action: (editor, vm) => {
@@ -1101,7 +1125,11 @@ export default {
content = content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
content = content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
content = content.replace(/&nbsp;/g, ' '); // 将所有 &nbsp; 替换为空格
if (type === 'addcontent') {
content = normalizeSpacesAroundBlueTags(content);
} else {
content = content.replace(/&nbsp;/g, ' ');
}
this.$emit('getContent', type, content);
},

View File

@@ -10,6 +10,8 @@
ref="tinymceChild1"
:wordStyle="wordStyle"
:isAutomaticUpdate="isAutomaticUpdate"
:article-id="articleId"
:keep-inline-images="enableImportWordMath"
@getContent="getContent"
@openLatexEditor="openLatexEditor"
@updateChange="updateChange"
@@ -48,6 +50,9 @@ export default {
enableImportWordMath: {
type: Boolean,
default: false
},
articleId: {
default: ''
}
},
components: {
@@ -62,9 +67,9 @@ export default {
if (!this.isAutomaticUpdate) {
groups.push('LateX');
}
// if (this.enableImportWordMath) {
// groups.push('importWordMath');
// }
if (this.enableImportWordMath) {
groups.push('importWordMath');
}
groups.push(
'myuppercase myuppercasea Line MoreSymbols',
'subscript superscript',

View File

@@ -21,6 +21,9 @@
:style="{ '--p-l': '10px', '--p-l': '10px', '--fl-ai': 'center' }"
>
<el-button @click="handleUncheck" v-if="!isPreview" plain type="info">{{ $t('commonTable.Uncheck') }}</el-button>
<el-button @click="handleSelectAll" v-if="!isPreview && zyModeEnabled" plain type="info" size="mini">
<i class="el-icon-circle-check"></i> {{ $t('commonTable.selectAllShort') }}
</el-button>
<div
@click="handleClickAI()"
v-if="isEditComment && !isPreview && activeName == 'proofreading'"
@@ -76,39 +79,78 @@
</li>
<li
v-if="zyModeEnabled"
@click="handleExportManuscriptWord"
class="base-font-size base-bg-imp base-padding-all"
:style="{ '--f-s': '12px', '--f-c': '#333' }"
@click="handleDownloadReferencesHtml"
class="zy-toolbar-btn"
>
<i
class="el-icon-download base-margin"
:style="{ '--m-r': '2px' }"
v-if="!exportingManuscriptWord"
></i>
<i
class="el-icon-loading base-margin"
:style="{ '--m-r': '2px' }"
v-else
></i>
{{ $t('commonTable.exportWord') }}
<el-tooltip :content="$t('commonTable.refHtmlDownload')" placement="bottom">
<span class="zy-toolbar-btn-inner">
<i
class="el-icon-document"
v-if="!referencesHtmlLoading"
></i>
<i class="el-icon-loading" v-else></i>
<span class="zy-toolbar-label">{{ $t('commonTable.refHtmlDownloadShort') }}</span>
</span>
</el-tooltip>
</li>
<li
v-if="zyModeEnabled"
@click="triggerReferencesUpload"
@dblclick.stop="openReferencesPasteDialog"
class="zy-toolbar-btn"
>
<el-tooltip
:content="uploadedReferencesCount ? $t('commonTable.refHtmlUploadLoadedTip', { n: uploadedReferencesCount }) : $t('commonTable.refHtmlUpload')"
placement="bottom"
>
<span class="zy-toolbar-btn-inner">
<i
class="el-icon-upload2"
v-if="!referencesUploadLoading"
></i>
<i class="el-icon-loading" v-else></i>
<span class="zy-toolbar-label">
{{ $t('commonTable.refHtmlUploadShort') }}
<em v-if="uploadedReferencesCount" class="zy-toolbar-badge">({{ uploadedReferencesCount }})</em>
</span>
</span>
</el-tooltip>
</li>
<li
v-if="zyModeEnabled"
@click="handleExportManuscriptWord"
class="zy-toolbar-btn"
:class="{ 'zy-toolbar-btn--ready': uploadedReferencesCount }"
>
<el-tooltip
:content="uploadedReferencesCount ? $t('commonTable.exportWordWithUploadedRefs', { n: uploadedReferencesCount }) : $t('commonTable.exportWord')"
placement="bottom"
>
<span class="zy-toolbar-btn-inner">
<i
class="el-icon-download"
v-if="!exportingManuscriptWord"
></i>
<i class="el-icon-loading" v-else></i>
<span class="zy-toolbar-label">{{ $t('commonTable.exportWordShort') }}</span>
</span>
</el-tooltip>
</li>
<li
v-if="zyModeEnabled"
@click="handleOpenCitationRelevance"
class="base-font-size base-bg-imp base-padding-all"
:style="{ '--f-s': '12px', '--f-c': '#333' }"
class="zy-toolbar-btn"
>
<i
class="el-icon-connection base-margin"
:style="{ '--m-r': '2px' }"
v-if="!citationRelevanceLoading"
></i>
<i
class="el-icon-loading base-margin"
:style="{ '--m-r': '2px' }"
v-else
></i>
{{ $t('commonTable.citeRelevanceDetect') }}
<el-tooltip :content="$t('commonTable.citeRelevanceDetect')" placement="bottom">
<span class="zy-toolbar-btn-inner">
<i
class="el-icon-connection"
v-if="!citationRelevanceLoading"
></i>
<i class="el-icon-loading" v-else></i>
<span class="zy-toolbar-label">{{ $t('commonTable.citeRelevanceDetectShort') }}</span>
</span>
</el-tooltip>
</li>
</ul>
</div>
@@ -1008,6 +1050,43 @@
</el-button>
</span>
</el-dialog>
<el-dialog
append-to-body
destroy-on-close
:title="$t('commonTable.refHtmlPasteTitle')"
:visible.sync="referencesPasteVisible"
width="960px"
:close-on-click-modal="false"
>
<p style="margin: 0 0 12px; color: #606266; font-size: 13px; line-height: 1.6">
{{ $t('commonTable.refHtmlPasteTip') }}
</p>
<el-input
v-model="referencesPasteText"
type="textarea"
:rows="18"
:placeholder="$t('commonTable.refHtmlPastePlaceholder')"
@input="updateReferencesPastePreview"
></el-input>
<p v-if="referencesPasteText" style="margin: 10px 0 0; font-size: 13px" :style="{ color: referencesPasteCount > 0 ? '#67C23A' : '#E6A23C' }">
{{ referencesPastePreviewText }}
</p>
<span slot="footer" class="dialog-footer">
<el-button @click="referencesPasteVisible = false">{{ $t('commonTable.refHtmlPasteCancel') }}</el-button>
<el-button @click="triggerReferencesHtmlFileImport">{{ $t('commonTable.refHtmlImportHtml') }}</el-button>
<el-button type="primary" :loading="referencesUploadLoading" @click="confirmReferencesUpload">
{{ $t('commonTable.refHtmlUploadConfirm') }}
</el-button>
</span>
</el-dialog>
<input
ref="referencesHtmlFileInput"
type="file"
accept=".html,.htm,.txt,text/html,text/plain"
style="display: none"
@change="handleReferencesFileUpload"
/>
<div class="rail" ref="rail" v-if="isEditComment">
<div
v-for="(m, i) in markers"
@@ -1101,6 +1180,15 @@ import { debounce, throttle } from '@/common/js/debounce';
import { tableStyle, commonWordStyle } from '@/utils/tinymceStyles';
import LatexDataPanel from './LatexDataPanel.vue';
import { downloadManuscriptWord, fetchManuscriptReferenceList } from '@/utils/exportManuscriptWord';
import {
buildReferencesCopyText,
buildReferencesHtmlLabels,
copyReferencesToClipboard,
countParsedReferences,
downloadReferencesEditableHtml,
parseReferencesBulkContent,
parseReferencesEditableHtml
} from '@/utils/manuscriptReferenceHtml';
import {
buildCitationReviewQueue,
buildCitationReviewHtmlLabels,
@@ -1232,6 +1320,14 @@ export default {
scrollPosition: 0,
wordList: [],
exportingManuscriptWord: false,
referencesCopyLoading: false,
referencesHtmlLoading: false,
referencesUploadLoading: false,
uploadedReferenceHtmlItems: null,
uploadedReferencesCount: 0,
referencesPasteVisible: false,
referencesPasteText: '',
referencesPasteCount: 0,
citationRelevanceLoading: false,
manuscriptReferences: [],
proofreadingList: [],
@@ -1361,6 +1457,15 @@ export default {
zyModeEnabled() {
return isZyModeEnabled(this.$route);
},
referencesPastePreviewText() {
if (!this.referencesPasteText) {
return '';
}
if (this.referencesPasteCount > 0) {
return this.$t('commonTable.refHtmlPasteParsed', { n: this.referencesPasteCount });
}
return this.$t('commonTable.refHtmlPasteParseEmpty');
},
sortedProofreadingList() {
const order = [2, 1, 3];
const rank = { 2: 0, 1: 1, 3: 2 };
@@ -1496,6 +1601,164 @@ export default {
this.editors = {};
},
methods: {
async loadManuscriptReferences(forceReload) {
if (!forceReload && this.manuscriptReferences && this.manuscriptReferences.length) {
return this.manuscriptReferences;
}
if (!this.$api) {
throw new Error('NO_API');
}
const references = await fetchManuscriptReferenceList(this.$api, this.articleId, this.pArticleId);
this.manuscriptReferences = references || [];
return this.manuscriptReferences;
},
async handleCopyReferences() {
if (this.referencesCopyLoading) {
return;
}
if (!this.$api) {
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
return;
}
this.referencesCopyLoading = true;
try {
const references = await this.loadManuscriptReferences(false);
if (!references.length) {
this.$message.warning(this.$t('commonTable.refHtmlEmpty'));
return;
}
await copyReferencesToClipboard(references);
this.$message.success(this.$t('commonTable.refHtmlCopySuccess'));
} catch (err) {
console.error(err);
if (err && err.message === 'EMPTY') {
this.$message.warning(this.$t('commonTable.refHtmlEmpty'));
} else {
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
}
} finally {
this.referencesCopyLoading = false;
}
},
async handleDownloadReferencesHtml() {
if (this.referencesHtmlLoading) {
return;
}
if (!this.$api) {
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
return;
}
this.referencesHtmlLoading = true;
try {
const references = await this.loadManuscriptReferences(false);
if (!references.length) {
this.$message.warning(this.$t('commonTable.refHtmlEmpty'));
return;
}
const labels = buildReferencesHtmlLabels(this.$t.bind(this));
const fileName = 'references-editor' + (this.articleId ? '-' + this.articleId : '') + '.html';
downloadReferencesEditableHtml(references, labels, fileName);
this.$message.success(this.$t('commonTable.refHtmlDownloadSuccess'));
} catch (err) {
console.error(err);
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
} finally {
this.referencesHtmlLoading = false;
}
},
triggerReferencesUpload() {
const input = this.$refs.referencesHtmlFileInput;
if (input) {
input.value = '';
input.click();
}
},
triggerReferencesHtmlFileImport() {
this.triggerReferencesUpload();
},
parseUploadedReferenceContent(text, fileName) {
const raw = String(text || '');
const isPlainText = /\.txt$/i.test(String(fileName || ''));
if (isPlainText) {
return parseReferencesBulkContent(raw);
}
return parseReferencesEditableHtml(raw);
},
applyUploadedReferences(items) {
if (!items || !items.length) {
this.$message.warning(this.$t('commonTable.refHtmlParseEmpty'));
return false;
}
this.uploadedReferenceHtmlItems = items;
this.uploadedReferencesCount = items.length;
this.$message.success(
this.$t('commonTable.refHtmlUploadSuccess', { n: items.length })
);
return true;
},
handleReferencesFileUpload(event) {
const input = event && event.target;
const file = input && input.files && input.files[0];
if (!file) {
return;
}
this.referencesUploadLoading = true;
const reader = new FileReader();
reader.onload = () => {
try {
const items = this.parseUploadedReferenceContent(reader.result, file.name);
this.applyUploadedReferences(items);
} catch (err) {
console.error(err);
this.$message.error(this.$t('commonTable.refHtmlToWordFail'));
} finally {
this.referencesUploadLoading = false;
if (input) {
input.value = '';
}
}
};
reader.onerror = () => {
this.referencesUploadLoading = false;
if (input) {
input.value = '';
}
this.$message.error(this.$t('commonTable.refHtmlToWordFail'));
};
reader.readAsText(file, 'UTF-8');
},
async openReferencesPasteDialog() {
if (this.referencesUploadLoading) {
return;
}
if (!this.$api) {
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
return;
}
try {
const references = await this.loadManuscriptReferences(false);
this.referencesPasteText = references.length ? buildReferencesCopyText(references) : '';
} catch (err) {
console.error(err);
this.referencesPasteText = '';
}
this.updateReferencesPastePreview();
this.referencesPasteVisible = true;
},
updateReferencesPastePreview() {
this.referencesPasteCount = countParsedReferences(this.referencesPasteText);
},
confirmReferencesUpload() {
const items = parseReferencesBulkContent(this.referencesPasteText);
if (this.applyUploadedReferences(items)) {
this.referencesPasteVisible = false;
}
},
async handleExportManuscriptWord() {
if (this.exportingManuscriptWord) {
return;
@@ -1506,19 +1769,32 @@ export default {
}
this.exportingManuscriptWord = true;
try {
const hasUploaded =
this.uploadedReferenceHtmlItems && this.uploadedReferenceHtmlItems.length;
await downloadManuscriptWord(this.wordList, this.mediaUrl, 'manuscript', {
fetchReferences: true,
fetchReferences: !hasUploaded,
referenceHtmlItems: hasUploaded ? this.uploadedReferenceHtmlItems : null,
apiClient: this.$api,
articleId: this.articleId,
pArticleId: this.pArticleId
});
this.$message.success(this.$t('commonTable.exportManuscriptSuccess') || 'Word downloaded.');
this.$message.success(
hasUploaded
? this.$t('commonTable.exportWordWithUploadedRefsSuccess', {
n: this.uploadedReferencesCount
})
: this.$t('commonTable.exportManuscriptSuccess') || 'Word downloaded.'
);
} catch (err) {
console.error(err);
if (err && err.message === 'NO_CONTENT') {
this.$message.warning(this.$t('commonTable.exportManuscriptEmpty') || 'No content to export.');
} else {
this.$message.error(this.$t('commonTable.exportManuscriptFail') || 'Failed to export Word.');
const detail =
err && err.message
? err.message
: this.$t('commonTable.exportManuscriptFail') || 'Failed to export Word.';
this.$message.error(detail);
}
} finally {
this.exportingManuscriptWord = false;
@@ -1539,11 +1815,7 @@ export default {
this.citationRelevanceLoading = true;
try {
let references = this.manuscriptReferences;
if (!references || !references.length) {
references = await fetchManuscriptReferenceList(this.$api, this.articleId, this.pArticleId);
this.manuscriptReferences = references || [];
}
const references = await this.loadManuscriptReferences(false);
const items = buildCitationReviewQueue(this.wordList, this.manuscriptReferences);
if (!items.length) {
@@ -2607,6 +2879,14 @@ export default {
this.selectedIds = [];
this.$forceUpdate();
},
handleSelectAll() {
this.currentId = null;
this.currentData = {};
this.selectedIds = (this.wordList || [])
.map((item) => (item && item.am_id != null ? item.am_id : null))
.filter((id) => id != null);
this.$forceUpdate();
},
onEdit() {
this.$emit('onEdit', this.currentId);
},
@@ -4378,6 +4658,52 @@ export default {
border-radius: 0;
height: auto;
}
.HTitleBox li.zy-toolbar-btn {
padding: 4px 10px;
margin: 0 2px;
font-size: 12px !important;
font-weight: normal !important;
min-width: auto;
height: auto;
color: #409eff;
background: #fff;
border: 1px solid #409eff;
border-radius: 4px;
box-sizing: border-box;
}
.HTitleBox li.zy-toolbar-btn:hover {
background: #ecf5ff;
}
.HTitleBox li.zy-toolbar-btn.zy-toolbar-btn--ready {
border-color: #67c23a;
color: #67c23a;
}
.HTitleBox li.zy-toolbar-btn.zy-toolbar-btn--ready:hover {
background: #f0f9eb;
}
.zy-toolbar-btn-inner {
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 4px;
line-height: 1.2;
pointer-events: none;
}
.zy-toolbar-btn-inner i {
font-size: 14px;
margin: 0;
}
.zy-toolbar-label {
font-size: 12px;
white-space: nowrap;
font-weight: normal;
}
.zy-toolbar-badge {
font-style: normal;
color: inherit;
font-weight: bold;
}
.operateBox {
width: auto;
display: flex;

View File

@@ -556,6 +556,16 @@
>We have detected updates to the reference content. You need to click the "Automatic parsing" button to
recognize them.</span
>
<el-button
v-if="zyModeEnabled && SourceType === 'book'"
type="primary"
plain
size="mini"
style="margin-top: 8px"
@click="parseBookReferenceZy"
>
{{ $t('commonTable.parseBookReference') }}
</el-button>
</div>
</el-form-item>
@@ -898,6 +908,8 @@
<script>
import VueUeditorWrap from 'vue-ueditor-wrap'; // ES6 Module
import ReferenceSearchLinks from '@/components/page/components/ReferenceSearchLinks.vue';
import { isZyModeEnabled } from '@/utils/zyMode';
import { parseBookReferenceContent } from '@/utils/parseBookReference';
/** 单条引用 records[].status0 待检测 2 已完成 3 检测失败 */
const REF_RELEVANCE_RECORD_STATUS_PENDING = 0;
@@ -1072,6 +1084,9 @@ export default {
};
},
computed: {
zyModeEnabled() {
return isZyModeEnabled(this.$route);
},
showRefRelevanceToolbar() {
return this.role === 'editor' && this.showB_step === 2 && !this.refRelevanceStatusLoading;
},
@@ -1542,6 +1557,27 @@ export default {
this.$message.error(err);
});
},
parseBookReferenceZy() {
const content = String(this.refenceForm.content || '').trim();
if (!content) {
this.$message.error(this.$t('commonTable.parseBookReferenceContentEmpty'));
return;
}
const parsed = parseBookReferenceContent(content);
if (!parsed || (!parsed.author && !parsed.title && !parsed.dateno && !parsed.isbn)) {
this.$message.warning(this.$t('commonTable.parseBookReferenceEmpty'));
return;
}
this.SourceType = 'book';
this.refenceForm.refer_type = 'book';
this.refenceForm.author = parsed.author || '';
this.refenceForm.title = parsed.title || '';
this.refenceForm.dateno = parsed.dateno || '';
this.refenceForm.isbn = parsed.isbn || '';
this.isShowParsing = false;
this.isShowParsingData = true;
this.$message.success(this.$t('commonTable.parseBookReferenceSuccess'));
},
getRefData(id) {
return this.$api

View File

@@ -71,7 +71,14 @@
<span class="value time">{{ scope.row.ctime_text ? scope.row.ctime_text : $t('expertDatabase.emptyMark') }}</span>
</p>
<span class="custom-tag">{{ scope.row.state_text }}</span>
<el-tooltip
v-if="shouldShowStateTag(scope.row)"
:content="getLastContactTooltip(scope.row)"
placement="top"
effect="dark"
>
<span class="custom-tag">{{ scope.row.state_text }}</span>
</el-tooltip>
</div>
</template>
</el-table-column>
@@ -289,6 +296,20 @@ export default {
getUnsubscribeValue(row) {
return this.normalizeUnsubscribeValue(row);
},
shouldShowStateTag(row) {
const text = String((row && row.state_text) || '').trim();
if (!text || text.indexOf('待联系') !== -1) {
return false;
}
return true;
},
getLastContactTooltip(row) {
const time = row && row.ltime_text ? String(row.ltime_text).trim() : '';
if (time) {
return this.$t('expertDatabase.lastContactTime', { time });
}
return this.$t('expertDatabase.lastContactTimeEmpty');
},
async handleUnsubscribeSwitch(row, checked) {
const expertId = this.getExpertId(row);
if (!expertId) {
@@ -432,6 +453,7 @@ export default {
color: #ce4f15;
font-size: 12px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
cursor: default;
}
.info-row {
margin-bottom: 4px;

View File

@@ -44,8 +44,8 @@
</div>
</div>
<el-table :data="tableData" border stripe class="table" ref="multipleTable" @sort-change="changeSort"
header-cell-class-name="table-header">
<el-table :data="tableData" border stripe class="table" ref="multipleTable" v-loading="listLoading"
@sort-change="changeSort" header-cell-class-name="table-header">
<el-table-column label="Basic Information">
<template slot-scope="scope">
<p class="tab_tie_col">
@@ -147,8 +147,16 @@
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
:page-size="query.pageSize" :total="Total" @current-change="handlePageChange"></el-pagination>
<el-pagination
background
layout="sizes, total, prev, pager, next"
:current-page="query.pageIndex"
:page-size="query.pageSize"
:page-sizes="[10, 15, 20, 50, 100]"
:total="Total"
@size-change="handleSizeChange"
@current-change="handlePageChange"
></el-pagination>
</div>
</div>
@@ -266,6 +274,8 @@ import bus from '../common/bus'
order_remark: 0
},
Total: 0,
listLoading: false,
paginationSizeChanging: false,
df_jour: [],
df_year: [],
list_year: [{
@@ -400,23 +410,43 @@ import bus from '../common/bus'
},
// 获取青年科学家列表数据
buildListParams() {
return {
journal_id: this.query.journal_id,
type: this.query.type,
year: this.query.year,
pageIndex: Number(this.query.pageIndex) || 1,
pageSize: Number(this.query.pageSize) || 15,
keywords: this.query.keywords || '',
fieldkey: this.query.fieldkey || '',
order_remark: this.query.order_remark || 0
};
},
getDate() {
this.$api
.post('api/User/getYboardlist', this.query)
const params = this.buildListParams();
this.listLoading = true;
return this.$api
.post('api/User/getYboardlist', params)
.then(res => {
if (res.code == 0) {
console.log(res.data.yboards,'zheli');
this.tableData = res.data.yboards;
this.tableData = res.data.yboards || [];
for (var i = 0; i < this.tableData.length; i++) {
this.getScoreData(i, this.tableData[i].score)
this.getScoreData(i, this.tableData[i].score);
}
this.Total = res.data.count;
this.Total = res.data.count || 0;
} else {
this.tableData = [];
this.Total = 0;
this.$message.error(res.msg);
}
})
.catch(err => {
this.tableData = [];
this.Total = 0;
console.log(err);
})
.finally(() => {
this.listLoading = false;
});
},
@@ -671,9 +701,23 @@ import bus from '../common/bus'
});
},
// 分页导航
// 分页:每页条数
handleSizeChange(size) {
this.paginationSizeChanging = true;
this.query.pageSize = size;
this.query.pageIndex = 1;
this.getDate().finally(() => {
this.$nextTick(() => {
this.paginationSizeChanging = false;
});
});
},
// 分页:页码
handlePageChange(val) {
this.$set(this.query, 'pageIndex', val);
if (this.paginationSizeChanging) {
return;
}
this.query.pageIndex = val;
this.getDate();
},