1、审稿人14天超时 重新审稿邀请
2、nbsp 转换 3、H3标记为myh3 4、文章详情审稿和编委邮箱机构显示 5、稿号开头为Draft 状态为Reject->Awaiting Submission 6、作者端稿件重复(标题) 7、produce 增加 通讯作者详细地址 8、produce 增加 是否显示图文摘要1
This commit is contained in:
@@ -19,8 +19,8 @@ const service = axios.create({
|
||||
// baseURL: 'https://submission.tmrjournals.com/', //正式 记得切换
|
||||
// baseURL: 'http://www.tougao.com/', //测试本地 记得切换
|
||||
// baseURL: 'http://192.168.110.110/tougao/public/index.php/',
|
||||
baseURL: '/api', //本地
|
||||
// baseURL: '/', //正式
|
||||
// baseURL: '/api', //本地
|
||||
baseURL: '/', //正式
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ const baseUrl = '/';
|
||||
|
||||
//测试环境
|
||||
|
||||
// const mediaUrl = 'http://tougaotest.tmrjournals.com/public/';
|
||||
// // const mediaUrl = 'http://zmzm.tougao.dev.com/public/';
|
||||
// const baseUrl = '/api';
|
||||
|
||||
|
||||
////新正式环境
|
||||
// const mediaUrl = 'http://mytest.tmrjournals.com/public/';
|
||||
|
||||
@@ -290,12 +290,13 @@ const en = {
|
||||
state1: 'With editor',
|
||||
state2: 'Under review',
|
||||
state3: 'Reject',
|
||||
stateDraft: 'Awaiting Submission',
|
||||
state4: 'Revision',
|
||||
state5: 'Accept',
|
||||
state6: 'Pre-accept',
|
||||
state8: 'Final Decision',
|
||||
act1: 'Dealing',
|
||||
act2: 'Finished'
|
||||
act2: 'Finished',
|
||||
},
|
||||
evaluationsis: {
|
||||
EmploymentRate: 'Employment Rate',
|
||||
|
||||
@@ -276,6 +276,7 @@ const zh = {
|
||||
state1: '已受理',
|
||||
state2: '送审中',
|
||||
state3: '拒稿',
|
||||
stateDraft: '待提交',
|
||||
state4: '退修',
|
||||
state5: '接收',
|
||||
state6: '预接收',
|
||||
|
||||
@@ -780,9 +780,8 @@ export default {
|
||||
var that = this;
|
||||
var str = content.replace(/^<p>\s*(.*?)\s*<\/p>$/, '$1').trim();
|
||||
|
||||
if (str.replace(/<br\s*\/?>/gi, '').trim() === '') {
|
||||
str = '';
|
||||
}
|
||||
str = str.replace(/<br\s*\/?>/gi, '');
|
||||
|
||||
str = await that.$commonJS.decodeHtml(str);
|
||||
|
||||
await that.$api
|
||||
@@ -1138,7 +1137,7 @@ export default {
|
||||
});
|
||||
},
|
||||
async addCommentSetting(content) {
|
||||
|
||||
|
||||
await this.$api
|
||||
.post(this.urlList.addComment, {
|
||||
am_id: content.am_id,
|
||||
@@ -1161,8 +1160,10 @@ export default {
|
||||
});
|
||||
},
|
||||
async addComment(content) {
|
||||
|
||||
var str = content.replace(/^<p>(.*?)<\/p>$/, '$1') ? content.replace(/^<p>(.*?)<\/p>$/, '$1') : '';
|
||||
|
||||
var str= this.$commonJS.transformHtmlString(content)
|
||||
str=str.replace(/<br\s*\/?>/gi, '');
|
||||
console.log("🚀 ~ addComment ~ content:", str);
|
||||
if (str == '') {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
@@ -1884,6 +1885,9 @@ export default {
|
||||
// 确定保存图片
|
||||
async savePic() {
|
||||
var str = this.picStyle1.note ? await this.$commonJS.decodeHtml(this.picStyle1.note) : '';
|
||||
|
||||
|
||||
|
||||
var titleStr = this.picStyle1.title ? await this.$commonJS.decodeHtml(this.picStyle1.title) : '';
|
||||
|
||||
if (!this.picStyle.picUrl) {
|
||||
@@ -1894,6 +1898,8 @@ export default {
|
||||
this.$message.error('Please enter a title');
|
||||
return;
|
||||
}
|
||||
str = str.replace(/<br\s*\/?>/gi, '');
|
||||
titleStr = titleStr.replace(/<br\s*\/?>/gi, '');
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading...',
|
||||
@@ -1969,28 +1975,42 @@ export default {
|
||||
},
|
||||
async saveTable(content) {
|
||||
const cleanTableData = (tableList) => {
|
||||
if (tableList.length == 0) {
|
||||
return [];
|
||||
} else {
|
||||
// 假设第一行是表头,保存表头
|
||||
const header = tableList[0];
|
||||
if (tableList.length == 0) {
|
||||
return [];
|
||||
} else {
|
||||
// 定义清理函数:去掉所有 br 标签和 TinyMCE 占位符
|
||||
const cleanText = (text) => {
|
||||
if (!text) return "";
|
||||
return text.replace(/<br\s*\/?>/gi, '').trim();
|
||||
};
|
||||
|
||||
// 从第二行开始,移除与表头相同的行
|
||||
const cleanedTable = tableList.filter((row, index) => {
|
||||
// 如果是第一行,则保留
|
||||
if (index === 0) return true;
|
||||
// 1. 获取处理后的干净表头
|
||||
const header = tableList[0].map(cell => ({
|
||||
...cell,
|
||||
text: cleanText(cell.text)
|
||||
}));
|
||||
|
||||
// 比较当前行的每个单元格与表头是否相同
|
||||
const isHeaderRow = row.every((cell, cellIndex) => {
|
||||
return cell.text === header[cellIndex].text;
|
||||
});
|
||||
// 2. 过滤逻辑
|
||||
const cleanedTable = tableList.map((row) => {
|
||||
// 首先:把每一行里的每个 cell.text 里的 <br> 都去掉
|
||||
return row.map(cell => ({
|
||||
...cell,
|
||||
text: cleanText(cell.text)
|
||||
}));
|
||||
}).filter((row, index) => {
|
||||
if (index === 0) return true;
|
||||
|
||||
return !isHeaderRow; // 只保留与表头不同的行
|
||||
});
|
||||
// 3. 此时比较的就是没有 <br> 的文本了
|
||||
const isHeaderRow = row.every((cell, cellIndex) => {
|
||||
return cell.text === header[cellIndex].text;
|
||||
});
|
||||
|
||||
return cleanedTable;
|
||||
}
|
||||
};
|
||||
return !isHeaderRow;
|
||||
});
|
||||
|
||||
return cleanedTable;
|
||||
}
|
||||
};
|
||||
var cleanedTableList = content.table ? content.table : [];
|
||||
|
||||
cleanedTableList = cleanTableData(content.table);
|
||||
@@ -2014,11 +2034,15 @@ export default {
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
strNote = strNote.replace(/<br\s*\/?>/gi, '');
|
||||
strTitle = strTitle.replace(/<br\s*\/?>/gi, '');
|
||||
var tableStr=JSON.stringify(cleanedTableList)
|
||||
|
||||
if (this.lineStyle.visiTitle == 'Edit Table') {
|
||||
this.$api
|
||||
.post(this.urlList.editTable, {
|
||||
amt_id: this.lineStyle.amt_id,
|
||||
table_data: JSON.stringify(cleanedTableList),
|
||||
table_data: tableStr,
|
||||
html_data: content.html_data,
|
||||
note: strNote,
|
||||
title: strTitle
|
||||
|
||||
@@ -928,7 +928,7 @@
|
||||
<div>
|
||||
<span>Status : </span>
|
||||
<b>{{ articleState }}</b>
|
||||
<el-button type="text" @click="testvis" icon="el-icon-edit">Change</el-button>
|
||||
<el-button type="text" @click="testvis" icon="el-icon-edit" v-if="!(form.is_draft==1&&form.state==3)">Change</el-button>
|
||||
</div>
|
||||
<div style="display: flex; width: 100%">
|
||||
<span>Remarks :</span>
|
||||
@@ -1553,6 +1553,7 @@ export default {
|
||||
remarks: '',
|
||||
state: '',
|
||||
ctime: '',
|
||||
is_draft: '',
|
||||
authorList: [],
|
||||
transList: []
|
||||
},
|
||||
@@ -1788,10 +1789,17 @@ export default {
|
||||
},
|
||||
articleState: function () {
|
||||
let str = '';
|
||||
switch (this.form.state) {
|
||||
|
||||
|
||||
if(this.form.is_draft==1&&this.form.state==3){
|
||||
str = this.$t('artstate.stateDraft');
|
||||
return str;
|
||||
}else{
|
||||
switch (this.form.state) {
|
||||
case 0:
|
||||
str = this.$t('artstate.state0');
|
||||
break;
|
||||
|
||||
case 1:
|
||||
str = this.$t('artstate.state1');
|
||||
break;
|
||||
@@ -1814,7 +1822,9 @@ export default {
|
||||
str = this.$t('artstate.state6');
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -2540,6 +2550,7 @@ export default {
|
||||
this.form.is_use_ai = res.article.is_use_ai;
|
||||
this.form.use_ai_explain = res.article.use_ai_explain;
|
||||
this.form.transList = res.transfer;
|
||||
this.form.is_draft = res.article.is_draft;
|
||||
this.msgs = res.msg;
|
||||
var alist = res.authors;
|
||||
let alist_name = [];
|
||||
|
||||
@@ -87,9 +87,13 @@
|
||||
</p> -->
|
||||
|
||||
<div class="man_state" :style="item.state,'3' | stateChange" >
|
||||
<b :style="item.state,'4' | stateChange">
|
||||
<b :style="item.state,'4' | stateChange" v-if="item.is_draft==1&&item.state==3">
|
||||
{{$t('artstate.stateDraft')}}
|
||||
</b>
|
||||
<b :style="item.state,'4' | stateChange" v-else>
|
||||
{{item.state,'tst' | stateChange}}
|
||||
</b>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="man_btn" style="overflow: hidden;">
|
||||
@@ -1058,7 +1062,7 @@ this.$router.push({
|
||||
border: 1px solid #fff;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 6px 18px;
|
||||
padding: 6px 12px;
|
||||
letter-spacing: -0.5px;
|
||||
border-top-right-radius: 3px;
|
||||
/* border-top-left-radius: 3px; */
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
<span style="float: right">
|
||||
<span class="labelTitle" style="font-weight: 500; font-size: 13px">Status :</span>
|
||||
<font style="margin-right: 15px; font-size: 13px; letter-spacing: -0.5px; font-weight: 700">
|
||||
{{ stateFormat(item.state) }}
|
||||
{{ stateFormat(item.is_draft==1&&item.state==3?'draft':item.state) }}
|
||||
</font>
|
||||
</span>
|
||||
</p>
|
||||
@@ -2629,6 +2629,9 @@ export default {
|
||||
case 0:
|
||||
str = this.$t('artstate.state0');
|
||||
break;
|
||||
case 'draft':
|
||||
str = this.$t('artstate.stateDraft');
|
||||
break;
|
||||
case 1:
|
||||
str = this.$t('artstate.state1');
|
||||
break;
|
||||
|
||||
@@ -96,6 +96,11 @@
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Use the Picture as Graphic Abstract :" prop="is_graphical_abstract" label-width="260px">
|
||||
<el-radio v-model="detailMes.is_graphical_abstract" :label="1">Yes</el-radio>
|
||||
<el-radio v-model="detailMes.is_graphical_abstract" :label="2">No</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item label="Type :" prop="type">
|
||||
<el-select v-model="detailMes.type" filterable placeholder="Please select an article type">
|
||||
<el-option v-for="item in opMedical" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
@@ -108,65 +113,61 @@
|
||||
<el-input v-model="detailMes.tradition_tag" placeholder="eg :Highlights"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Tradition Content :">
|
||||
<tinymce
|
||||
<div class="tinymce-container">
|
||||
<div v-if="tradition==null" class="loading-status loadTinymceBox">
|
||||
<i class="el-icon-loading"></i> Fetching highlights, please wait...
|
||||
</div>
|
||||
<tinymce v-else
|
||||
type="tradition"
|
||||
:height="160"
|
||||
id="tiny-tradition"
|
||||
ref="tinymceChild2"
|
||||
:tinymceOtherInit="{
|
||||
forced_root_block: '',
|
||||
newline_behavior: 'linebreak',
|
||||
newline_behavior: 'linebreak'
|
||||
}"
|
||||
valid_elements=",br"
|
||||
:wordStyle="`p{font-size: 13px;}`"
|
||||
:isAutomaticUpdate="true"
|
||||
@getContent="getContent"
|
||||
@updateChange="(content) => updateChange('tradition',content)"
|
||||
@updateChange="(content) => updateChange('tradition', content)"
|
||||
:value="tradition"
|
||||
class="paste-area text-container"
|
||||
:toolbar="[
|
||||
'bold italic |customBlue removeBlue|myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton'
|
||||
]"
|
||||
style="
|
||||
line-height: 12px;
|
||||
overflow: auto;
|
||||
font-size: 13px; /* 字体大小 */
|
||||
margin-top: 0pt; /* 段前间距 */
|
||||
margin-bottom: 0pt; /* 段后间距 */
|
||||
"
|
||||
style="line-height: 12px; overflow: auto; font-size: 13px; margin-top: 0pt; margin-bottom: 0pt"
|
||||
></tinymce>
|
||||
|
||||
</div>
|
||||
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.tradition" :options="editorOption"> </quill-editor> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="Medical history of objective :">
|
||||
|
||||
<tinymce
|
||||
<div class="tinymce-container">
|
||||
<div v-if="mhooStr==null" class="loading-status loadTinymceBox">
|
||||
<i class="el-icon-loading"></i> Fetching medical history of objective, please wait...
|
||||
</div>
|
||||
<tinymce v-else
|
||||
type="mhooStr"
|
||||
:height="160"
|
||||
ref="tinymceChild3"
|
||||
:tinymceOtherInit="{
|
||||
forced_root_block: '',
|
||||
newline_behavior: 'linebreak',
|
||||
newline_behavior: 'linebreak'
|
||||
}"
|
||||
valid_elements=",br"
|
||||
:wordStyle="`p{font-size: 13px;}`"
|
||||
:isAutomaticUpdate="true"
|
||||
@getContent="getContent"
|
||||
@updateChange="(content) => updateChange('mhooStr',content)"
|
||||
id="tiny-mhoo"
|
||||
@updateChange="(content) => updateChange('mhooStr', content)"
|
||||
:value="mhooStr"
|
||||
class="paste-area text-container"
|
||||
:toolbar="[
|
||||
'bold italic |customBlue removeBlue|myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton'
|
||||
]"
|
||||
style="
|
||||
line-height: 12px;
|
||||
overflow: auto;
|
||||
font-size: 13px; /* 字体大小 */
|
||||
margin-top: 0pt; /* 段前间距 */
|
||||
margin-bottom: 0pt; /* 段后间距 */
|
||||
"
|
||||
style="line-height: 12px; overflow: auto; font-size: 13px; margin-top: 0pt; margin-bottom: 0pt"
|
||||
></tinymce>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.mhoo" :options="editorOption"> </quill-editor> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="keywords :" prop="keywords">
|
||||
@@ -188,27 +189,27 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="Abstract :" prop="abstract">
|
||||
<template slot="label"> <span style="color: #f56c6c; margin-right: 4px">*</span>Abstract : </template>
|
||||
<tinymce
|
||||
type="Abstract"
|
||||
:height="160"
|
||||
ref="tinymceChild1"
|
||||
:wordStyle="`p{font-size: 13px;}`"
|
||||
:isAutomaticUpdate="true"
|
||||
@getContent="getContent"
|
||||
@updateChange="(content) => updateChange('abstract',content)"
|
||||
:value="abstract"
|
||||
class="paste-area text-container"
|
||||
:toolbar="[
|
||||
'bold italic |customBlue removeBlue|myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton'
|
||||
]"
|
||||
style="
|
||||
line-height: 12px;
|
||||
overflow: auto;
|
||||
font-size: 13px; /* 字体大小 */
|
||||
margin-top: 0pt; /* 段前间距 */
|
||||
margin-bottom: 0pt; /* 段后间距 */
|
||||
"
|
||||
></tinymce>
|
||||
<div class="tinymce-container">
|
||||
<div v-if="abstract==null" class="loading-status loadTinymceBox">
|
||||
<i class="el-icon-loading"></i> Fetching abstract, please wait...
|
||||
</div>
|
||||
|
||||
<tinymce
|
||||
v-else
|
||||
type="Abstract"
|
||||
:height="160"
|
||||
ref="tinymceChild1"
|
||||
id="tiny-abstract"
|
||||
:wordStyle="`p{font-size: 13px;}`"
|
||||
:isAutomaticUpdate="true"
|
||||
@getContent="getContent"
|
||||
@updateChange="(content) => updateChange('abstract', content)"
|
||||
:value="abstract"
|
||||
class="paste-area text-container"
|
||||
:toolbar="['bold italic |customBlue removeBlue|myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton']"
|
||||
style="line-height: 12px; overflow: auto; font-size: 13px; margin-top: 0pt; margin-bottom: 0pt"
|
||||
></tinymce>
|
||||
</div>
|
||||
|
||||
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.abstract" :options="editorOption"> </quill-editor> -->
|
||||
</el-form-item>
|
||||
@@ -266,6 +267,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="author_country" label="Country" width="140px"></el-table-column>
|
||||
<el-table-column prop="orcid" label="ORCID"></el-table-column>
|
||||
<el-table-column prop="mailing_address" label="Corresponding author details" min-width="160px"></el-table-column>
|
||||
<el-table-column label="" width="190" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div class="operation">
|
||||
@@ -292,7 +294,7 @@
|
||||
</el-table>
|
||||
<!-- 添加作者弹出框 -->
|
||||
<el-dialog title="Add author" :visible.sync="addAuthor" width="650px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form ref="add_Author" :model="addFomauthor" :rules="rules" label-width="165px">
|
||||
<el-form ref="add_Author" :model="addFomauthor" :rules="rules" label-width="215px">
|
||||
<el-form-item label="Author first name :" prop="first_name">
|
||||
<el-input v-model="addFomauthor.first_name"></el-input>
|
||||
</el-form-item>
|
||||
@@ -312,7 +314,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="Email :" v-if="addFomauthor.is_report != '1'">
|
||||
<el-input v-model="editFomauthor.email" type="email"></el-input>
|
||||
<el-input v-model="addFomauthor.email" type="email"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Email :" prop="email" v-if="addFomauthor.is_report == '1'">
|
||||
<el-input v-model="addFomauthor.email" type="email"></el-input>
|
||||
@@ -350,6 +352,17 @@
|
||||
<template slot="prepend">https://orcid.org/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:required="addFomauthor.is_report == '1'"
|
||||
label="Corresponding author details :"
|
||||
prop="mailing_address"
|
||||
>
|
||||
<el-input
|
||||
v-model="addFomauthor.mailing_address"
|
||||
type="textarea"
|
||||
placeholder="eg: Author full name. Affiliation address. Email."
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addAuthor = false">Canel</el-button>
|
||||
@@ -358,7 +371,7 @@
|
||||
</el-dialog>
|
||||
<!-- 编辑作者弹出框 -->
|
||||
<el-dialog title="Edit Author" :visible.sync="editAuthor" width="650px" :close-on-click-modal="false">
|
||||
<el-form ref="edit_Author" :model="editFomauthor" :rules="rules" label-width="165px">
|
||||
<el-form ref="edit_Author" :model="editFomauthor" :rules="rules" label-width="215px">
|
||||
<el-form-item label="Author first name :" prop="first_name">
|
||||
<el-input v-model="editFomauthor.first_name"></el-input>
|
||||
</el-form-item>
|
||||
@@ -415,6 +428,18 @@
|
||||
<template slot="prepend">https://orcid.org/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
:required="editFomauthor.is_report == '1'"
|
||||
label="Corresponding author details :"
|
||||
prop="mailing_address"
|
||||
>
|
||||
<el-input
|
||||
v-model="editFomauthor.mailing_address"
|
||||
type="textarea"
|
||||
placeholder="eg: Author full name. Affiliation address. Email."
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editAuthor = false">Cancel</el-button>
|
||||
@@ -688,7 +713,7 @@
|
||||
<div class="bor_style_onli">
|
||||
<h4>{{ tabsList[5].name }}</h4>
|
||||
<div style="font-size: 14px">
|
||||
<div style="margin: 30px 0px 0 0">
|
||||
<div style="margin: 30px 0px 0 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px">Improve information</h5>
|
||||
<!-- 时间Doi简介信息 -->
|
||||
<el-form ref="Abs_Form" :model="detailMes" :rules="rules" label-width="150px" style="margin-top: 30px">
|
||||
@@ -709,80 +734,97 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="text-align: center; margin: 0px 0 0 0">
|
||||
<el-button type="primary" @click="ZsSaveAbs" class="save-btn" style="margin-top: 10px;">
|
||||
<el-button type="primary" @click="ZsSaveAbs" class="save-btn" style="margin-top: 10px">
|
||||
<i class="el-icon-check"></i>
|
||||
Save Essential Information
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 1px; background-color: #c5e1f1; width: 100%; margin: 80px 0 40px"></div>
|
||||
<div style="display: flex; /* 开启 flex 布局 */
|
||||
justify-content: space-between;
|
||||
padding: 20px;">
|
||||
<div class="left-panel">
|
||||
<div style="margin: 0 0 40px 0">
|
||||
Choose Template :
|
||||
<el-select v-model="shuTter.board" placeholder="Please select a template..." @change="select_tem($event)" style="width: 225px">
|
||||
<el-option v-for="item in fol_low" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
<el-button type="primary" plain style="width: 150px; margin: 0 5px 0 15px" @click="EstaBlish">
|
||||
<i class="el-icon-document"></i> Create Manuscript
|
||||
</el-button>
|
||||
</div>
|
||||
<div style="display: flex; /* 开启 flex 布局 */ justify-content: space-between; padding: 20px">
|
||||
<div class="left-panel">
|
||||
<div style="margin: 0 0 40px 0">
|
||||
Choose Template :
|
||||
<el-select
|
||||
v-model="shuTter.board"
|
||||
placeholder="Please select a template..."
|
||||
@change="select_tem($event)"
|
||||
style="width: 225px"
|
||||
>
|
||||
<el-option v-for="item in fol_low" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button type="primary" plain style="width: 150px; margin: 0 5px 0 15px" @click="EstaBlish">
|
||||
<i class="el-icon-document"></i> Create Manuscript
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div style="margin: 30px 0 40px 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px">Download list</h5>
|
||||
<p v-if="DLfileList.length == 0" style="color: #666; font-size: 14px">No Manuscript</p>
|
||||
<div v-for="(item, index) in DLfileList" :key="index" class="load_pdf">
|
||||
<img src="../../assets/img/icon_0.png" />
|
||||
<span style="color: #333">Typesetting {{ index + 1 }}</span>
|
||||
<span style="margin-left: 40px; color: #888; font-size: 13px">Time : {{ modifDate(item.ctime * 1000) }}</span>
|
||||
<a :href="'/tsfile/' + item.url" target="_blank" style="margin-left: 40px">
|
||||
<i class="el-icon-download" style="color: #66b1ff; font-weight: bold"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 30px 0 40px 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px">Download list</h5>
|
||||
<p v-if="DLfileList.length == 0" style="color: #666; font-size: 14px">No Manuscript</p>
|
||||
<div v-for="(item, index) in DLfileList" :key="index" class="load_pdf">
|
||||
<img src="../../assets/img/icon_0.png" />
|
||||
<span style="color: #333">Typesetting {{ index + 1 }}</span>
|
||||
<span style="margin-left: 40px; color: #888; font-size: 13px"
|
||||
>Time : {{ modifDate(item.ctime * 1000) }}</span
|
||||
>
|
||||
<a :href="'/tsfile/' + item.url" target="_blank" style="margin-left: 40px">
|
||||
<i class="el-icon-download" style="color: #66b1ff; font-weight: bold"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<h5 style="font-size: 14px; margin: 0 0 40px 0">
|
||||
<el-button
|
||||
type="success"
|
||||
icon="el-icon-printer"
|
||||
style="width: 150px; height: 32px; font-size: 12px; margin-right: 14px"
|
||||
:loading="isGenerating"
|
||||
@click="generatePDF"
|
||||
>
|
||||
{{ isGenerating ? 'Generating PDF...' : 'Generate PDF' }}
|
||||
</el-button>
|
||||
<span>Click the button below to start high-quality PDF typesetting.</span>
|
||||
</h5>
|
||||
<div style="margin: 30px 0 40px 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px; font-weight: bold">
|
||||
Download list
|
||||
<span
|
||||
><i
|
||||
class="el-icon-refresh"
|
||||
style="color: #006699; font-weight: bold; margin-left: 6px; cursor: pointer"
|
||||
@click="refreshPdfList"
|
||||
></i
|
||||
></span>
|
||||
|
||||
<span
|
||||
v-if="detailMes.file_sub_table"
|
||||
style="color: #006699; font-size: 13px; font-weight: normal; float: right"
|
||||
>Supplementary Material :<a
|
||||
:href="'/public/articleSUBTAB/' + detailMes.file_sub_table"
|
||||
target="_blank"
|
||||
style="margin-left: 20px"
|
||||
>
|
||||
<i class="el-icon-download" style="color: #006699; font-weight: bold"></i> </a
|
||||
></span>
|
||||
</h5>
|
||||
<p v-if="PDFfileList.length == 0" style="color: #666; font-size: 14px">No Manuscript</p>
|
||||
<div v-for="(item, index) in PDFfileList" :key="index" class="load_pdf">
|
||||
<img src="../../assets/img/icon_pdf.png" style="width: 26px; height: 26px" />
|
||||
<span style="color: #333">Typesetting {{ index + 1 }}</span>
|
||||
<span style="margin-left: 40px; color: #888; font-size: 13px"
|
||||
>Time : {{ modifDate(item.create_time * 1000) }}</span
|
||||
>
|
||||
<a :href="'/public/' + item.url" target="_blank" style="margin-left: 40px">
|
||||
<i class="el-icon-download" style="color: #66b1ff; font-weight: bold"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<h5 style="font-size: 14px; margin: 0 0 40px 0;">
|
||||
|
||||
<el-button
|
||||
type="success"
|
||||
icon="el-icon-printer"
|
||||
style="width: 150px; height: 32px; font-size: 12px;margin-right: 14px;"
|
||||
:loading="isGenerating"
|
||||
@click="generatePDF"
|
||||
>
|
||||
|
||||
{{ isGenerating ? 'Generating PDF...' : 'Generate PDF' }}
|
||||
</el-button>
|
||||
<span>Click the button below to start high-quality PDF typesetting.</span>
|
||||
</h5>
|
||||
<div style="margin: 30px 0 40px 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px;font-weight: bold;">Download list
|
||||
<span><i class="el-icon-refresh" style="color: #006699; font-weight: bold;margin-left: 6px;cursor: pointer;" @click="refreshPdfList"></i></span>
|
||||
|
||||
<span v-if="detailMes.file_sub_table" style="color: #006699; font-size: 13px;font-weight: normal;float: right;">Supplementary Material :<a :href="'/public/articleSUBTAB/' +detailMes.file_sub_table" target="_blank" style="margin-left: 20px">
|
||||
<i class="el-icon-download" style="color: #006699; font-weight: bold"></i>
|
||||
</a></span>
|
||||
</h5>
|
||||
<p v-if="PDFfileList.length == 0" style="color: #666; font-size: 14px">No Manuscript</p>
|
||||
<div v-for="(item, index) in PDFfileList" :key="index" class="load_pdf">
|
||||
<img src="../../assets/img/icon_pdf.png" style="width: 26px; height: 26px;" />
|
||||
<span style="color: #333">Typesetting {{ index + 1 }}</span>
|
||||
<span style="margin-left: 40px; color: #888; font-size: 13px">Time : {{ modifDate(item.create_time * 1000) }}</span>
|
||||
<a :href="'/public/' + item.url" target="_blank" style="margin-left: 40px">
|
||||
<i class="el-icon-download" style="color: #66b1ff; font-weight: bold"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 1px; background-color: #c5e1f1; width: 100%; margin: 10px 0"></div>
|
||||
<div style="margin: 30px 0 30px 0">
|
||||
<h5 style="font-size: 16px; margin: 0 0 30px 0; letter-spacing: -0.5px">Upload the final typeset file</h5>
|
||||
@@ -829,7 +871,6 @@
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1030,7 +1071,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
isGenerating: false, // 按钮加载状态
|
||||
percentage: 0, // 进度条
|
||||
percentage: 0, // 进度条
|
||||
finalReview: null,
|
||||
baseUrl: this.Common.baseUrl,
|
||||
mediaUrl: this.Common.mediaUrl,
|
||||
@@ -1096,11 +1137,13 @@ export default {
|
||||
],
|
||||
detailMes: {
|
||||
type: '',
|
||||
is_graphical_abstract: '3',
|
||||
journal_special_id: 'None'
|
||||
},
|
||||
abstract: '',
|
||||
tradition: '',
|
||||
mhooStr: '',
|
||||
abstract: null,
|
||||
|
||||
tradition:null,
|
||||
mhooStr: null,
|
||||
opInstal: [],
|
||||
// opMedical: [
|
||||
// {
|
||||
@@ -1475,6 +1518,40 @@ export default {
|
||||
message: 'Please use English characters only',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
is_graphical_abstract: [
|
||||
{
|
||||
required: true,
|
||||
validator: function (rule, value, callback) {
|
||||
if (value == 1 || value == 2) {
|
||||
callback();
|
||||
} else {
|
||||
// 这里的英文提示更加符合地道的校验语境
|
||||
callback(
|
||||
new Error(
|
||||
'Please select whether the uploaded picture should be shown as graphic abstract on the PDF title page.'
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
trigger: 'change' // 建议下拉框用 change,失去焦点用 blur
|
||||
}
|
||||
],
|
||||
mailing_address: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
var formData = this.addAuthor ? this.addFomauthor : this.editFomauthor;
|
||||
if (formData.is_report == '1') {
|
||||
if (!value || value.trim() === '') {
|
||||
// 更加正式的表达:请提供通讯作者的详细信息
|
||||
return callback(new Error('Please provide the corresponding author details.'));
|
||||
}
|
||||
}
|
||||
// 必须确保所有逻辑路径都能执行到 callback()
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change'] // 建议加上 change,体验更好
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -1484,7 +1561,6 @@ export default {
|
||||
this.getHight();
|
||||
window.addEventListener('resize', this.getHight);
|
||||
this.getData();
|
||||
|
||||
this.getAuthorJG();
|
||||
this.getCount();
|
||||
this.getWorldPdf();
|
||||
@@ -1492,30 +1568,29 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async generatePDF() {
|
||||
// 1. 验证逻辑(保持原样)
|
||||
// 1. 验证逻辑(保持原样)
|
||||
|
||||
try {
|
||||
this.isGenerating = true; // 开启加载
|
||||
try {
|
||||
this.isGenerating = true; // 开启加载
|
||||
|
||||
// 注意:这里要加 await,确保拿到结果后再往下走
|
||||
const res = await this.$api.post('api/Production/createArticlePdf', {
|
||||
p_article_id: this.p_article_id
|
||||
});
|
||||
// 注意:这里要加 await,确保拿到结果后再往下走
|
||||
const res = await this.$api.post('api/Production/createArticlePdf', {
|
||||
p_article_id: this.p_article_id
|
||||
});
|
||||
|
||||
if (res.status == 1) {
|
||||
this.$message.success("The PDF document is being processed. Please wait and refresh the page in one minute.");
|
||||
} else {
|
||||
this.$message.error("Generation failed, please try again.");
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.$message.error("Network error, please try again.");
|
||||
} finally {
|
||||
// 只有请求真正完成后,才会执行这里
|
||||
this.isGenerating = false;
|
||||
}
|
||||
},
|
||||
if (res.status == 1) {
|
||||
this.$message.success('The PDF document is being processed. Please wait and refresh the page in one minute.');
|
||||
} else {
|
||||
this.$message.error('Generation failed, please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.$message.error('Network error, please try again.');
|
||||
} finally {
|
||||
// 只有请求真正完成后,才会执行这里
|
||||
this.isGenerating = false;
|
||||
}
|
||||
},
|
||||
getArticleFinal(id) {
|
||||
// api/Finalreview/getRecord
|
||||
this.$api
|
||||
@@ -1524,7 +1599,6 @@ export default {
|
||||
// article_id: 6075
|
||||
})
|
||||
.then((res) => {
|
||||
|
||||
if (res.status == 1) {
|
||||
this.finalReview = res.data;
|
||||
} else {
|
||||
@@ -1533,17 +1607,13 @@ export default {
|
||||
});
|
||||
},
|
||||
updateChange(type, content) {
|
||||
|
||||
this[type] = content;
|
||||
},
|
||||
|
||||
getTinymceContent(type) {
|
||||
|
||||
this.$refs.tinymceChild1.getContent(type);
|
||||
},
|
||||
getContent(type, content) {
|
||||
|
||||
},
|
||||
getContent(type, content) {},
|
||||
// 跳转文章详情
|
||||
showdetaileditor(data) {
|
||||
this.$router.push({
|
||||
@@ -1583,45 +1653,39 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getData() {
|
||||
this.idform.p_article_id = this.p_article_id;
|
||||
this.detailMes.p_article_id = this.p_article_id;
|
||||
this.addFomauthor.p_article_id = this.p_article_id;
|
||||
this.addFomschool.p_article_id = this.p_article_id;
|
||||
this.UpTypeFile.p_article_id = this.p_article_id;
|
||||
this.abstract = '';
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
this.idform.p_article_id = this.p_article_id;
|
||||
this.detailMes.p_article_id = this.p_article_id;
|
||||
this.detailMes.is_graphical_abstract = 3;
|
||||
this.addFomauthor.p_article_id = this.p_article_id;
|
||||
this.addFomschool.p_article_id = this.p_article_id;
|
||||
this.UpTypeFile.p_article_id = this.p_article_id;
|
||||
this.abstract = null;
|
||||
this.tradition = null;
|
||||
this.mhooStr = null;
|
||||
|
||||
|
||||
|
||||
// 获取文章信息
|
||||
this.$api
|
||||
.post('api/Production/getProductionDetail', this.idform)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
if (res.code == 0) {
|
||||
|
||||
this.abstract = res.data.production.abstract ? res.data.production.abstract : '';
|
||||
this.tradition = res.data.production.tradition ? res.data.production.tradition : '';
|
||||
this.mhooStr = res.data.production.mhoo ? res.data.production.mhoo : '';
|
||||
|
||||
this.detailMes = res.data.production;
|
||||
this.abstract = res.data.production.abstract?res.data.production.abstract:'';
|
||||
this.tradition = res.data.production.tradition?res.data.production.tradition:'';
|
||||
this.mhooStr = res.data.production.mhoo?res.data.production.mhoo:'';
|
||||
if (this.abstract != '') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tinymceChild1.setContent(this.abstract);
|
||||
});
|
||||
}
|
||||
if (this.tradition != '') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tinymceChild2.setContent(this.tradition);
|
||||
});
|
||||
}
|
||||
if (this.mhooStr != '') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tinymceChild3.setContent(this.mhooStr);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.UpTyFIle = res.data.production.file_pdf;
|
||||
this.getArticleFinal(res.data.production.article_id);
|
||||
if (res.data.production.icon != '') {
|
||||
@@ -1785,7 +1849,8 @@ export default {
|
||||
this.$message.error(err);
|
||||
});
|
||||
},
|
||||
refreshPdfList(){ const loading = this.$loading({
|
||||
refreshPdfList() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: 'Loading...',
|
||||
spinner: 'el-icon-loading',
|
||||
@@ -1800,22 +1865,19 @@ export default {
|
||||
},
|
||||
getPdfList() {
|
||||
// 可以下载的word列表
|
||||
|
||||
|
||||
this.$api
|
||||
.post('/api/Production/getProductionArticlePdf', {
|
||||
p_article_id: this.p_article_id
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status == 1) {
|
||||
|
||||
this.PDFfileList = res.data;
|
||||
} else {
|
||||
|
||||
this.$message.error(res.msg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
this.$message.error(err);
|
||||
});
|
||||
},
|
||||
@@ -1944,7 +2006,7 @@ export default {
|
||||
return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page;
|
||||
},
|
||||
async abstractFormat(content) {
|
||||
content = this.$commonJS.transformHtmlString(content,'content',{keepBr:true});
|
||||
content = this.$commonJS.transformHtmlString(content, 'content', { keepBr: true });
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = content;
|
||||
var imgTags = div.getElementsByTagName('img');
|
||||
@@ -1969,41 +2031,46 @@ export default {
|
||||
}
|
||||
// 处理 p 标签 + 解码
|
||||
content = div.innerHTML;
|
||||
|
||||
|
||||
content = content.replace(/^<p>\s*(.*?)\s*<\/p>$/, '$1').trim();
|
||||
|
||||
|
||||
content = await this.$commonJS.decodeHtml(content);
|
||||
content = content.replace(/ |\u00A0/g, ' ');
|
||||
|
||||
|
||||
return content;
|
||||
},
|
||||
// 1----保存稿件信息
|
||||
async ZsSaveMes() {
|
||||
|
||||
var abstractStr = '';
|
||||
var mhooStr = '';
|
||||
var traditionStr = '';
|
||||
if (this.detailMes.journal_stage_id == 0) {
|
||||
this.$message.error('Please select an installment!');
|
||||
return;
|
||||
} if (this.tradition!='') {
|
||||
}
|
||||
if (this.tradition != '') {
|
||||
traditionStr = await this.abstractFormat(this.tradition);
|
||||
}
|
||||
if (this.mhooStr!='') {
|
||||
}
|
||||
if (this.mhooStr != '') {
|
||||
mhooStr = await this.abstractFormat(this.mhooStr);
|
||||
}
|
||||
|
||||
|
||||
if (this.abstract == '') {
|
||||
this.$message.error('Please input abstract!');
|
||||
return false;
|
||||
} else {
|
||||
abstractStr = await this.abstractFormat(this.abstract);
|
||||
}
|
||||
|
||||
|
||||
this.$refs.Mes_Form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$api
|
||||
.post('api/Production/editProduction', { ...this.detailMes, abstract: abstractStr, mhoo: mhooStr, tradition: traditionStr })
|
||||
.post('api/Production/editProduction', {
|
||||
...this.detailMes,
|
||||
abstract: abstractStr,
|
||||
mhoo: mhooStr,
|
||||
tradition: traditionStr
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`Successfully save the article!`);
|
||||
@@ -2025,6 +2092,10 @@ export default {
|
||||
|
||||
// 2----添加作者操作
|
||||
add_Authorclick(index, row) {
|
||||
if (this.schoolData.length == 0) {
|
||||
this.$message.error('Please provide at least one institutional affiliation.');
|
||||
return;
|
||||
}
|
||||
this.aid = index;
|
||||
this.addFomauthor = {
|
||||
is_first: '0',
|
||||
@@ -2035,7 +2106,6 @@ export default {
|
||||
this.addAuthor = true;
|
||||
},
|
||||
authorAdd(addFomauthor) {
|
||||
console.log(this.addFomauthor);
|
||||
this.$refs.add_Author.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$api
|
||||
@@ -2982,7 +3052,6 @@ export default {
|
||||
// 获取文章信息
|
||||
this.$api
|
||||
.post('api/Preaccept/getArticleMains', {
|
||||
|
||||
article_id: this.detailMes.article_id
|
||||
})
|
||||
.then((res) => {
|
||||
@@ -3171,35 +3240,43 @@ export default {
|
||||
min-height: 60px;
|
||||
}
|
||||
.left-panel {
|
||||
flex: 1; /* 左侧占据剩余空间 */
|
||||
margin-right: 40px;
|
||||
border-right: 1px dashed #eee; /* 加一条虚线分隔线 */
|
||||
padding-right: 20px;
|
||||
flex: 1; /* 左侧占据剩余空间 */
|
||||
margin-right: 40px;
|
||||
border-right: 1px dashed #eee; /* 加一条虚线分隔线 */
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
width: 48%; /* 右侧固定宽度 */
|
||||
width: 48%; /* 右侧固定宽度 */
|
||||
}
|
||||
.right-panel h5 {
|
||||
font-weight: normal;
|
||||
}
|
||||
.console-card {
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border: 1px solid #ebeef5;
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.load_pdf {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
transition: background 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.load_pdf:hover {
|
||||
background: #f5f7fa;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
.loadTinymceBox {
|
||||
height: 160px; line-height: 160px; text-align: center; border: 2px solid #eee;
|
||||
border-radius: 10px;
|
||||
color: #c0c4cc !important;
|
||||
}
|
||||
.loadTinymceBox *{
|
||||
color: #c0c4cc !important;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</p>
|
||||
<!-- <p style="color: #7f8790;margin: 10px 0 0 0;">Follow the progress of your submission.</p> -->
|
||||
<div class="tit_head">
|
||||
Status : <b style="margin: 0 50px 0 0">{{ statetostr(artMes.laststate) }}</b> Journal : <b>{{ artMes.journalname }}</b>
|
||||
Status : <b style="margin: 0 50px 0 0">{{ artMes.is_draft==1&&(artMes.laststate==3||artMes.laststate==-1) ? $t('artstate.stateDraft') : statetostr(artMes.laststate)}}</b><span v-if="artMes.journalname">Journal : <b>{{ artMes.journalname }}</b></span>
|
||||
</div>
|
||||
<div class="tit_head" v-if="artMes.majors && artMes.majors.length > 0">
|
||||
<b style="margin: 0 50px 0 0; font-size: 20px">Research areas</b>
|
||||
|
||||
@@ -441,7 +441,7 @@ export default {
|
||||
},
|
||||
async created() {
|
||||
this.isCollapse = localStorage.getItem('isCollapse') == 'true' ? true : false;
|
||||
console.log('localStorage.getItem', typeof localStorage.getItem('isCollapse'));
|
||||
|
||||
this.isShowEditComment();
|
||||
this.isFresh = false;
|
||||
this.$nextTick(async () => {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div class="tinymce-container editor-container">
|
||||
|
||||
|
||||
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
@@ -125,21 +123,23 @@ export default {
|
||||
formLabelWidth: '120px',
|
||||
hasChange: false,
|
||||
hasInit: false,
|
||||
|
||||
editorInstance: null,
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date()
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
// console.log('val at line 208:', val);
|
||||
value: {
|
||||
|
||||
handler(val) {
|
||||
|
||||
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() => {
|
||||
|
||||
|
||||
window.tinymce.get(this.tinymceId).setContent(val);
|
||||
// window.renderMathJax(); // 主动触发 MathJax 渲染
|
||||
});
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -163,13 +163,31 @@ export default {
|
||||
this.destroyTinymce();
|
||||
},
|
||||
methods: {
|
||||
handleSetContent(val) {
|
||||
if (!this.editorInstance) return;
|
||||
|
||||
let finalContent = val || '';
|
||||
// 你的业务逻辑:自动包裹 <p> 标签
|
||||
if (!finalContent.includes('wordTableHtml') && !finalContent.startsWith('<p>')) {
|
||||
finalContent = '<p>' + finalContent + '</p>';
|
||||
}
|
||||
|
||||
this.editorInstance.setContent(finalContent);
|
||||
|
||||
// 渲染数学公式
|
||||
this.$nextTick(() => {
|
||||
if (window.renderMathJax) {
|
||||
window.renderMathJax(this.tinymceId);
|
||||
}
|
||||
});
|
||||
},
|
||||
onClear() {
|
||||
if (this.uploadNotificationInstance) {
|
||||
this.uploadNotificationInstance.close(); this.uploadNotificationInstance = null;
|
||||
this.uploadedImageCount = 0;
|
||||
this.totalUploadImages = 0;}
|
||||
|
||||
this.uploadNotificationInstance.close();
|
||||
this.uploadNotificationInstance = null;
|
||||
this.uploadedImageCount = 0;
|
||||
this.totalUploadImages = 0;
|
||||
}
|
||||
},
|
||||
updateUploadProgressNotification(imgIndex, status = 'processing', message = '') {
|
||||
// 快捷调用 $t
|
||||
@@ -184,7 +202,7 @@ export default {
|
||||
<p id="total-status-text" style="margin: 0 0 12px 0; font-size: 14px; color: #606266; font-weight: 500;">
|
||||
${t('preparing', { total: this.totalUploadImages })}
|
||||
</p>
|
||||
|
||||
|
||||
<div class="el-progress el-progress--line" style="margin-bottom: 15px;">
|
||||
<div class="el-progress-bar">
|
||||
<div class="el-progress-bar__outer" style="height: 10px; background: #ebeef5; border-radius: 5px;">
|
||||
@@ -351,46 +369,46 @@ export default {
|
||||
}
|
||||
},
|
||||
// 按照你要求的 XMLHttpRequest 格式编写
|
||||
// 直接接收已经转好的 blob
|
||||
uploadSingleImage(blob, index) {
|
||||
const _this = this;
|
||||
const xhr = new XMLHttpRequest();
|
||||
const formData = new FormData();
|
||||
|
||||
// 直接把传进来的 blob 丢进表单
|
||||
formData.append('file_name', blob, `word_img_${index}.png`);
|
||||
formData.append('article_id', this.articleId);
|
||||
// 直接接收已经转好的 blob
|
||||
uploadSingleImage(blob, index) {
|
||||
const _this = this;
|
||||
const xhr = new XMLHttpRequest();
|
||||
const formData = new FormData();
|
||||
|
||||
xhr.withCredentials = false;
|
||||
xhr.open('POST', _this.baseUrl + 'api/Articlemain/uploadTableImage');
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.status !== 200) {
|
||||
_this.removePlaceholder(index); // 失败清理
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const json = JSON.parse(xhr.responseText);
|
||||
if (json.status == 1) {
|
||||
const finalUrl = _this.mediaUrl + 'articleTableImage/' + json.data;
|
||||
const doc = tinymce.activeEditor.getDoc();
|
||||
const placeholder = doc.querySelector(`img[data-idx="${index}"]`);
|
||||
if (placeholder) {
|
||||
placeholder.src = finalUrl;
|
||||
placeholder.removeAttribute('data-idx');
|
||||
// 直接把传进来的 blob 丢进表单
|
||||
formData.append('file_name', blob, `word_img_${index}.png`);
|
||||
formData.append('article_id', this.articleId);
|
||||
|
||||
xhr.withCredentials = false;
|
||||
xhr.open('POST', _this.baseUrl + 'api/Articlemain/uploadTableImage');
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.status !== 200) {
|
||||
_this.removePlaceholder(index); // 失败清理
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_this.removePlaceholder(index);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析响应失败', e);
|
||||
_this.removePlaceholder(index);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => _this.removePlaceholder(index);
|
||||
xhr.send(formData);
|
||||
},
|
||||
try {
|
||||
const json = JSON.parse(xhr.responseText);
|
||||
if (json.status == 1) {
|
||||
const finalUrl = _this.mediaUrl + 'articleTableImage/' + json.data;
|
||||
const doc = tinymce.activeEditor.getDoc();
|
||||
const placeholder = doc.querySelector(`img[data-idx="${index}"]`);
|
||||
if (placeholder) {
|
||||
placeholder.src = finalUrl;
|
||||
placeholder.removeAttribute('data-idx');
|
||||
}
|
||||
} else {
|
||||
_this.removePlaceholder(index);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析响应失败', e);
|
||||
_this.removePlaceholder(index);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => _this.removePlaceholder(index);
|
||||
xhr.send(formData);
|
||||
},
|
||||
|
||||
removePlaceholder(idx) {
|
||||
const doc = tinymce.activeEditor.getDoc();
|
||||
@@ -412,35 +430,71 @@ uploadSingleImage(blob, index) {
|
||||
}
|
||||
return new Blob([u8arr], { type: mime });
|
||||
},
|
||||
formatHtml(val) {
|
||||
const rawValue = val || ''; // 处理 null
|
||||
const cleanEmptyTags = /<([a-zA-Z1-6]+)\b[^>]*><\/\1>/g;
|
||||
const replaceSpaces = /\s+(?=<)|(?<=>)\s+/g;
|
||||
const removeBr = /<br\s*\/?>/gi; // 移除所有 br 标签
|
||||
|
||||
if (rawValue.includes('wordTableHtml')) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(rawValue, 'text/html');
|
||||
const cells = doc.querySelectorAll('td, th');
|
||||
|
||||
cells.forEach((cell) => {
|
||||
cell.innerHTML = cell.innerHTML
|
||||
.replace(cleanEmptyTags, '')
|
||||
.replace(removeBr, '') // 针对你“不想要br”的需求
|
||||
.replace(replaceSpaces, ' ');
|
||||
});
|
||||
return doc.body.innerHTML;
|
||||
} else {
|
||||
return rawValue
|
||||
.replace(cleanEmptyTags, '')
|
||||
.replace(removeBr, '')
|
||||
.replace(replaceSpaces, ' ');
|
||||
}
|
||||
},
|
||||
getSafeContent(val) {
|
||||
const rawValue = val || '';
|
||||
const cleanEmptyTags = /<([a-zA-Z1-6]+)\b[^>]*><\/\1>/g;
|
||||
const replaceSpaces = /\s+(?=<)|(?<=>)\s+/g;
|
||||
|
||||
|
||||
const escapeIllegalLT = (str) => {
|
||||
return str.replace(/<(?!(\/?(p|div|span|table|tr|td|th|b|i|strong|em|ul|ol|li|br|img)))/gi, '<');
|
||||
};
|
||||
|
||||
let processedHtml = '';
|
||||
|
||||
if (rawValue.includes('wordTableHtml')) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(rawValue, 'text/html');
|
||||
const cells = doc.querySelectorAll('td, th');
|
||||
|
||||
cells.forEach((cell) => {
|
||||
// 1. 先把单元格内的非法 < 转义
|
||||
let cellText = cell.innerHTML;
|
||||
// let cellText = escapeIllegalLT(cell.innerHTML);
|
||||
// 2. 再清理空标签和多余空格
|
||||
cell.innerHTML = cellText
|
||||
.replace(cleanEmptyTags, '')
|
||||
.replace(replaceSpaces, ' ');
|
||||
});
|
||||
processedHtml = doc.body.innerHTML;
|
||||
} else {
|
||||
// 非表格逻辑也同样处理转义
|
||||
// processedHtml = escapeIllegalLT(rawValue)
|
||||
processedHtml = rawValue
|
||||
.replace(cleanEmptyTags, '')
|
||||
.replace(replaceSpaces, ' ');
|
||||
}
|
||||
|
||||
return processedHtml;
|
||||
},
|
||||
|
||||
initTinymce() {
|
||||
if (this.value.includes('wordTableHtml')) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(this.value, 'text/html');
|
||||
|
||||
// 1. 只针对单元格 (td, th) 进行处理
|
||||
const cells = doc.querySelectorAll('td, th');
|
||||
cells.forEach(cell => {
|
||||
let html = cell.innerHTML;
|
||||
// 执行你原来的清理逻辑,但仅限单元格内部
|
||||
html = html.replace(/<([a-zA-Z1-6]+)\b[^>]*><\/\1>/g, '') // 清理空标签
|
||||
.replace(/\s+(?=<)|(?<=>)\s+/g, ' '); // 补全空格
|
||||
cell.innerHTML = html;
|
||||
});
|
||||
|
||||
// 2. 将处理后的完整 HTML 重新赋回,此时 table 外部的换行符保持原样(纯文本)
|
||||
this.content = doc.body.innerHTML;
|
||||
} else {
|
||||
// 非表格模式,维持你原有的全局逻辑
|
||||
this.content = this.value
|
||||
.replace(/<([a-zA-Z1-6]+)\b[^>]*><\/\1>/g, '')
|
||||
.replace(/\s+(?=<)|(?<=>)\s+/g, ' ');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let globalImgCounter = 0; // 放在 init 闭包内,确保计数器持续增长
|
||||
let currentPasteBase64Images = [];
|
||||
var _this = this;
|
||||
window.tinymce.init({
|
||||
..._this.tinymceOtherInit,
|
||||
@@ -470,37 +524,37 @@ uploadSingleImage(blob, index) {
|
||||
blue{
|
||||
display: inline;
|
||||
}
|
||||
myfigure,
|
||||
mytable {
|
||||
pointer-events: auto !important; /* 强制允许鼠标点击 */
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: rgb(0, 130, 170) !important;
|
||||
text-shadow: 0 0 3px #09c2fb, 0 0 4px rgba(0, 130, 170, 0.3);
|
||||
}
|
||||
myfigure,
|
||||
mytable {
|
||||
pointer-events: auto !important; /* 强制允许鼠标点击 */
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: rgb(0, 130, 170) !important;
|
||||
text-shadow: 0 0 3px #09c2fb, 0 0 4px rgba(0, 130, 170, 0.3);
|
||||
}
|
||||
|
||||
myfigure *,
|
||||
mytable * {
|
||||
color: inherit !important;
|
||||
text-shadow: inherit !important;
|
||||
background: transparent !important; /* 防止内部标签背景干扰 */
|
||||
}
|
||||
myh3 ,myh3 *{
|
||||
font-weight: bold !important;
|
||||
}
|
||||
myfigure *,
|
||||
mytable * {
|
||||
color: inherit !important;
|
||||
text-shadow: inherit !important;
|
||||
background: transparent !important; /* 防止内部标签背景干扰 */
|
||||
}
|
||||
myh3 ,myh3 *{
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
@keyframes blueGlow {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`,
|
||||
@keyframes blueGlow {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`,
|
||||
formats: {
|
||||
bold: { inline: 'b' },
|
||||
italic: { inline: 'i' }
|
||||
@@ -575,42 +629,39 @@ font-weight: bold !important;
|
||||
_this.$commonJS.initEditorButton(_this, ed);
|
||||
var currentWmathElement = null;
|
||||
ed.on('click', function (e) {
|
||||
const wmathElement = e.target.closest('wmath');
|
||||
if (wmathElement) {
|
||||
currentWmathElement = wmathElement; // 保存当前点击的元素
|
||||
|
||||
// 1. 提取内容:获取 LaTeX
|
||||
const latexContentRaw = wmathElement.getAttribute('data-latex') || '';
|
||||
const latexContent = latexContentRaw.replace(/\$/g, '').trim();
|
||||
const encoded = encodeURIComponent(latexContent);
|
||||
const wmathElement = e.target.closest('wmath');
|
||||
if (wmathElement) {
|
||||
currentWmathElement = wmathElement; // 保存当前点击的元素
|
||||
|
||||
// 2. 提取状态:获取之前的 wrap 模式 👈 重要新增
|
||||
const wrapMode = wmathElement.getAttribute('data-wrap') || 'block';
|
||||
// 1. 提取内容:获取 LaTeX
|
||||
const latexContentRaw = wmathElement.getAttribute('data-latex') || '';
|
||||
const latexContent = latexContentRaw.replace(/\$/g, '').trim();
|
||||
const encoded = encodeURIComponent(latexContent);
|
||||
|
||||
// 3. 处理唯一 ID
|
||||
let wmathId = wmathElement.getAttribute('data-id');
|
||||
if (!wmathId) {
|
||||
wmathId = 'wmath-' + Math.random().toString(36).substr(2, 9);
|
||||
wmathElement.setAttribute('data-id', wmathId);
|
||||
}
|
||||
// 2. 提取状态:获取之前的 wrap 模式 👈 重要新增
|
||||
const wrapMode = wmathElement.getAttribute('data-wrap') || 'block';
|
||||
|
||||
const editorId = ed.id;
|
||||
// 3. 处理唯一 ID
|
||||
let wmathId = wmathElement.getAttribute('data-id');
|
||||
if (!wmathId) {
|
||||
wmathId = 'wmath-' + Math.random().toString(36).substr(2, 9);
|
||||
wmathElement.setAttribute('data-id', wmathId);
|
||||
}
|
||||
|
||||
// 4. 打开窗口:在 URL 参数中增加 wrap 模式 👈 这样弹窗就知道该默认选哪个了
|
||||
window.open(
|
||||
`/LateX?id=${encoded}&wmathId=${wmathId}&editorId=${editorId}&wrap=${wrapMode}`,
|
||||
'_blank',
|
||||
'width=1000,height=800,scrollbars=no,resizable=no'
|
||||
);
|
||||
}
|
||||
});
|
||||
const editorId = ed.id;
|
||||
|
||||
ed.on('paste', async (event) => {
|
||||
|
||||
// 4. 打开窗口:在 URL 参数中增加 wrap 模式 👈 这样弹窗就知道该默认选哪个了
|
||||
window.open(
|
||||
`/LateX?id=${encoded}&wmathId=${wmathId}&editorId=${editorId}&wrap=${wrapMode}`,
|
||||
'_blank',
|
||||
'width=1000,height=800,scrollbars=no,resizable=no'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ed.on('paste', async (event) => {
|
||||
const rtf = event.clipboardData.getData('text/rtf');
|
||||
if (rtf && rtf.includes('\\pict')) {
|
||||
|
||||
const extracted = extractHexImagesFromRTF(rtf);
|
||||
_this.totalUploadImages = extracted.length; // 设置总数
|
||||
_this.uploadedImageCount = 0; // 重置已上传数
|
||||
@@ -630,22 +681,21 @@ font-weight: bold !important;
|
||||
return; // 跳过此图片
|
||||
}
|
||||
try {
|
||||
|
||||
const imageBlob = _this.hexToBlob(img.hex, img.mimeType);
|
||||
|
||||
_this.updateUploadProgressNotification(i, 'uploading');
|
||||
const imageBlob = _this.hexToBlob(img.hex, img.mimeType);
|
||||
|
||||
// 2. 【核心优化】直接上传这个 Blob 文件
|
||||
// uploadSingleImage 内部需要改用 FormData 发送
|
||||
await _this.uploadSingleImage(imageBlob, i);
|
||||
|
||||
_this.updateUploadProgressNotification(i, 'success');
|
||||
} catch (err) {
|
||||
_this.updateUploadProgressNotification(i, 'uploading');
|
||||
|
||||
// 2. 【核心优化】直接上传这个 Blob 文件
|
||||
// uploadSingleImage 内部需要改用 FormData 发送
|
||||
await _this.uploadSingleImage(imageBlob, i);
|
||||
|
||||
_this.updateUploadProgressNotification(i, 'success');
|
||||
} catch (err) {
|
||||
console.error('Upload failed:', err);
|
||||
_this.updateUploadProgressNotification(i, 'fail', err.message || 'Network error'); // 上传失败
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
// Promise.all 完成后, updateUploadProgressNotification 会自动计算 totalCount === uploadedCount 并关闭
|
||||
}
|
||||
@@ -676,36 +726,40 @@ font-weight: bold !important;
|
||||
}
|
||||
});
|
||||
ed.on('init', function () {
|
||||
_this.$commonJS.inTinymceButtonClass();
|
||||
const editorBody = ed.getBody();
|
||||
_this.editorInstance = ed;
|
||||
_this.hasInit = true;
|
||||
_this.$commonJS.inTinymceButtonClass();
|
||||
if (_this.isAutomaticUpdate) {
|
||||
_this.$emit('updateChange', _this.value);
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
const currentContent = ed.getContent({ format: 'raw' });
|
||||
|
||||
|
||||
if (_this.isAutomaticUpdate) {
|
||||
_this.$emit('updateChange', currentContent);
|
||||
// _this.$emit('updateChange', _this.$commonJS.decodeHtml(currentContent));
|
||||
//暂时注释掉数字公式
|
||||
// _this.$commonJS.replaceWMathContent(currentContent, (res) => {
|
||||
// console.log('res at line 451:', res);
|
||||
// _this.$emit('updateChange', res);
|
||||
// });
|
||||
}
|
||||
});
|
||||
|
||||
// 监听子节点和内容的变化
|
||||
observer.observe(editorBody, { childList: true, subtree: true, characterData: true });
|
||||
});
|
||||
// // 定义自定义按钮
|
||||
// ed.ui.registry.addButton('clearButton', {
|
||||
// text: 'Empty',
|
||||
}
|
||||
_this.content = _this.getSafeContent(_this.value);
|
||||
|
||||
// onAction: () => {
|
||||
// // 插入自定义表格到编辑器中
|
||||
// ed.setContent('');
|
||||
// }
|
||||
// });
|
||||
_this.handleSetContent(_this.content || '');
|
||||
|
||||
// 3. 监听内容变化
|
||||
ed.on('NodeChange Change KeyUp SetContent', () => {
|
||||
_this.hasChange = true;
|
||||
_this.$emit('input', ed.getContent({ format: 'raw' }));
|
||||
});
|
||||
|
||||
// 4. 监听 DOM 变化
|
||||
const observer = new MutationObserver(() => {
|
||||
const currentContent = ed.getContent({ format: 'raw' });
|
||||
if (_this.isAutomaticUpdate) {
|
||||
_this.$emit('updateChange', currentContent);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(ed.getBody(), {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
characterData: true
|
||||
});
|
||||
});
|
||||
|
||||
// 定义自定义按钮
|
||||
ed.ui.registry.addButton('customButtonExportWord', {
|
||||
@@ -726,7 +780,7 @@ font-weight: bold !important;
|
||||
text: _this.$t('commonTable.exportImg'),
|
||||
onAction: () => {
|
||||
// 插入自定义表格到编辑器中
|
||||
_this.export('image', ed.getContent({ format: 'raw' }));
|
||||
_this.export('image', ed.getContent({ format: 'raw' }));
|
||||
}
|
||||
});
|
||||
ed.ui.registry.addContextToolbar('spacer', {
|
||||
@@ -740,10 +794,9 @@ font-weight: bold !important;
|
||||
ed.dom.select('wmath', editorBody).forEach(function (wmathElement) {
|
||||
ed.dom.setAttrib(wmathElement, 'contenteditable', 'false');
|
||||
// ed.dom.addClass(wmathElement, 'non-editable-wmath');
|
||||
});
|
||||
});
|
||||
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
|
||||
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
|
||||
|
||||
});
|
||||
ed.on('GetContent', function (e) {
|
||||
e.content = e.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>');
|
||||
@@ -763,7 +816,6 @@ font-weight: bold !important;
|
||||
tempDiv.innerHTML = content;
|
||||
|
||||
if (tempDiv.querySelector('table')) {
|
||||
|
||||
if (_this.type == 'table') {
|
||||
// 3. 在这里直接消费外部变量 currentPasteBase64Images
|
||||
// content = content.replace(new RegExp(`src="${silentPlaceholder}"`, 'gi'), () => {
|
||||
@@ -804,40 +856,29 @@ font-weight: bold !important;
|
||||
args.content = container.innerHTML; // 更新处理后的内容
|
||||
});
|
||||
} else {
|
||||
// _this.$confirm('检测到粘贴内容包含表格,是否需要以表格形式添加?', '提示', {
|
||||
// confirmButtonText: '添加表格',
|
||||
// cancelButtonText: '纯文本添加',
|
||||
// type: 'info'
|
||||
// }).then(() => {
|
||||
// _this.$emit('openAddTable', content);
|
||||
// return false
|
||||
// }).catch(() => {
|
||||
|
||||
// });
|
||||
// _this.$confirm('检测到粘贴内容包含表格,是否需要以表格形式添加?', '提示', {
|
||||
// confirmButtonText: '添加表格',
|
||||
// cancelButtonText: '纯文本添加',
|
||||
// type: 'info'
|
||||
// }).then(() => {
|
||||
// _this.$emit('openAddTable', content);
|
||||
// return false
|
||||
// }).catch(() => {
|
||||
// });
|
||||
}
|
||||
} else {
|
||||
console.log('Original content:', content); // 输出原始粘贴内容
|
||||
const mathRegex = /\$\$([\s\S]+?)\$\$|\$([\s\S]+?)\$/g;
|
||||
content = content.replace(mathRegex, function (match, blockFormula, inlineFormula) {
|
||||
const formula = blockFormula || inlineFormula;
|
||||
const mode = blockFormula ? 'block' : 'inline';
|
||||
console.log(`Matched ${mode} formula:`, formula);
|
||||
|
||||
// 1. 修改正则:同时匹配 $$...$$ (块级) 和 $...$ (行内)
|
||||
// 注意:先匹配双美元符,再匹配单美元符,防止冲突
|
||||
const mathRegex = /\$\$([\s\S]+?)\$\$|\$([\s\S]+?)\$/g;
|
||||
return `<wmath data-wrap="${mode}" data-latex="${formula.trim()}">${formula.trim()}</wmath>`;
|
||||
});
|
||||
|
||||
content = content.replace(mathRegex, function (match, blockFormula, inlineFormula) {
|
||||
// 判断是块级还是行内
|
||||
const formula = blockFormula || inlineFormula;
|
||||
const mode = blockFormula ? 'block' : 'inline';
|
||||
|
||||
console.log(`Matched ${mode} formula:`, formula);
|
||||
|
||||
// 2. 统一改造:标签内只放纯 formula,不带 $ 符号
|
||||
// 属性中保存 data-latex 和 data-wrap
|
||||
return `<wmath data-wrap="${mode}" data-latex="${formula.trim()}">${formula.trim()}</wmath>`;
|
||||
});
|
||||
|
||||
console.log('Processed content:', content); // 输出处理后的内容
|
||||
|
||||
}
|
||||
// 更新 args.content 为处理后的内容
|
||||
// 阻止默认的粘贴行为,确保自定义处理优先执行
|
||||
|
||||
if (args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
@@ -853,111 +894,79 @@ console.log('Processed content:', content); // 输出处理后的内容
|
||||
}, 10);
|
||||
},
|
||||
clear_custom_action: (editor, vm) => {
|
||||
|
||||
vm.onClear();
|
||||
},
|
||||
init_instance_callback: (editor) => {
|
||||
|
||||
|
||||
if (_this.content) {
|
||||
let finalContent = _this.content;
|
||||
|
||||
if (finalContent.includes('wordTableHtml')) {
|
||||
|
||||
editor.setContent(finalContent);
|
||||
} else {
|
||||
|
||||
editor.setContent('<p>' + finalContent + '</p>');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (window.renderMathJax) {
|
||||
window.renderMathJax(_this.tinymceId);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
_this.hasInit = true;
|
||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||
this.hasChange = true;
|
||||
this.$emit('input', editor.getContent({ format: 'raw' }));
|
||||
|
||||
});
|
||||
}
|
||||
// init_instance_callback: (editor) => {
|
||||
|
||||
// }
|
||||
});
|
||||
if (!window._wmath_listener_registered) {
|
||||
// 💾 新增公式插入点记录
|
||||
let latexEditorBookmark = null;
|
||||
let activeEditorId = null;
|
||||
|
||||
// 👂 message 监听器:处理编辑 + 新增两种情况
|
||||
window.addEventListener('message', function (event) {
|
||||
const data = event.data;
|
||||
|
||||
if (data && (data.type === 'update-wmath' || data.type === 'insert-wmath')) {
|
||||
const { editorId, wmathId, latex } = data;
|
||||
const newLatex = latex ? latex.trim() : '';
|
||||
if (!editorId) return;
|
||||
const data = event.data;
|
||||
|
||||
const targetEditor = tinymce.get(editorId);
|
||||
if (!targetEditor) return;
|
||||
if (data && (data.type === 'update-wmath' || data.type === 'insert-wmath')) {
|
||||
const { editorId, wmathId, latex } = data;
|
||||
const newLatex = latex ? latex.trim() : '';
|
||||
if (!editorId) return;
|
||||
|
||||
// 尝试寻找现有标签
|
||||
const targetWmath = wmathId ? targetEditor.dom.select(`wmath[data-id="${wmathId}"]`, targetEditor.getBody())[0] : null;
|
||||
const targetEditor = tinymce.get(editorId);
|
||||
if (!targetEditor) return;
|
||||
|
||||
if (targetWmath) {
|
||||
// --- 原有的更新/删除逻辑 ---
|
||||
if (!newLatex) {
|
||||
targetEditor.dom.remove(targetWmath);
|
||||
} else {
|
||||
targetWmath.setAttribute('data-latex', newLatex);
|
||||
if (data.wrapMode === 'inline') {
|
||||
targetWmath.setAttribute('data-wrap', 'inline');
|
||||
} else {
|
||||
targetWmath.setAttribute('data-wrap', 'block');
|
||||
}
|
||||
targetWmath.innerHTML = newLatex;
|
||||
}
|
||||
} else if (newLatex) {
|
||||
// --- ✨ 新增逻辑:如果找不到现有标签且有 latex 内容 ---
|
||||
// 生成一个新的唯一 ID (如果你后端或插件没给的话)
|
||||
const newId = wmathId || 'wmath_' + Date.now();
|
||||
|
||||
// 构建新的 wmath 标签字符串
|
||||
// 这里你可以根据之前选的 wrapMode (块级/行内) 来决定样式
|
||||
const htmlToInsert = `<wmath data-id="${newId}" data-latex="${newLatex}" data-wrap="${data.wrapMode === 'inline' ? 'inline' : 'block'}">${newLatex}</wmath>`;
|
||||
|
||||
// 在当前光标位置插入内容
|
||||
targetEditor.insertContent(htmlToInsert);
|
||||
}
|
||||
const targetWmath = wmathId
|
||||
? targetEditor.dom.select(`wmath[data-id="${wmathId}"]`, targetEditor.getBody())[0]
|
||||
: null;
|
||||
|
||||
// 统一渲染
|
||||
setTimeout(() => {
|
||||
if (typeof renderMathJax === 'function') {
|
||||
renderMathJax(editorId);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
if (targetWmath) {
|
||||
if (!newLatex) {
|
||||
targetEditor.dom.remove(targetWmath);
|
||||
} else {
|
||||
targetWmath.setAttribute('data-latex', newLatex);
|
||||
if (data.wrapMode === 'inline') {
|
||||
targetWmath.setAttribute('data-wrap', 'inline');
|
||||
} else {
|
||||
targetWmath.setAttribute('data-wrap', 'block');
|
||||
}
|
||||
targetWmath.innerHTML = newLatex;
|
||||
}
|
||||
} else if (newLatex) {
|
||||
const newId = wmathId || 'wmath_' + Date.now();
|
||||
|
||||
const htmlToInsert = `<wmath data-id="${newId}" data-latex="${newLatex}" data-wrap="${
|
||||
data.wrapMode === 'inline' ? 'inline' : 'block'
|
||||
}">${newLatex}</wmath>`;
|
||||
|
||||
targetEditor.insertContent(htmlToInsert);
|
||||
}
|
||||
|
||||
// 统一渲染
|
||||
setTimeout(() => {
|
||||
if (typeof renderMathJax === 'function') {
|
||||
renderMathJax(editorId);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
|
||||
// 🚩 标记为已注册,防止重复
|
||||
window._wmath_listener_registered = true;
|
||||
|
||||
// 导出保存位置函数(你可以在按钮点击时调用它)
|
||||
window._recordLatexInsertContext = function (editorInstance) {
|
||||
latexEditorBookmark = editorInstance.selection.getBookmark(2);
|
||||
activeEditorId = editorInstance.id;
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
hexToBlob(hex, mimeType) {
|
||||
const len = hex.length / 2;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
||||
}
|
||||
return new Blob([bytes], { type: mimeType });
|
||||
},
|
||||
const len = hex.length / 2;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
||||
}
|
||||
return new Blob([bytes], { type: mimeType });
|
||||
},
|
||||
updateTableStyles(container) {
|
||||
var html = this.$commonJS.updateTableStyles(container, this.typesettingType);
|
||||
var editor = window.tinymce.activeEditor; // 将外部 DOM 内容更新到编辑器
|
||||
@@ -967,11 +976,11 @@ console.log('Processed content:', content); // 输出处理后的内容
|
||||
editor.focus(); // 聚焦到编辑器// 触发编辑器内容变化后,如果需要,可能还要设置编辑器的样式
|
||||
},
|
||||
//销毁富文本
|
||||
destroyTinymce() {this.onClear();
|
||||
destroyTinymce() {
|
||||
this.onClear();
|
||||
if (window.tinymce.get(this.tinymceId)) {
|
||||
window.tinymce.get(this.tinymceId).destroy();
|
||||
}
|
||||
|
||||
},
|
||||
//设置内容
|
||||
setContent(value) {
|
||||
@@ -980,13 +989,12 @@ console.log('Processed content:', content); // 输出处理后的内容
|
||||
//获取内容
|
||||
async getContent(type) {
|
||||
var content = window.tinymce.get(this.tinymceId).getContent({ format: 'raw' });
|
||||
|
||||
|
||||
|
||||
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(/ /g, ' '); // 将所有 替换为空格
|
||||
|
||||
|
||||
this.$emit('getContent', type, content);
|
||||
},
|
||||
|
||||
|
||||
@@ -365,6 +365,7 @@
|
||||
:id="'editor' + item.am_id"
|
||||
v-html="highlightText({ am_id: item.am_id, text: item.content }, item.checks ? item.checks : [], item.type)"
|
||||
></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3021,7 +3022,10 @@ export default {
|
||||
text = this.highlightText3(item.text, [], type, item.am_id);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
// const finalHtml = text.replace(/<(?!(\/?(span|p|div|table|tr|td|th|b|i|strong|em|ul|ol|li|br|img|myh3|myfigure|mytable|blue|wmath)))/gi, '<');
|
||||
|
||||
return text;
|
||||
|
||||
},
|
||||
// 改造版:DOM 安全高亮
|
||||
// 仅保留 <wmath>…</wmath> 内部,其他用正则匹配高亮
|
||||
@@ -3303,6 +3307,8 @@ export default {
|
||||
html += `<img contenteditable="false" src="${this.imagePath || ''}" alt="" style="width:20px;height:20px;opacity:.6;">`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return html;
|
||||
},
|
||||
getProofreadingList(arr) {
|
||||
|
||||
@@ -930,7 +930,7 @@ if(newData.ami_id) {
|
||||
},
|
||||
async created() {
|
||||
this.isCollapse = localStorage.getItem('isCollapse') == 'true' ? true : false;
|
||||
console.log('localStorage.getItem', typeof localStorage.getItem('isCollapse'));
|
||||
|
||||
this.isShowEditComment();
|
||||
this.isFresh = false;
|
||||
this.$nextTick(async () => {
|
||||
|
||||
@@ -361,7 +361,7 @@ export default {
|
||||
this.add_apply = 0;
|
||||
|
||||
break;
|
||||
case 7||16:
|
||||
case 7:
|
||||
// 7文章状态不在审稿中
|
||||
this.add_apply = 1;
|
||||
break;
|
||||
@@ -369,7 +369,8 @@ export default {
|
||||
//拒绝审稿
|
||||
this.add_apply = -1;
|
||||
break;
|
||||
case 13:
|
||||
case 13:
|
||||
case 16:
|
||||
//13 邀请审稿超过5天未同意邀请16同意审稿后14天未进行审稿
|
||||
this.add_apply = 2;
|
||||
break;
|
||||
|
||||
@@ -71,8 +71,8 @@ module.exports = {
|
||||
proxy: {
|
||||
'/api': {
|
||||
// target: 'http://zmzm.tougao.dev.com/',//晓玲本地
|
||||
// target: 'https://submission.tmrjournals.com/',//正式
|
||||
target: 'http://tougaotest.tmrjournals.com/public/index.php/',//测试环境
|
||||
target: 'https://submission.tmrjournals.com/',//正式
|
||||
// target: 'http://tougaotest.tmrjournals.com/public/index.php/',//测试环境
|
||||
// target: 'http://mytest.tmrjournals.com/public/index.php/',//新测试环境
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
|
||||
Reference in New Issue
Block a user