去掉作者端 Article Proofreading (原步骤2)
This commit is contained in:
@@ -19,8 +19,8 @@ const service = axios.create({
|
|||||||
// baseURL: 'https://submission.tmrjournals.com/', //正式 记得切换
|
// baseURL: 'https://submission.tmrjournals.com/', //正式 记得切换
|
||||||
// baseURL: 'http://www.tougao.com/', //测试本地 记得切换
|
// baseURL: 'http://www.tougao.com/', //测试本地 记得切换
|
||||||
// baseURL: 'http://192.168.110.110/tougao/public/index.php/',
|
// baseURL: 'http://192.168.110.110/tougao/public/index.php/',
|
||||||
baseURL: '/api', //本地
|
// baseURL: '/api', //本地
|
||||||
// baseURL: '/', //正式
|
baseURL: '/', //正式
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
//记得切换
|
//记得切换
|
||||||
|
|
||||||
//正式
|
//正式
|
||||||
// const mediaUrl = '/public/';
|
const mediaUrl = '/public/';
|
||||||
// const baseUrl = '/';
|
const baseUrl = '/';
|
||||||
|
|
||||||
//正式环境
|
//正式环境
|
||||||
|
|
||||||
const mediaUrl = 'https://submission.tmrjournals.com/public/';
|
// const mediaUrl = 'https://submission.tmrjournals.com/public/';
|
||||||
// const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
|
// // const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
|
||||||
const baseUrl = '/api'
|
// const baseUrl = '/api'
|
||||||
|
|
||||||
//测试环境
|
//测试环境
|
||||||
|
|
||||||
|
|||||||
@@ -1145,7 +1145,7 @@ const en = {
|
|||||||
typesettingType1: 'Vertical A4',
|
typesettingType1: 'Vertical A4',
|
||||||
AnnotationList: 'Annotation List',
|
AnnotationList: 'Annotation List',
|
||||||
Annotations: 'Comments',
|
Annotations: 'Comments',
|
||||||
exportWord: 'Export Word',
|
exportWord: 'Generate Word file',
|
||||||
exportManuscriptEmpty: 'No content to export.',
|
exportManuscriptEmpty: 'No content to export.',
|
||||||
exportManuscriptSuccess: 'Word downloaded.',
|
exportManuscriptSuccess: 'Word downloaded.',
|
||||||
exportManuscriptFail: 'Failed to export Word.',
|
exportManuscriptFail: 'Failed to export Word.',
|
||||||
@@ -1174,8 +1174,10 @@ const en = {
|
|||||||
citeRelevanceBatchTip: '{n} references per batch within each paragraph',
|
citeRelevanceBatchTip: '{n} references per batch within each paragraph',
|
||||||
citeRelevanceRefBatch: 'Batch refs {nums}',
|
citeRelevanceRefBatch: 'Batch refs {nums}',
|
||||||
citeRelevanceBatchProgress: 'Paragraph batch {current}/{total}',
|
citeRelevanceBatchProgress: 'Paragraph batch {current}/{total}',
|
||||||
citeRelevanceGroupTotal: '{n} paragraphs to review',
|
citeRelevanceGroupTotal: '{n} batches to review',
|
||||||
citeRelevanceGroupNavLabel: 'Para {paragraph} · {refs}',
|
citeRelevanceGroupNavLabel: 'Para {paragraph} · {refs}',
|
||||||
|
citeRelevanceTableNavLabel: 'Table {paragraph} · {refs}',
|
||||||
|
citeRelevancePreviewTitle: 'Preview',
|
||||||
citeRelevanceJumpTo: 'Jump to',
|
citeRelevanceJumpTo: 'Jump to',
|
||||||
citeRelevanceCopyGroup: 'Copy paragraph',
|
citeRelevanceCopyGroup: 'Copy paragraph',
|
||||||
citeRelevanceDownloadHtml: 'Download HTML',
|
citeRelevanceDownloadHtml: 'Download HTML',
|
||||||
|
|||||||
@@ -1131,7 +1131,7 @@ const zh = {
|
|||||||
typesettingType1: '竖向 A4',
|
typesettingType1: '竖向 A4',
|
||||||
AnnotationList: '批注列表',
|
AnnotationList: '批注列表',
|
||||||
Annotations: '批注',
|
Annotations: '批注',
|
||||||
exportWord: '导出 Word',
|
exportWord: '生成 Word 文件',
|
||||||
exportManuscriptEmpty: '没有可导出的内容。',
|
exportManuscriptEmpty: '没有可导出的内容。',
|
||||||
exportManuscriptSuccess: 'Word 已下载。',
|
exportManuscriptSuccess: 'Word 已下载。',
|
||||||
exportManuscriptFail: 'Word 导出失败。',
|
exportManuscriptFail: 'Word 导出失败。',
|
||||||
@@ -1160,8 +1160,10 @@ const zh = {
|
|||||||
citeRelevanceBatchTip: '每段正文按 {n} 条参考文献一批提问',
|
citeRelevanceBatchTip: '每段正文按 {n} 条参考文献一批提问',
|
||||||
citeRelevanceRefBatch: '本批文献 {nums}',
|
citeRelevanceRefBatch: '本批文献 {nums}',
|
||||||
citeRelevanceBatchProgress: '本段第 {current}/{total} 批',
|
citeRelevanceBatchProgress: '本段第 {current}/{total} 批',
|
||||||
citeRelevanceGroupTotal: '共 {n} 段待核查',
|
citeRelevanceGroupTotal: '共 {n} 组待核查',
|
||||||
citeRelevanceGroupNavLabel: '段落 {paragraph} · {refs}',
|
citeRelevanceGroupNavLabel: '段落 {paragraph} · {refs}',
|
||||||
|
citeRelevanceTableNavLabel: '表格 {paragraph} · {refs}',
|
||||||
|
citeRelevancePreviewTitle: '内容预览',
|
||||||
citeRelevanceJumpTo: '快速跳转',
|
citeRelevanceJumpTo: '快速跳转',
|
||||||
citeRelevanceCopyGroup: '复制本段',
|
citeRelevanceCopyGroup: '复制本段',
|
||||||
citeRelevanceDownloadHtml: '下载 HTML',
|
citeRelevanceDownloadHtml: '下载 HTML',
|
||||||
|
|||||||
@@ -136,16 +136,16 @@
|
|||||||
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
|
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content_box mt20 stepbox">
|
<!-- <div class="content_box mt20 stepbox">
|
||||||
<!-- 文章引用 -->
|
|
||||||
<div class="con">
|
<div class="con">
|
||||||
<h4 class="con-title">{{ this.$t('PreAccept.step2') }}</h4>
|
<h4 class="con-title">{{ this.$t('PreAccept.step2') }}</h4>
|
||||||
<p style="color: #505050; font-size: 14px; padding: 20px; box-sizing: border-box">
|
<p style="color: #505050; font-size: 14px; padding: 20px; box-sizing: border-box">
|
||||||
<el-button @click="goGenerateCharts(thisArtcleId)" icon="el-icon-edit" type="text">Edit</el-button>
|
<el-button @click="goGenerateCharts(thisArtcleId)" icon="el-icon-edit" type="text">Edit</el-button>
|
||||||
</p>
|
</p>
|
||||||
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="content_box mt20 stepbox">
|
<div class="content_box mt20 stepbox">
|
||||||
<!-- 文章引用 -->
|
<!-- 文章引用 -->
|
||||||
<div class="con">
|
<div class="con">
|
||||||
|
|||||||
@@ -92,49 +92,6 @@
|
|||||||
></i>
|
></i>
|
||||||
{{ $t('commonTable.exportWord') }}
|
{{ $t('commonTable.exportWord') }}
|
||||||
</li>
|
</li>
|
||||||
<li
|
|
||||||
v-if="zyModeEnabled"
|
|
||||||
@click="handleDownloadReferencesHtml"
|
|
||||||
class="base-font-size base-bg-imp base-padding-all"
|
|
||||||
:style="{ '--f-s': '12px', '--f-c': '#333' }"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="el-icon-document base-margin"
|
|
||||||
:style="{ '--m-r': '2px' }"
|
|
||||||
v-if="!referencesHtmlLoading"
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
class="el-icon-loading base-margin"
|
|
||||||
:style="{ '--m-r': '2px' }"
|
|
||||||
v-else
|
|
||||||
></i>
|
|
||||||
{{ $t('commonTable.refHtmlDownload') }}
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
v-if="zyModeEnabled"
|
|
||||||
@click="triggerReferencesHtmlToWord"
|
|
||||||
class="base-font-size base-bg-imp base-padding-all"
|
|
||||||
:style="{ '--f-s': '12px', '--f-c': '#333' }"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="el-icon-upload2 base-margin"
|
|
||||||
:style="{ '--m-r': '2px' }"
|
|
||||||
v-if="!exportingReferencesHtmlWord"
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
class="el-icon-loading base-margin"
|
|
||||||
:style="{ '--m-r': '2px' }"
|
|
||||||
v-else
|
|
||||||
></i>
|
|
||||||
{{ $t('commonTable.refHtmlToWord') }}
|
|
||||||
</li>
|
|
||||||
<input
|
|
||||||
ref="referencesHtmlFileInput"
|
|
||||||
type="file"
|
|
||||||
accept=".html,text/html"
|
|
||||||
style="display: none"
|
|
||||||
@change="handleReferencesHtmlToWord"
|
|
||||||
/>
|
|
||||||
<li
|
<li
|
||||||
v-if="zyModeEnabled"
|
v-if="zyModeEnabled"
|
||||||
@click="handleOpenCitationRelevance"
|
@click="handleOpenCitationRelevance"
|
||||||
@@ -1144,11 +1101,6 @@ import { debounce, throttle } from '@/common/js/debounce';
|
|||||||
import { tableStyle, commonWordStyle } from '@/utils/tinymceStyles';
|
import { tableStyle, commonWordStyle } from '@/utils/tinymceStyles';
|
||||||
import LatexDataPanel from './LatexDataPanel.vue';
|
import LatexDataPanel from './LatexDataPanel.vue';
|
||||||
import { downloadManuscriptWord, fetchManuscriptReferenceList } from '@/utils/exportManuscriptWord';
|
import { downloadManuscriptWord, fetchManuscriptReferenceList } from '@/utils/exportManuscriptWord';
|
||||||
import {
|
|
||||||
buildReferencesHtmlLabels,
|
|
||||||
downloadReferencesEditableHtml,
|
|
||||||
parseReferencesEditableHtml
|
|
||||||
} from '@/utils/manuscriptReferenceHtml';
|
|
||||||
import {
|
import {
|
||||||
buildCitationReviewQueue,
|
buildCitationReviewQueue,
|
||||||
buildCitationReviewHtmlLabels,
|
buildCitationReviewHtmlLabels,
|
||||||
@@ -1280,8 +1232,6 @@ export default {
|
|||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
wordList: [],
|
wordList: [],
|
||||||
exportingManuscriptWord: false,
|
exportingManuscriptWord: false,
|
||||||
referencesHtmlLoading: false,
|
|
||||||
exportingReferencesHtmlWord: false,
|
|
||||||
citationRelevanceLoading: false,
|
citationRelevanceLoading: false,
|
||||||
manuscriptReferences: [],
|
manuscriptReferences: [],
|
||||||
proofreadingList: [],
|
proofreadingList: [],
|
||||||
@@ -1574,104 +1524,6 @@ export default {
|
|||||||
this.exportingManuscriptWord = false;
|
this.exportingManuscriptWord = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async handleDownloadReferencesHtml() {
|
|
||||||
if (this.referencesHtmlLoading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.$api) {
|
|
||||||
this.$message.error(this.$t('commonTable.refHtmlLoadFail'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.referencesHtmlLoading = true;
|
|
||||||
try {
|
|
||||||
let references = this.manuscriptReferences;
|
|
||||||
if (!references || !references.length) {
|
|
||||||
references = await fetchManuscriptReferenceList(this.$api, this.articleId, this.pArticleId);
|
|
||||||
this.manuscriptReferences = references || [];
|
|
||||||
}
|
|
||||||
if (!references || !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;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
triggerReferencesHtmlToWord() {
|
|
||||||
if (this.exportingReferencesHtmlWord) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const input = this.$refs.referencesHtmlFileInput;
|
|
||||||
if (input) {
|
|
||||||
input.value = '';
|
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleReferencesHtmlToWord(event) {
|
|
||||||
const input = event && event.target;
|
|
||||||
const file = input && input.files && input.files[0];
|
|
||||||
if (!file) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.wordList || !this.wordList.length) {
|
|
||||||
this.$message.warning(this.$t('commonTable.exportManuscriptEmpty'));
|
|
||||||
if (input) {
|
|
||||||
input.value = '';
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.exportingReferencesHtmlWord = true;
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = async () => {
|
|
||||||
try {
|
|
||||||
const referenceHtmlItems = parseReferencesEditableHtml(String(reader.result || ''));
|
|
||||||
if (!referenceHtmlItems.length) {
|
|
||||||
this.$message.warning(this.$t('commonTable.refHtmlParseEmpty'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await downloadManuscriptWord(this.wordList, this.mediaUrl, 'manuscript', {
|
|
||||||
fetchReferences: false,
|
|
||||||
referenceHtmlItems: referenceHtmlItems,
|
|
||||||
apiClient: this.$api,
|
|
||||||
articleId: this.articleId,
|
|
||||||
pArticleId: this.pArticleId
|
|
||||||
});
|
|
||||||
this.$message.success(this.$t('commonTable.refHtmlToWordSuccess'));
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
if (err && err.message === 'NO_CONTENT') {
|
|
||||||
this.$message.warning(this.$t('commonTable.exportManuscriptEmpty'));
|
|
||||||
} else {
|
|
||||||
this.$message.error(this.$t('commonTable.refHtmlToWordFail'));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.exportingReferencesHtmlWord = false;
|
|
||||||
if (input) {
|
|
||||||
input.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.onerror = () => {
|
|
||||||
this.exportingReferencesHtmlWord = false;
|
|
||||||
if (input) {
|
|
||||||
input.value = '';
|
|
||||||
}
|
|
||||||
this.$message.error(this.$t('commonTable.refHtmlToWordFail'));
|
|
||||||
};
|
|
||||||
reader.readAsText(file, 'UTF-8');
|
|
||||||
},
|
|
||||||
async handleOpenCitationRelevance() {
|
async handleOpenCitationRelevance() {
|
||||||
if (this.citationRelevanceLoading) {
|
if (this.citationRelevanceLoading) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
/** 正文引用标记,如 [1]、[1-7]、<blue>[4,6,8]</blue> */
|
/** 正文引用标记,如 [1]、[1-7]、<blue>[4,6,8]</blue> */
|
||||||
const CITATION_BRACKET_RE = /(?:<blue>\s*)?\[([^\]]+)\](?:\s*<\/blue>)?/gi;
|
const CITATION_BRACKET_RE = /(?:<blue>\s*)?\[([^\]]+)\](?:\s*<\/blue>)?/gi;
|
||||||
|
|
||||||
|
/** 每批最多分析的参考文献条数 */
|
||||||
|
export const CITATION_REVIEW_BATCH_SIZE = 4;
|
||||||
|
|
||||||
function decodeHtmlEntities(text) {
|
function decodeHtmlEntities(text) {
|
||||||
return String(text || '')
|
return String(text || '')
|
||||||
.replace(/ /g, ' ')
|
.replace(/ /g, ' ')
|
||||||
@@ -117,17 +120,162 @@ export function formatReferencePlainText(ref) {
|
|||||||
return parts.filter(Boolean).join('. ').replace(/\.\s*\./g, '.').trim();
|
return parts.filter(Boolean).join('. ').replace(/\.\s*\./g, '.').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTextParagraphItem(item) {
|
function isTableItem(item) {
|
||||||
|
return !!(item && item.type == 2 && item.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCitableReviewItem(item) {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (item.type == 1 || item.type == 2) {
|
if (item.type == 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isTableItem(item)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const html = String(item.content || item.text || '').trim();
|
const html = String(item.content || item.text || '').trim();
|
||||||
return !!html;
|
return !!html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function forEachTableRowCells(row, fn) {
|
||||||
|
if (!row || !Array.isArray(row)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.forEach(function (cell) {
|
||||||
|
if (cell && typeof cell === 'object' && cell.text != null) {
|
||||||
|
fn(cell);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectTablePartsHtml(table) {
|
||||||
|
const parts = [];
|
||||||
|
if (!table) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (table.title) {
|
||||||
|
parts.push(String(table.title));
|
||||||
|
}
|
||||||
|
(table.tableHeader || []).forEach(function (row) {
|
||||||
|
forEachTableRowCells(row, function (cell) {
|
||||||
|
parts.push(String(cell.text || ''));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(table.tableContent || []).forEach(function (row) {
|
||||||
|
forEachTableRowCells(row, function (cell) {
|
||||||
|
parts.push(String(cell.text || ''));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (table.note) {
|
||||||
|
parts.push(String(table.note));
|
||||||
|
}
|
||||||
|
return parts.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTablePlainText(table) {
|
||||||
|
const lines = [];
|
||||||
|
if (!table) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (table.title) {
|
||||||
|
lines.push(htmlToPlainText(table.title));
|
||||||
|
}
|
||||||
|
(table.tableHeader || []).forEach(function (row) {
|
||||||
|
const cells = [];
|
||||||
|
forEachTableRowCells(row, function (cell) {
|
||||||
|
cells.push(htmlToPlainText(cell.text));
|
||||||
|
});
|
||||||
|
if (cells.length) {
|
||||||
|
lines.push(cells.join(' | '));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(table.tableContent || []).forEach(function (row) {
|
||||||
|
const cells = [];
|
||||||
|
forEachTableRowCells(row, function (cell) {
|
||||||
|
cells.push(htmlToPlainText(cell.text));
|
||||||
|
});
|
||||||
|
if (cells.length) {
|
||||||
|
lines.push(cells.join(' | '));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (table.note) {
|
||||||
|
lines.push(htmlToPlainText(table.note));
|
||||||
|
}
|
||||||
|
return lines.filter(Boolean).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReviewItemSourceHtml(item) {
|
||||||
|
if (isTableItem(item)) {
|
||||||
|
return collectTablePartsHtml(item.table);
|
||||||
|
}
|
||||||
|
return String(item.content || item.text || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReviewItemPlainText(item) {
|
||||||
|
if (isTableItem(item)) {
|
||||||
|
return buildTablePlainText(item.table);
|
||||||
|
}
|
||||||
|
return htmlToPlainText(getReviewItemSourceHtml(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTableRowPreviewHtml(row, oddRowIds) {
|
||||||
|
if (!row || !Array.isArray(row)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const isOdd = row.rowId && (oddRowIds || []).indexOf(row.rowId) !== -1;
|
||||||
|
let cellsHtml = '';
|
||||||
|
row.forEach(function (cell) {
|
||||||
|
if (!cell || typeof cell !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cellsHtml +=
|
||||||
|
'<td rowspan="' +
|
||||||
|
(cell.rowspan || 1) +
|
||||||
|
'" colspan="' +
|
||||||
|
(cell.colspan || 1) +
|
||||||
|
'">' +
|
||||||
|
(cell.text || '') +
|
||||||
|
'</td>';
|
||||||
|
});
|
||||||
|
return '<tr class="' + (isOdd ? 'oddColor' : '') + '">' + cellsHtml + '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildReviewTablePreviewHtml(item) {
|
||||||
|
const table = item.table;
|
||||||
|
if (!table) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
let tableRows = '';
|
||||||
|
(table.tableHeader || []).forEach(function (row) {
|
||||||
|
tableRows += buildTableRowPreviewHtml(row, []);
|
||||||
|
});
|
||||||
|
(table.tableContent || []).forEach(function (row) {
|
||||||
|
tableRows += buildTableRowPreviewHtml(row, table.oddRowIds || []);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
'<div class="cite-preview-table">' +
|
||||||
|
(table.title ? '<div class="cite-preview-table-title">' + table.title + '</div>' : '') +
|
||||||
|
'<table border="1"><tbody>' +
|
||||||
|
tableRows +
|
||||||
|
'</tbody></table>' +
|
||||||
|
(table.note ? '<div class="cite-preview-table-note">' + table.note + '</div>' : '') +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildReviewContentPreviewHtml(item) {
|
||||||
|
if (isTableItem(item)) {
|
||||||
|
return buildReviewTablePreviewHtml(item);
|
||||||
|
}
|
||||||
|
const html = String(item.content || item.text || '');
|
||||||
|
if (!html) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return '<div class="cite-preview-paragraph">' + html + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
function buildCitationEntry(citeNum, refList) {
|
function buildCitationEntry(citeNum, refList) {
|
||||||
const ref = refList[citeNum - 1] || null;
|
const ref = refList[citeNum - 1] || null;
|
||||||
return {
|
return {
|
||||||
@@ -144,19 +292,40 @@ export function formatCitationNumsLabel(citeNums) {
|
|||||||
}).join(' ');
|
}).join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chunkCitationNumbers(citeNums, batchSize) {
|
||||||
|
const size = batchSize || CITATION_REVIEW_BATCH_SIZE;
|
||||||
|
const chunks = [];
|
||||||
|
const nums = citeNums || [];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nums.length; i += size) {
|
||||||
|
chunks.push(nums.slice(i, i + size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
export function getCitationReviewGroupMeta(item, index, labels) {
|
export function getCitationReviewGroupMeta(item, index, labels) {
|
||||||
const l = labels || {};
|
const l = labels || {};
|
||||||
const groupNo = index + 1;
|
const groupNo = index + 1;
|
||||||
const paragraphNo = item.paragraphIndex + 1;
|
const paragraphNo = item.paragraphIndex + 1;
|
||||||
const citeNumsLabel = formatCitationNumsLabel(item.citeNums);
|
const citeNumsLabel = formatCitationNumsLabel(item.citeNums);
|
||||||
const citeNumsPlain = (item.citeNums || []).join('、');
|
const citeNumsPlain = (item.citeNums || []).join('、');
|
||||||
|
const batchTotal = item.batchTotal || 1;
|
||||||
|
const batchIndex = item.batchIndex || 1;
|
||||||
|
let batchSuffix = '';
|
||||||
|
|
||||||
let title = '正文段落 ' + paragraphNo + ' · ' + citeNumsLabel;
|
if (batchTotal > 1 && l.batchProgress) {
|
||||||
if (l.groupLabel) {
|
batchSuffix = ' · ' + l.batchProgress.replace('{current}', batchIndex).replace('{total}', batchTotal);
|
||||||
title = l.groupLabel
|
}
|
||||||
|
|
||||||
|
let title = (item.sourceType === 'table' ? '表格 ' : '正文段落 ') + paragraphNo + ' · ' + citeNumsLabel + batchSuffix;
|
||||||
|
const navLabel = item.sourceType === 'table' ? l.tableGroupLabel : l.groupLabel;
|
||||||
|
if (navLabel) {
|
||||||
|
title = navLabel
|
||||||
.replace('{group}', groupNo)
|
.replace('{group}', groupNo)
|
||||||
.replace('{paragraph}', paragraphNo)
|
.replace('{paragraph}', paragraphNo)
|
||||||
.replace('{refs}', citeNumsLabel);
|
.replace('{refs}', citeNumsLabel) + batchSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -170,39 +339,51 @@ export function getCitationReviewGroupMeta(item, index, labels) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建核查队列:每个含引文的正文段落一组,该段全部参考文献一并询问;
|
* 构建核查队列:含引文的正文段落与表格均纳入;每处按最多 4 条参考文献拆批。
|
||||||
* 同一条文献出现在不同段落时,会在各段落中分别询问。
|
|
||||||
*/
|
*/
|
||||||
export function buildCitationReviewQueue(wordList, references) {
|
export function buildCitationReviewQueue(wordList, references, batchSize) {
|
||||||
const items = [];
|
const items = [];
|
||||||
const refList = references || [];
|
const refList = references || [];
|
||||||
|
const size = batchSize || CITATION_REVIEW_BATCH_SIZE;
|
||||||
|
|
||||||
(wordList || []).forEach(function (item, paragraphIndex) {
|
(wordList || []).forEach(function (item, contentIndex) {
|
||||||
if (!isTextParagraphItem(item)) {
|
if (!isCitableReviewItem(item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = item.content || item.text || '';
|
const sourceHtml = getReviewItemSourceHtml(item);
|
||||||
const citeNums = parseCitationNumbersFromHtml(html);
|
const citeNums = parseCitationNumbersFromHtml(sourceHtml);
|
||||||
if (!citeNums.length) {
|
if (!citeNums.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const paragraphText = htmlToPlainText(html);
|
const sourceType = isTableItem(item) ? 'table' : 'paragraph';
|
||||||
const citations = citeNums.map(function (citeNum) {
|
const sourcePlainText = getReviewItemPlainText(item);
|
||||||
return buildCitationEntry(citeNum, refList);
|
const previewHtml = buildReviewContentPreviewHtml(item);
|
||||||
});
|
const citeChunks = chunkCitationNumbers(citeNums, size);
|
||||||
|
const batchTotal = citeChunks.length;
|
||||||
|
|
||||||
items.push({
|
citeChunks.forEach(function (chunkNums, batchIndex) {
|
||||||
paragraphIndex: paragraphIndex,
|
const citations = chunkNums.map(function (citeNum) {
|
||||||
amId: item.am_id,
|
return buildCitationEntry(citeNum, refList);
|
||||||
paragraphHtml: html,
|
});
|
||||||
paragraphText: paragraphText,
|
|
||||||
citeNums: citeNums.slice(),
|
items.push({
|
||||||
citations: citations,
|
contentIndex: contentIndex,
|
||||||
hasMissingReference: citations.some(function (c) {
|
paragraphIndex: contentIndex,
|
||||||
return c.referenceMissing;
|
sourceType: sourceType,
|
||||||
})
|
amId: item.am_id,
|
||||||
|
paragraphHtml: sourceHtml,
|
||||||
|
paragraphText: sourcePlainText,
|
||||||
|
previewHtml: previewHtml,
|
||||||
|
citeNums: chunkNums.slice(),
|
||||||
|
citations: citations,
|
||||||
|
batchIndex: batchIndex + 1,
|
||||||
|
batchTotal: batchTotal,
|
||||||
|
hasMissingReference: citations.some(function (c) {
|
||||||
|
return c.referenceMissing;
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -216,6 +397,7 @@ export function buildWenaiRelevancePrompt(item) {
|
|||||||
|
|
||||||
const paragraphText = item.paragraphText || '';
|
const paragraphText = item.paragraphText || '';
|
||||||
const citations = item.citations || [];
|
const citations = item.citations || [];
|
||||||
|
const isTable = item.sourceType === 'table';
|
||||||
const citeLabels = citations.map(function (c) {
|
const citeLabels = citations.map(function (c) {
|
||||||
return '[' + c.citeNum + ']';
|
return '[' + c.citeNum + ']';
|
||||||
});
|
});
|
||||||
@@ -227,12 +409,18 @@ export function buildWenaiRelevancePrompt(item) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const labelList = citeLabels.join('、') || '';
|
const labelList = citeLabels.join('、') || '';
|
||||||
|
const intro = isTable
|
||||||
|
? '请审读以下表格及其引用文献,结合表格内容、标题与注释,判断各文献与表格的相关程度。'
|
||||||
|
: '请审读以下正文段落及其引用文献,结合该段落的论述内容,判断各文献与正文的相关程度。';
|
||||||
|
const contentLabel = isTable ? '【表格】' : '【正文段落】';
|
||||||
|
const contentSection = isTable
|
||||||
|
? ''
|
||||||
|
: contentLabel + '\n' + paragraphText + '\n\n';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'请审读以下正文段落及其引用文献,结合该段落的论述内容,判断各文献与正文的相关程度。\n\n' +
|
intro +
|
||||||
'【正文段落】\n' +
|
|
||||||
paragraphText +
|
|
||||||
'\n\n' +
|
'\n\n' +
|
||||||
|
contentSection +
|
||||||
'【参考文献】\n' +
|
'【参考文献】\n' +
|
||||||
refBlock.trim() +
|
refBlock.trim() +
|
||||||
'\n\n' +
|
'\n\n' +
|
||||||
@@ -241,8 +429,8 @@ export function buildWenaiRelevancePrompt(item) {
|
|||||||
'请按文献序号 ' +
|
'请按文献序号 ' +
|
||||||
labelList +
|
labelList +
|
||||||
' 依次说明,保留原文序号且顺序连续,不要重新编号或跳号。\n' +
|
' 依次说明,保留原文序号且顺序连续,不要重新编号或跳号。\n' +
|
||||||
'对每条文献分别给出关联判断:直接相关 / 强相关 / 弱相关 / 不相关,并用一句话简要说明理由。\n' +
|
'对每条文献一条条列出分别给出关联判断:直接相关 / 强相关 / 弱相关 / 不相关,并用一句话简要说明理由。\n\n' +
|
||||||
'将全部内容合并写成一段连贯的批注文字,语气客观、专业、克制,可直接作为稿件文件批注使用。'
|
'再结合上述给出的弱相关和不相关的文献写成一段简短的不相关理由批注文字,以编辑的语气建议,可直接作为稿件文件批注使用。'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +458,7 @@ export function buildCitationReviewStandaloneHtml(reviewItems, labels) {
|
|||||||
const copyAllText = l.copyAll || '复制全部';
|
const copyAllText = l.copyAll || '复制全部';
|
||||||
const copySuccessText = l.copySuccess || '已复制';
|
const copySuccessText = l.copySuccess || '已复制';
|
||||||
const copyFailText = l.copyFail || '复制失败';
|
const copyFailText = l.copyFail || '复制失败';
|
||||||
|
const previewTitle = l.previewTitle || '内容预览';
|
||||||
|
|
||||||
let navHtml = '';
|
let navHtml = '';
|
||||||
let bodyHtml = '';
|
let bodyHtml = '';
|
||||||
@@ -280,6 +469,13 @@ export function buildCitationReviewStandaloneHtml(reviewItems, labels) {
|
|||||||
const meta = getCitationReviewGroupMeta(item, i, labels);
|
const meta = getCitationReviewGroupMeta(item, i, labels);
|
||||||
const prompt = buildWenaiRelevancePrompt(item);
|
const prompt = buildWenaiRelevancePrompt(item);
|
||||||
const promptId = 'cite-prompt-' + meta.groupNo;
|
const promptId = 'cite-prompt-' + meta.groupNo;
|
||||||
|
const previewBlock = item.previewHtml
|
||||||
|
? '<div class="group-preview"><div class="group-preview-title">' +
|
||||||
|
escapeHtml(previewTitle) +
|
||||||
|
'</div>' +
|
||||||
|
item.previewHtml +
|
||||||
|
'</div>'
|
||||||
|
: '';
|
||||||
|
|
||||||
navHtml +=
|
navHtml +=
|
||||||
'<a class="nav-link" href="#' +
|
'<a class="nav-link" href="#' +
|
||||||
@@ -302,6 +498,7 @@ export function buildCitationReviewStandaloneHtml(reviewItems, labels) {
|
|||||||
escapeHtml(copyGroupText) +
|
escapeHtml(copyGroupText) +
|
||||||
'</button>' +
|
'</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
previewBlock +
|
||||||
'<pre class="group-prompt" id="' +
|
'<pre class="group-prompt" id="' +
|
||||||
promptId +
|
promptId +
|
||||||
'">' +
|
'">' +
|
||||||
@@ -320,7 +517,7 @@ export function buildCitationReviewStandaloneHtml(reviewItems, labels) {
|
|||||||
'</title>' +
|
'</title>' +
|
||||||
'<style>' +
|
'<style>' +
|
||||||
'*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;background:#f5f7fa;color:#303133;line-height:1.5}' +
|
'*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;background:#f5f7fa;color:#303133;line-height:1.5}' +
|
||||||
'.page{max-width:960px;margin:0 auto;padding:20px}' +
|
'.page{max-width:1400px;margin:0 auto;padding:20px}' +
|
||||||
'.header{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.08)}' +
|
'.header{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.08)}' +
|
||||||
'.header h1{margin:0 0 8px;font-size:20px}' +
|
'.header h1{margin:0 0 8px;font-size:20px}' +
|
||||||
'.summary{color:#606266;font-size:14px;margin-bottom:12px}' +
|
'.summary{color:#606266;font-size:14px;margin-bottom:12px}' +
|
||||||
@@ -337,6 +534,13 @@ export function buildCitationReviewStandaloneHtml(reviewItems, labels) {
|
|||||||
'.group-head h3{margin:0;font-size:15px;color:#303133}' +
|
'.group-head h3{margin:0;font-size:15px;color:#303133}' +
|
||||||
'.copy-btn{border:1px solid #409eff;background:#ecf5ff;color:#409eff;border-radius:4px;padding:4px 12px;font-size:12px;cursor:pointer;white-space:nowrap}' +
|
'.copy-btn{border:1px solid #409eff;background:#ecf5ff;color:#409eff;border-radius:4px;padding:4px 12px;font-size:12px;cursor:pointer;white-space:nowrap}' +
|
||||||
'.copy-btn:hover{background:#409eff;color:#fff}' +
|
'.copy-btn:hover{background:#409eff;color:#fff}' +
|
||||||
|
'.group-preview{margin-bottom:12px;padding:12px;background:#fcfcfd;border:1px solid #ebeef5;border-radius:4px;overflow-x:auto}' +
|
||||||
|
'.group-preview-title{font-size:12px;color:#909399;margin-bottom:8px;font-weight:600}' +
|
||||||
|
'.cite-preview-paragraph{font-size:14px;line-height:1.6;color:#303133}' +
|
||||||
|
'.cite-preview-table-title,.cite-preview-table-note{text-align:center;margin:8px 0;font-size:14px;color:#303133}' +
|
||||||
|
'.cite-preview-table table{width:100%;border-collapse:collapse;font-size:13px;background:#fff}' +
|
||||||
|
'.cite-preview-table td{border:1px solid #dcdfe6;padding:6px 8px;text-align:center;vertical-align:middle;color:#303133}' +
|
||||||
|
'.cite-preview-table tr.oddColor td{background:#f5f7fa}' +
|
||||||
'.group-prompt{margin:0;padding:12px;background:#fafafa;border:1px solid #ebeef5;border-radius:4px;white-space:pre-wrap;word-break:break-word;font-size:13px;font-family:Consolas,"Courier New",monospace}' +
|
'.group-prompt{margin:0;padding:12px;background:#fafafa;border:1px solid #ebeef5;border-radius:4px;white-space:pre-wrap;word-break:break-word;font-size:13px;font-family:Consolas,"Courier New",monospace}' +
|
||||||
'#all-prompt{display:none}' +
|
'#all-prompt{display:none}' +
|
||||||
'</style></head><body><div class="page">' +
|
'</style></head><body><div class="page">' +
|
||||||
@@ -401,6 +605,9 @@ export function buildCitationReviewHtmlLabels(translate) {
|
|||||||
copyAll: t('commonTable.citeRelevanceCopyAllWenai'),
|
copyAll: t('commonTable.citeRelevanceCopyAllWenai'),
|
||||||
copySuccess: t('commonTable.citeRelevanceCopySuccess'),
|
copySuccess: t('commonTable.citeRelevanceCopySuccess'),
|
||||||
copyFail: t('commonTable.citeRelevanceCopyFail'),
|
copyFail: t('commonTable.citeRelevanceCopyFail'),
|
||||||
groupLabel: t('commonTable.citeRelevanceGroupNavLabel')
|
groupLabel: t('commonTable.citeRelevanceGroupNavLabel'),
|
||||||
|
tableGroupLabel: t('commonTable.citeRelevanceTableNavLabel'),
|
||||||
|
batchProgress: t('commonTable.citeRelevanceBatchProgress'),
|
||||||
|
previewTitle: t('commonTable.citeRelevancePreviewTitle')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export function buildReferencesEditableHtml(references, labels) {
|
|||||||
'<title>' + escapeHtml(pageTitle) + '</title>' +
|
'<title>' + escapeHtml(pageTitle) + '</title>' +
|
||||||
'<style>' +
|
'<style>' +
|
||||||
'*{box-sizing:border-box}body{margin:0;font-family:Charis SIL,Georgia,"Times New Roman",serif;background:#f5f7fa;color:#303133;line-height:1.5}' +
|
'*{box-sizing:border-box}body{margin:0;font-family:Charis SIL,Georgia,"Times New Roman",serif;background:#f5f7fa;color:#303133;line-height:1.5}' +
|
||||||
'.page{max-width:920px;margin:0 auto;padding:20px}' +
|
'.page{max-width:1400px;margin:0 auto;padding:20px}' +
|
||||||
'.header{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.08)}' +
|
'.header{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.08)}' +
|
||||||
'.header h1{margin:0 0 8px;font-size:20px;text-align:center;font-style:italic;font-weight:bold;color:#008080}' +
|
'.header h1{margin:0 0 8px;font-size:20px;text-align:center;font-style:italic;font-weight:bold;color:#008080}' +
|
||||||
'.intro{color:#606266;font-size:14px;margin-bottom:12px;white-space:pre-wrap}' +
|
'.intro{color:#606266;font-size:14px;margin-bottom:12px;white-space:pre-wrap}' +
|
||||||
|
|||||||
Reference in New Issue
Block a user