This commit is contained in:
2026-01-13 09:32:33 +08:00
parent 0f3ee631e3
commit 1755fd2202
20 changed files with 3656 additions and 3385 deletions

View File

@@ -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: '/', //正式
}); });

View File

@@ -831,26 +831,27 @@ export default {
// } // }
// }, // },
transformHtmlString(inputHtml, type) { transformHtmlString(inputHtml, type, options = {}) {
const { keepBr = false } = options;
if (!keepBr) {
inputHtml = inputHtml.replace(/<br\s*\/?>/g, '');
}
// inputHtml = inputHtml.replace(/(<[^>]+) style="[^"]*"/g, '$1'); // 移除style属性 // inputHtml = inputHtml.replace(/(<[^>]+) style="[^"]*"/g, '$1'); // 移除style属性
// inputHtml = inputHtml.replace(/(<[^>]+) class="[^"]*"/g, '$1'); // 移除class属性 // inputHtml = inputHtml.replace(/(<[^>]+) class="[^"]*"/g, '$1'); // 移除class属性
// inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)[^>]*>/g, '<$1>'); // 删除标签上的所有属性 // inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)[^>]*>/g, '<$1>'); // 删除标签上的所有属性
inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)([^>]*)>/g, function (match, tag, attributes) { inputHtml = inputHtml.replace(/<([a-zA-Z0-9]+)([^>]*)>/g, function (match, tag, attributes) {
// 使用正则表达式删除属性(保留 data-latex // 使用正则表达式删除属性(保留 data-latex
let updatedAttributes = attributes.replace(/\s([a-zA-Z0-9-]+)(="[^"]*")?/g, function (attrMatch, attrName) { let updatedAttributes = attributes.replace(/\s([a-zA-Z0-9-]+)(="[^"]*")?/g, function (attrMatch, attrName) {
// 只保留 data-latex 属性,其他属性删除
if (attrName === "data-latex") { if (attrName === "data-latex") {
return attrMatch; return attrMatch;
} }
if (type == 'table' && tag == 'img' && (attrName === "src" || attrName === "width" || attrName === "height")) { if (type == 'table' && tag == 'img' && (attrName === "src" || attrName === "width" || attrName === "height")) {
return attrMatch; return attrMatch;
} }
return ''; // 删除其他属性 return '';
}); });
// 返回标签,保留 data-latex 属性
return `<${tag}${updatedAttributes}>`; return `<${tag}${updatedAttributes}>`;
}); });
// 2. 删除所有不需要的标签 (除 `strong`, `em`, `sub`, `sup`, `b`, `i` 外的所有标签) // 2. 删除所有不需要的标签 (除 `strong`, `em`, `sub`, `sup`, `b`, `i` 外的所有标签)
@@ -861,14 +862,11 @@ export default {
} }
// 3. 删除所有 `<br>` 标签 // 去掉样式
inputHtml = inputHtml.replace(/<br\s*\/?>/g, ''); // 删除 <br> 标签
// 3. 如果有 `<strong>` 和 `<em>` 标签,去掉内部样式并保留内容
inputHtml = inputHtml.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签 inputHtml = inputHtml.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
inputHtml = inputHtml.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>'); // 将 `strong` 替换成 `b` inputHtml = inputHtml.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>'); // 将 `strong` 替换成 `b`
inputHtml = inputHtml.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>'); // 将 `em` 替换成 `i` inputHtml = inputHtml.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>'); // 将 `em` 替换成 `i`
// 4. 合并相同标签
// 4. 合并相同标签(如多个连续的 <b> 标签)
inputHtml = inputHtml.replace(/<b>(.*?)<\/b>\s*<b>/g, '<b>$1'); // 合并连续的 <b> 标签 inputHtml = inputHtml.replace(/<b>(.*?)<\/b>\s*<b>/g, '<b>$1'); // 合并连续的 <b> 标签
inputHtml = inputHtml.replace(/<i>(.*?)<\/i>\s*<i>/g, '<i>$1'); // 合并连续的 <i> 标签 inputHtml = inputHtml.replace(/<i>(.*?)<\/i>\s*<i>/g, '<i>$1'); // 合并连续的 <i> 标签

View File

@@ -2,16 +2,16 @@
//记得切换 //记得切换
//正式 //正式
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'
// const mediaUrl = 'http://tougaotest.tmrjournals.com/public/'; const mediaUrl = 'http://tougaotest.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';
//本地(正式环境 ) //本地(正式环境 )

View File

@@ -225,7 +225,9 @@
<font style="color: #f56c6c; margin-right: 5px">*</font> <font style="color: #f56c6c; margin-right: 5px">*</font>
Table: Table:
</span> </span>
<common-table <common-table
:articleId="articleId"
@getContent="getContent" @getContent="getContent"
v-if="threeVisible" v-if="threeVisible"
ref="commonTable" ref="commonTable"

View File

@@ -720,7 +720,7 @@ export default {
article_id: this.$route.query.id article_id: this.$route.query.id
}) })
.then((res) => { .then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.article_pay_info = { this.article_pay_info = {
fee: res.data.article ? res.data.article.fee : 0, fee: res.data.article ? res.data.article.fee : 0,
@@ -1049,34 +1049,7 @@ export default {
return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page; return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page;
}, },
// 1----保存稿件信息
ZsSaveMes() {
if (this.detailMes.journal_stage_id == 0) {
this.$message.error('Please select an installment!');
return;
}
this.$refs.Mes_Form.validate((valid) => {
if (valid) {
this.$api
.post('api/Production/editProduction', this.detailMes)
.then((res) => {
if (res.code == 0) {
this.$message.success(`Successfully save the article!`);
this.getData();
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
} else {
this.$message.error('Please complete Essential Information first!');
this.jumpTab(0, this.tabsList[0]);
return false;
}
});
},
// 2----添加作者操作 // 2----添加作者操作
add_Authorclick(index, row) { add_Authorclick(index, row) {

View File

@@ -831,7 +831,7 @@ export default {
article_id: this.article_id article_id: this.article_id
}) })
.then((res) => { .then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.feeStatus=res.data.state this.feeStatus=res.data.state
this.isShowCommit=res.data.state==1?true:false this.isShowCommit=res.data.state==1?true:false
@@ -1146,34 +1146,7 @@ export default {
return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page; return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page;
}, },
// 1----保存稿件信息
ZsSaveMes() {
if (this.detailMes.journal_stage_id == 0) {
this.$message.error('Please select an installment!');
return;
}
this.$refs.Mes_Form.validate((valid) => {
if (valid) {
this.$api
.post('api/Production/editProduction', this.detailMes)
.then((res) => {
if (res.code == 0) {
this.$message.success(`Successfully save the article!`);
this.getData();
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message.error(err);
});
} else {
this.$message.error('Please complete Essential Information first!');
this.jumpTab(0, this.tabsList[0]);
return false;
}
});
},
// 2----添加作者操作 // 2----添加作者操作
add_Authorclick(index, row) { add_Authorclick(index, row) {

View File

@@ -2084,7 +2084,7 @@ export default {
restaurants[i].value = restaurants[i].email + ' | ' + restaurants[i].firstname + restaurants[i].lastname; restaurants[i].value = restaurants[i].email + ' | ' + restaurants[i].firstname + restaurants[i].lastname;
} }
var results = value ? restaurants.filter(this.createMata(value)) : restaurants; var results = value ? restaurants.filter(this.createMata(value)) : restaurants;
console.log('🚀 ~ .then ~ results177:', results);
// 调用 callback 返回建议列表的数据 // 调用 callback 返回建议列表的数据
cb(results); cb(results);
// this.form.authorList[num].load = false; // this.form.authorList[num].load = false;

View File

@@ -11,7 +11,12 @@
> >
Detailed for MS</el-button Detailed for MS</el-button
> >
<div class="tab_item" v-for="(item, index) in tabsList" @click="jumpTab(index, item)" :class="tabName == item.refName ? 'P_style' : ''"> <div
class="tab_item"
v-for="(item, index) in tabsList"
@click="jumpTab(index, item)"
:class="tabName == item.refName ? 'P_style' : ''"
>
<h5> <h5>
<span>{{ index + 1 }}</span> <span>{{ index + 1 }}</span>
{{ item.name }} {{ item.name }}
@@ -103,10 +108,66 @@
<el-input v-model="detailMes.tradition_tag" placeholder="eg Highlights"></el-input> <el-input v-model="detailMes.tradition_tag" placeholder="eg Highlights"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="Tradition Content :"> <el-form-item label="Tradition Content :">
<quill-editor ref="myTextEditor" v-model="detailMes.tradition" :options="editorOption"> </quill-editor> <tinymce
type="tradition"
:height="160"
ref="tinymceChild2"
:tinymceOtherInit="{
forced_root_block: '',
newline_behavior: 'linebreak',
}"
valid_elements=",br"
:wordStyle="`p{font-size: 13px;}`"
:isAutomaticUpdate="true"
@getContent="getContent"
@updateChange="(content) => updateChange('tradition',content)"
:value="tradition"
class="paste-area text-container"
:toolbar="[
'bold italic |customBlue removeBlue|myuppercase myuppercasea Line|subscript superscript|clearButton'
]"
style="
line-height: 12px;
overflow: auto;
font-size: 13px; /* 字体大小 */
margin-top: 0pt; /* 段前间距 */
margin-bottom: 0pt; /* 段后间距 */
"
></tinymce>
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.tradition" :options="editorOption"> </quill-editor> -->
</el-form-item> </el-form-item>
<el-form-item label="Medical history of objective :"> <el-form-item label="Medical history of objective :">
<quill-editor ref="myTextEditor" v-model="detailMes.mhoo" :options="editorOption"> </quill-editor>
<tinymce
type="mhooStr"
:height="160"
ref="tinymceChild3"
:tinymceOtherInit="{
forced_root_block: '',
newline_behavior: 'linebreak',
}"
valid_elements=",br"
:wordStyle="`p{font-size: 13px;}`"
:isAutomaticUpdate="true"
@getContent="getContent"
@updateChange="(content) => updateChange('mhooStr',content)"
:value="mhooStr"
class="paste-area text-container"
:toolbar="[
'bold italic |customBlue removeBlue|myuppercase myuppercasea Line|subscript superscript|clearButton'
]"
style="
line-height: 12px;
overflow: auto;
font-size: 13px; /* 字体大小 */
margin-top: 0pt; /* 段前间距 */
margin-bottom: 0pt; /* 段后间距 */
"
></tinymce>
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.mhoo" :options="editorOption"> </quill-editor> -->
</el-form-item> </el-form-item>
<el-form-item label="keywords :" prop="keywords"> <el-form-item label="keywords :" prop="keywords">
<el-input v-model="detailMes.keywords" placeholder="eg : keyword1,keyword2,keyword3"> </el-input> <el-input v-model="detailMes.keywords" placeholder="eg : keyword1,keyword2,keyword3"> </el-input>
@@ -118,6 +179,7 @@
<el-form-item label="Acknowledgment :" prop="acknowledgment"> <el-form-item label="Acknowledgment :" prop="acknowledgment">
<el-input v-model="detailMes.acknowledgment"></el-input> <el-input v-model="detailMes.acknowledgment"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="Abbreviation :"> <el-form-item label="Abbreviation :">
<el-input v-model="detailMes.abbreviation"></el-input> <el-input v-model="detailMes.abbreviation"></el-input>
</el-form-item> </el-form-item>
@@ -133,7 +195,7 @@
:wordStyle="`p{font-size: 13px;}`" :wordStyle="`p{font-size: 13px;}`"
:isAutomaticUpdate="true" :isAutomaticUpdate="true"
@getContent="getContent" @getContent="getContent"
@updateChange="updateChange" @updateChange="(content) => updateChange('abstract',content)"
:value="abstract" :value="abstract"
class="paste-area text-container" class="paste-area text-container"
:toolbar="[ :toolbar="[
@@ -150,6 +212,9 @@
<!-- <quill-editor ref="myTextEditor" v-model="detailMes.abstract" :options="editorOption"> </quill-editor> --> <!-- <quill-editor ref="myTextEditor" v-model="detailMes.abstract" :options="editorOption"> </quill-editor> -->
</el-form-item> </el-form-item>
<el-form-item label="Executive editor :" prop="executive_editor">
<el-input v-model="detailMes.executive_editor"></el-input>
</el-form-item>
</el-form> </el-form>
<div style="text-align: center; margin: 25px 0 0 0"> <div style="text-align: center; margin: 25px 0 0 0">
<el-button type="primary" @click="ZsSaveMes" class="save-btn"> <el-button type="primary" @click="ZsSaveMes" class="save-btn">
@@ -997,6 +1062,8 @@ export default {
journal_special_id: 'None' journal_special_id: 'None'
}, },
abstract: '', abstract: '',
tradition: '',
mhooStr: '',
opInstal: [], opInstal: [],
// opMedical: [ // opMedical: [
// { // {
@@ -1358,6 +1425,18 @@ export default {
message: 'Please enter mechanism', message: 'Please enter mechanism',
trigger: 'blur' trigger: 'blur'
} }
],
executive_editor: [
{
required: true,
message: 'Please enter the executive editor',
trigger: 'blur'
},
{
pattern: /^[^\u4e00-\u9fa5]*$/,
message: 'Please use English characters only',
trigger: 'blur'
}
] ]
} }
}; };
@@ -1381,7 +1460,7 @@ export default {
// article_id: 6075 // article_id: 6075
}) })
.then((res) => { .then((res) => {
console.log('res at line 1460:', res);
if (res.status == 1) { if (res.status == 1) {
this.finalReview = res.data; this.finalReview = res.data;
} else { } else {
@@ -1389,15 +1468,17 @@ export default {
} }
}); });
}, },
updateChange(content) { updateChange(type, content) {
this.abstract = content;
this[type] = content;
}, },
getTinymceContent(type) { getTinymceContent(type) {
this.$refs.tinymceChild1.getContent(type); this.$refs.tinymceChild1.getContent(type);
}, },
getContent(type, content) { getContent(type, content) {
console.log('content at line 1449:', content);
console.log('type at line 1449:', type);
}, },
// 跳转文章详情 // 跳转文章详情
showdetaileditor(data) { showdetaileditor(data) {
@@ -1459,12 +1540,24 @@ export default {
.then((res) => { .then((res) => {
if (res.code == 0) { if (res.code == 0) {
this.detailMes = res.data.production; this.detailMes = res.data.production;
this.abstract = res.data.production.abstract; 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 != '') { if (this.abstract != '') {
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.tinymceChild1.setContent(this.abstract); 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.UpTyFIle = res.data.production.file_pdf;
this.getArticleFinal(res.data.production.article_id); this.getArticleFinal(res.data.production.article_id);
if (res.data.production.icon != '') { if (res.data.production.icon != '') {
@@ -1753,23 +1846,17 @@ export default {
return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page; return e.stage_year + ' Vol.' + e.stage_vol + ' issue.' + e.stage_no + e.stage_pagename + e.stage_page;
}, },
async abstractFormat(content) { async abstractFormat(content) {
content = this.$commonJS.transformHtmlString(content); content = this.$commonJS.transformHtmlString(content,'content',{keepBr:true});
var div = document.createElement('div'); var div = document.createElement('div');
div.innerHTML = content; div.innerHTML = content;
// 1. 剔除所有 img 标签
var imgTags = div.getElementsByTagName('img'); var imgTags = div.getElementsByTagName('img');
for (var i = imgTags.length - 1; i >= 0; i--) { for (var i = imgTags.length - 1; i >= 0; i--) {
imgTags[i].parentNode.removeChild(imgTags[i]); imgTags[i].parentNode.removeChild(imgTags[i]);
} }
// 2. 新增:剔除所有 table 相关标签table、tr、td
var tableTags = div.getElementsByTagName('table'); var tableTags = div.getElementsByTagName('table');
for (var i = tableTags.length - 1; i >= 0; i--) { for (var i = tableTags.length - 1; i >= 0; i--) {
tableTags[i].parentNode.removeChild(tableTags[i]); tableTags[i].parentNode.removeChild(tableTags[i]);
} }
// 3. 替换 strong → b、em → i原有逻辑
var strongTags = div.getElementsByTagName('strong'); var strongTags = div.getElementsByTagName('strong');
for (var i = 0; i < strongTags.length; i++) { for (var i = 0; i < strongTags.length; i++) {
var bTag = document.createElement('b'); var bTag = document.createElement('b');
@@ -1782,32 +1869,43 @@ export default {
iTag.innerHTML = emTags[i].innerHTML; iTag.innerHTML = emTags[i].innerHTML;
emTags[i].parentNode.replaceChild(iTag, emTags[i]); emTags[i].parentNode.replaceChild(iTag, emTags[i]);
} }
// 处理 p 标签 + 解码 // 处理 p 标签 + 解码
content = div.innerHTML; content = div.innerHTML;
content = content.replace(/^<p>\s*(.*?)\s*<\/p>$/, '$1').trim(); content = content.replace(/^<p>\s*(.*?)\s*<\/p>$/, '$1').trim();
content = await this.$commonJS.decodeHtml(content); content = await this.$commonJS.decodeHtml(content);
content = content.replace(/&nbsp;|\u00A0/g, ' ');
return content; return content;
}, },
// 1----保存稿件信息 // 1----保存稿件信息
async ZsSaveMes() { async ZsSaveMes() {
var abstractStr = ''; var abstractStr = '';
var mhooStr = '';
var traditionStr = '';
if (this.detailMes.journal_stage_id == 0) { if (this.detailMes.journal_stage_id == 0) {
this.$message.error('Please select an installment!'); this.$message.error('Please select an installment!');
return; return;
} if (this.tradition!='') {
traditionStr = await this.abstractFormat(this.tradition);
}
if (this.mhooStr!='') {
mhooStr = await this.abstractFormat(this.mhooStr);
} }
if (this.abstract == '') { if (this.abstract == '') {
this.$message.error('Please input abstract!'); this.$message.error('Please input abstract!');
return; return false;
} else { } else {
abstractStr = await this.abstractFormat(this.abstract); abstractStr = await this.abstractFormat(this.abstract);
} }
console.log('abstractStr at line 1820:', abstractStr);
this.$refs.Mes_Form.validate((valid) => { this.$refs.Mes_Form.validate((valid) => {
if (valid) { if (valid) {
this.$api this.$api
.post('api/Production/editProduction', { ...this.detailMes, abstract: abstractStr }) .post('api/Production/editProduction', { ...this.detailMes, abstract: abstractStr, mhoo: mhooStr, tradition: traditionStr })
.then((res) => { .then((res) => {
if (res.code == 0) { if (res.code == 0) {
this.$message.success(`Successfully save the article!`); this.$message.success(`Successfully save the article!`);
@@ -2904,30 +3002,30 @@ export default {
}, },
onScroll(e) { onScroll(e) {
const scrollContainer = e.target; const scrollContainer = e.target;
const scrollItems = document.querySelectorAll('.scroll-item'); const scrollItems = document.querySelectorAll('.scroll-item');
// 遍历所有滚动项,找到“当前在可视区域内”的项
for (let i = 0; i < scrollItems.length; i++) {
const item = scrollItems[i];
// 计算项相对于滚动容器的位置(顶部距离)
const itemTop = item.offsetTop - scrollContainer.offsetTop;
// 计算项的底部距离
const itemBottom = itemTop + item.offsetHeight;
// 判断:项的顶部 <= 滚动距离,且项的底部 >= 滚动距离(即项在可视区域内 // 遍历所有滚动项,找到“当前在可视区域内”的项
const isInView = (itemTop <= scrollContainer.scrollTop) && (itemBottom >= scrollContainer.scrollTop); for (let i = 0; i < scrollItems.length; i++) {
const item = scrollItems[i];
if (isInView) { // 计算项相对于滚动容器的位置(顶部距离)
this.tabIndex = i.toString(); const itemTop = item.offsetTop - scrollContainer.offsetTop;
// 先判断tabsList是否存在对应索引避免报错 // 计算项的底部距离
if (this.tabsList[i]) { const itemBottom = itemTop + item.offsetHeight;
this.tabName = this.tabsList[i].refName;
// 判断:项的顶部 <= 滚动距离,且项的底部 >= 滚动距离(即项在可视区域内)
const isInView = itemTop <= scrollContainer.scrollTop && itemBottom >= scrollContainer.scrollTop;
if (isInView) {
this.tabIndex = i.toString();
// 先判断tabsList是否存在对应索引避免报错
if (this.tabsList[i]) {
this.tabName = this.tabsList[i].refName;
}
break; // 找到第一个匹配的项就停止
}
} }
break; // 找到第一个匹配的项就停止 },
}
}
},
getHight() { getHight() {
this.contentStyleObj.height = window.innerHeight - 60 + 'px'; this.contentStyleObj.height = window.innerHeight - 60 + 'px';
@@ -2969,9 +3067,9 @@ export default {
font-size: 14px !important; font-size: 14px !important;
padding: 6px 10px !important; padding: 6px 10px !important;
} }
.tab_item{ .tab_item {
height: 6vh; height: 6vh;
min-height: 60px; min-height: 60px;
} }
</style> </style>
<style> <style>

File diff suppressed because it is too large Load Diff

View File

@@ -5,14 +5,19 @@
</template> </template>
<script> <script>
import { string } from 'html-docx-js/dist/html-docx'; import { string } from 'html-docx-js/dist/html-docx';
import axios from 'axios';
import htmlDocx from 'html-docx-js/dist/html-docx.js'; import htmlDocx from 'html-docx-js/dist/html-docx.js';
import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js import { Document, Packer, PageOrientation, Paragraph, TextRun } from 'docx'; // 引入 docx.js
import html2canvas from 'html2canvas'; import html2canvas from 'html2canvas';
import { extractHexImagesFromRTF, hexToBlob } from '@/utils/rtfParser';
const tableStyle = `*{ const tableStyle = `
font-family: 'Charis SIL'; .word-img-placeholder {
} background: #f0f0f0 ;
b span{ }
*{
font-family: 'Charis SIL';
}
b span{
font-weight: bold !important; font-weight: bold !important;
} }
i span{ i span{
@@ -62,7 +67,6 @@ const tableStyle = `*{
mos-line-height: 20px !important; mos-line-height: 20px !important;
} }
table tbody tr td{ table tbody tr td{
text-align:left !important; text-align:left !important;
border-left:none !important; border-left:none !important;
mso-border-left-alt:none !important; mso-border-left-alt:none !important;
@@ -181,6 +185,17 @@ export default {
wordStyle: { wordStyle: {
type: String, type: String,
default: '' default: ''
},
valid_elements: {
type: String,
default: ''
},
tinymceOtherInit: {
type: Object,
default: () => ({})
},
articleId: {
default: ''
} }
}, },
data() { data() {
@@ -301,101 +316,97 @@ export default {
generateUniqueId() { generateUniqueId() {
return 'wmath-' + Math.random().toString(36).substr(2, 9); return 'wmath-' + Math.random().toString(36).substr(2, 9);
}, },
// 同步将 Hex 字符串转为 Base64
hexToBase64Sync(hex, mimeType) {
try {
// 将 Hex 字符串转为字节数组
const bytes = new Uint8Array(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
// 同步转为二进制字符串
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
// 使用 window.btoa 生成 base64
return `data:${mimeType};base64,${window.btoa(binary)}`;
} catch (e) {
console.error('Hex to Base64 conversion failed', e);
return '';
}
},
// 按照你要求的 XMLHttpRequest 格式编写
uploadSingleImage(base64Data, index) {
const _this = this;
//转为 Blob
const blob = _this.dataURLtoBlob(base64Data);
const xhr = new XMLHttpRequest();
const formData = new FormData();
// 按照你截图中的参数名,这里假设是 'file'
formData.append('mainImage', blob, `word_img_${index}.png`);
formData.append('article_id', this.articleId);
xhr.withCredentials = false;
xhr.open('POST', _this.baseUrl + 'api/Preaccept/up_img_mainImage');
xhr.onload = function () {
if (xhr.status !== 200) {
console.error('HTTP Error: ' + xhr.status);
return;
}
try {
const json = JSON.parse(xhr.responseText);
if (json.code === 0) {
// 2. 拼接服务器返回的 URL
const finalUrl = _this.mediaUrl + 'articleImage/' + json.data.upurl;
// 3. 找到对应的加载中占位图并替换
const doc = tinymce.activeEditor.getDoc();
const placeholder = doc.querySelector(`img[data-idx="${index}"]`);
if (placeholder) {
placeholder.src = finalUrl;
placeholder.removeAttribute('data-idx'); // 任务完成,移除标记
}
}
} catch (e) {
console.error('解析响应失败', e);
}
};
xhr.send(formData);
},
// 辅助工具Base64 转 Blob
dataURLtoBlob(dataurl) {
const arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
initTinymce() { initTinymce() {
let globalImgCounter = 0; // 放在 init 闭包内,确保计数器持续增长
let currentPasteBase64Images = [];
var _this = this; var _this = this;
window.tinymce.init({ window.tinymce.init({
..._this.tinymceOtherInit,
inline: false, // 使用 iframe 模式 inline: false, // 使用 iframe 模式
selector: `#${this.tinymceId}`, selector: `#${this.tinymceId}`,
// noneditable_regexp: "/<wmath>.*?<\/wmath>/g", // noneditable_regexp: "/<wmath>.*?<\/wmath>/g",
content_css: false, // 禁用默认样式 content_css: false, // 禁用默认样式
table_resize_bars: true, // 启用拖动调整功能 table_resize_bars: true, // 启用拖动调整功能
valid_elements: this.type == 'table' ? '*[*]' : 'img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,wmath', // 允许的标签和属性 valid_elements:
this.type == 'table'
? '*[*]'
: `img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,wmath${this.valid_elements}`, // 允许的标签和属性
// valid_elements: '*[*]', // 允许所有 HTML 标签 // valid_elements: '*[*]', // 允许所有 HTML 标签
noneditable_editable_class: 'MathJax', noneditable_editable_class: 'MathJax',
height: this.height, height: this.height,
paste_preprocess: function (plugin, args) {
let content = args.content; // 获取粘贴的内容
let tempDiv = document.createElement('div');
tempDiv.innerHTML = content;
if (tempDiv.querySelector('table')) {
console.log('粘贴的内容包含表格');
if (_this.type == 'table') {
_this.$commonJS.parseTableToArray(content, (tableList) => {
var contentHtml = `
<div class="thumbnailTableBox wordTableHtml table_Box" style="">
<table border="1" style="width: auto; border-collapse: collapse; text-align: center;">
${tableList
.map((row) => {
return `
<tr>
${row
.map((cell) => {
return `
<td colspan="${cell.colspan || 1}" rowspan="${cell.rowspan || 1}">
<span>${cell.text || ''}</span>
</td>
`;
})
.join('')}
</tr>
`;
})
.join('')}
</table>
</div>
`;
const container = document.createElement('div');
container.innerHTML = contentHtml;
// _this.updateTableStyles(container); // 根据需要应用额外的样式
args.content = container.innerHTML; // 更新处理后的内容
});
} else {
}
} else {
console.log('Original content:', content); // 输出原始粘贴内容
// 改进的正则表达式,匹配 $$...$$ 格式的 LaTeX 公式
const mathRegex = /\$\$([^$]+)\$\$/g;
// 如果粘贴的内容包含 $$...$$ 格式的公式,进行处理
content = content.replace(mathRegex, function (match, formula) {
console.log('Matched formula:', formula); // 输出每个匹配的公式
// 将公式包裹在 <wmath> 标签中,保留 $$...$$ 结构
return `<wmath data-latex="${match}">${match}</wmath>`;
});
console.log('Processed content:', content); // 输出处理后的内容
}
// 更新 args.content 为处理后的内容
// 阻止默认的粘贴行为,确保自定义处理优先执行
if (args.event) {
args.event.preventDefault();
args.event.stopPropagation();
}
if (_this.isAutomaticUpdate) {
args.content = _this.$commonJS.transformHtmlString(content); // 更新处理后的内容
} else {
args.content = content;
}
setTimeout(() => {
window.renderMathJax(_this.tinymceId);
}, 10);
},
content_style: ` content_style: `
${tableStyle} ${tableStyle}
${_this.wordStyle} ${_this.wordStyle}
`, `,
formats: { formats: {
bold: { inline: 'b' }, bold: { inline: 'b' },
italic: { inline: 'i' } italic: { inline: 'i' }
@@ -407,7 +418,6 @@ export default {
statusbar: false, // 关闭底部状态栏 statusbar: false, // 关闭底部状态栏
custom_colors: false, custom_colors: false,
color_map: ['0082AA', 'TMR Blue'], color_map: ['0082AA', 'TMR Blue'],
// image // image
plugins: 'texttransform noneditable table image', // 启用 forecolor 和 code 插件 plugins: 'texttransform noneditable table image', // 启用 forecolor 和 code 插件
// plugins: 'forecolor code paste table image mathType searchreplace raw', // 启用 forecolor 和 code 插件 // plugins: 'forecolor code paste table image mathType searchreplace raw', // 启用 forecolor 和 code 插件
@@ -419,81 +429,76 @@ export default {
config: 'TeX-AMS-MML_HTMLorMML' config: 'TeX-AMS-MML_HTMLorMML'
}, },
// automatic_uploads: false, // automatic_uploads: false,
// images_upload_handler: function (blobInfo, success, failure, progress) { images_upload_handler: function (blobInfo, progress) {
// console.log('blobInfo at line 419:', blobInfo); return new Promise((resolve, reject) => {
// return new Promise(function (resolve, reject) { const xhr = new XMLHttpRequest();
// const xhr = new XMLHttpRequest(); const formData = new FormData();
// const formData = new FormData(); const file = blobInfo.blob();
// const file = blobInfo.blob(); // 1. 处理文件名:优先使用原始文件名,没有则生成
// let filename = file.name; let filename = blobInfo.filename() || `upload_${Date.now()}.png`;
// if (!filename) { // 2. 构造符合你后端要求的参数
// // 如果没有名字,则手动生成一个 formData.append('mainImage', file, filename);
// const ext = file.type.split('/').pop(); // 从 MIME 类型获取扩展名,例如 'png' // 优先从路由取 id其次取 data 里的 articleId
// const timestamp = Date.now(); formData.append('article_id', _this.articleId);
// filename = `unnamed_${timestamp}.${ext}`; xhr.withCredentials = false;
// } // 拼接你的 baseUrl
// console.log('file at line 424:', file); xhr.open('POST', _this.baseUrl + '/api/Preaccept/up_img_mainImage');
// 上传进度(可选)
xhr.upload.onprogress = (e) => {
progress((e.loaded / e.total) * 100);
};
xhr.onload = function () {
if (xhr.status !== 200) {
reject('HTTP Error: ' + xhr.status);
return;
}
try {
const json = JSON.parse(xhr.responseText);
if (json.code === 0) {
// 3. 按照你的逻辑返回拼接后的完整 URL
const finalUrl = _this.mediaUrl + 'articleImage/' + json.data.upurl;
resolve(finalUrl);
console.log('手动上传成功:', finalUrl);
} else {
reject('Upload Error: ' + json.msg);
}
} catch (e) {
reject('Invalid response: ' + xhr.responseText);
}
};
// xhr.withCredentials = false; xhr.onerror = function () {
// xhr.open('POST', _this.baseUrl + '/api/Preaccept/up_img_mainImage'); reject('网络请求失败');
};
// xhr.onload = function () {
// if (xhr.status !== 200) {
// reject('HTTP Error: ' + xhr.status);
// return;
// }
// try { xhr.send(formData);
// const json = JSON.parse(xhr.responseText); });
// console.log('json at line 434:', json); },
// if (json.code != 0) {
// reject('Upload Error: ' + json.msg);
// return;
// }
// resolve(_this.mediaUrl + 'articleImage/' + json.data.upurl); // ✅ 返回图片 URL 给 TinyMCE 插入
// } catch (e) {
// reject('Invalid response: ' + xhr.responseText);
// }
// };
// formData.append('mainImage', file, filename);
// formData.append('article_id', _this.$route.query.id);
// xhr.send(formData);
// });
// },
//设置自定义按钮 myCustomToolbarButton //设置自定义按钮 myCustomToolbarButton
setup(ed) { setup(ed) {
let currentPasteImages = [];
_this.$commonJS.initEditorButton(_this, ed); _this.$commonJS.initEditorButton(_this, ed);
var currentWmathElement = null; var currentWmathElement = null;
ed.on('click', function (e) { ed.on('click', function (e) {
const wmathElement = e.target.closest('wmath'); const wmathElement = e.target.closest('wmath');
if (wmathElement) { if (wmathElement) {
currentWmathElement = wmathElement; // 👈 保存当前点击的元素 currentWmathElement = wmathElement; // 👈 保存当前点击的元素
const latexContentRaw = wmathElement.getAttribute('data-latex') || ''; const latexContentRaw = wmathElement.getAttribute('data-latex') || '';
console.log('at line 488: raw =', latexContentRaw); console.log('at line 488: raw =', latexContentRaw);
// 去除所有 $ 符号 // 去除所有 $ 符号
const latexContent = latexContentRaw.replace(/\$/g, '').trim(); const latexContent = latexContentRaw.replace(/\$/g, '').trim();
// console.log('at line 489: cleaned =', latexContent);
// 编码后用于传递到弹窗 // 编码后用于传递到弹窗
const encoded = encodeURIComponent(latexContent); const encoded = encodeURIComponent(latexContent);
// 给 wmath 添加唯一 data-id方便后续精准替换 // 给 wmath 添加唯一 data-id方便后续精准替换
let wmathId = wmathElement.getAttribute('data-id'); let wmathId = wmathElement.getAttribute('data-id');
if (!wmathId) { if (!wmathId) {
wmathId = 'wmath-' + Math.random().toString(36).substr(2, 9); wmathId = 'wmath-' + Math.random().toString(36).substr(2, 9);
wmathElement.setAttribute('data-id', wmathId); wmathElement.setAttribute('data-id', wmathId);
} }
// 当前编辑器 ID 也保存下来(如果你有多个编辑器) // 当前编辑器 ID 也保存下来(如果你有多个编辑器)
const editorId = ed.id; const editorId = ed.id;
// 打开编辑窗口并传参(传递 data-id + 内容) // 打开编辑窗口并传参(传递 data-id + 内容)
window.open( window.open(
`/LateX?id=${encoded}&wmathId=${wmathId}&editorId=${editorId}`, `/LateX?id=${encoded}&wmathId=${wmathId}&editorId=${editorId}`,
@@ -502,6 +507,17 @@ export default {
); );
} }
}); });
// 修改 paste 事件中的逻辑
ed.on('paste', (event) => {
const rtf = event.clipboardData.getData('text/rtf');
if (rtf && rtf.includes('\\pict')) {
const extracted = extractHexImagesFromRTF(rtf);
extracted.forEach((img, i) => {
const base64 = _this.hexToBase64Sync(img.hex, img.mimeType);
_this.uploadSingleImage(base64, i);
});
}
});
ed.ui.registry.addButton('uploadWord', { ed.ui.registry.addButton('uploadWord', {
text: 'Word', text: 'Word',
@@ -527,19 +543,12 @@ export default {
input.click(); input.click();
} }
}); });
ed.on('init', function () { ed.on('init', function () {
_this.$commonJS.inTinymceButtonClass(); _this.$commonJS.inTinymceButtonClass();
const editorBody = ed.getBody(); const editorBody = ed.getBody();
// 监听点击事件来确保用户可以删除<wmath>元素
// 创建 MutationObserver 监听内容变化
const observer = new MutationObserver(() => { const observer = new MutationObserver(() => {
const currentContent = ed.getContent(); const currentContent = ed.getContent();
// console.log('currentContent at line 484:', currentContent)
// console.log('currentContent at line 447:', currentContent);
if (_this.isAutomaticUpdate) { if (_this.isAutomaticUpdate) {
_this.$emit('updateChange', currentContent); _this.$emit('updateChange', currentContent);
// _this.$emit('updateChange', _this.$commonJS.decodeHtml(currentContent)); // _this.$emit('updateChange', _this.$commonJS.decodeHtml(currentContent));
@@ -606,6 +615,91 @@ export default {
e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>'); e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>');
}); });
}, },
paste_preprocess: function (plugin, args) {
let imgIdx = 0;
const silentPlaceholder = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
let content = args.content.replace(/(<img[^>]*?)src="file:\/\/\/[^" ]*"/gi, (match, p1) => {
// 保留 data-idx Word 里的尺寸
return `${p1}src="${silentPlaceholder}" class="word-img-placeholder" data-idx="${imgIdx++}"`;
});
let tempDiv = document.createElement('div');
tempDiv.innerHTML = content;
if (tempDiv.querySelector('table')) {
console.log('粘贴的内容包含表格');
if (_this.type == 'table') {
// 3. 在这里直接消费外部变量 currentPasteBase64Images
// content = content.replace(new RegExp(`src="${silentPlaceholder}"`, 'gi'), () => {
// // 按顺序取图
// const base64Data = currentPasteBase64Images[globalImgCounter] || '';
// globalImgCounter++;
// return `src="${base64Data}"`;
// });
_this.$commonJS.parseTableToArray(content, (tableList) => {
var contentHtml = `
<div class="thumbnailTableBox wordTableHtml table_Box table_Box3333" style="">
<table border="1" style="width: auto; border-collapse: collapse; text-align: center;">
${tableList
.map((row) => {
return `
<tr>
${row
.map((cell) => {
return `
<td colspan="${cell.colspan || 1}" rowspan="${cell.rowspan || 1}">
<span>${cell.text || ''}</span>
</td>
`;
})
.join('')}
</tr>
`;
})
.join('')}
</table>
</div>
`;
const container = document.createElement('div');
container.innerHTML = contentHtml;
// _this.updateTableStyles(container); // 根据需要应用额外的样式
args.content = container.innerHTML; // 更新处理后的内容
});
} else {
}
} else {
console.log('Original content:', content); // 输出原始粘贴内容
// 改进的正则表达式,匹配 $$...$$ 格式的 LaTeX 公式
const mathRegex = /\$\$([^$]+)\$\$/g;
// 如果粘贴的内容包含 $$...$$ 格式的公式,进行处理
content = content.replace(mathRegex, function (match, formula) {
console.log('Matched formula:', formula); // 输出每个匹配的公式
// 将公式包裹在 <wmath> 标签中,保留 $$...$$ 结构
return `<wmath data-latex="${match}">${match}</wmath>`;
});
console.log('Processed content:', content); // 输出处理后的内容
}
// 更新 args.content 为处理后的内容
// 阻止默认的粘贴行为,确保自定义处理优先执行
if (args.event) {
args.event.preventDefault();
args.event.stopPropagation();
}
if (_this.isAutomaticUpdate) {
args.content = _this.$commonJS.transformHtmlString(content); // 更新处理后的内容
} else {
args.content = content;
}
setTimeout(() => {
window.renderMathJax(_this.tinymceId);
}, 10);
},
init_instance_callback: (editor) => { init_instance_callback: (editor) => {
if (_this.value) { if (_this.value) {
editor.setContent(_this.value); editor.setContent(_this.value);
@@ -694,19 +788,15 @@ export default {
}, },
//设置内容 //设置内容
setContent(value) { setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value); window.tinymce.get(this.tinymceId).setContent(value);
}, },
//获取内容 //获取内容
async getContent(type) { async getContent(type) {
var content = window.tinymce.get(this.tinymceId).getContent(); var content = window.tinymce.get(this.tinymceId).getContent();
content = content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签 content = content.replace(/<span[^>]*>/g, '').replace(/<\/span>/g, ''); // 去除span标签
content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>'); content = content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
content = content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>'); content = content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
content = content.replace(/&nbsp;/g, ' '); // 将所有 &nbsp; 替换为空格 content = content.replace(/&nbsp;/g, ' '); // 将所有 &nbsp; 替换为空格
console.log('content at line 632:', content);
this.$emit('getContent', type, content); this.$emit('getContent', type, content);
}, },
@@ -817,4 +907,8 @@ export default {
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
} }
::v-deep .tox:not(.tox-tinymce-inline) .tox-editor-header {
padding: 0 !important;
}
</style> </style>

View File

@@ -452,7 +452,7 @@ export default {
article_id: this.articleId article_id: this.articleId
}) })
.then((res) => { .then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.articleInfo = res.data.article_detail; this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail; this.journalInfo = res.data.journal_detail;

View File

@@ -353,7 +353,7 @@ export default {
}) })
.then((res) => { .then((res) => {
loading.close(); loading.close();
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.articleInfo = res.data.article_detail; this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail; this.journalInfo = res.data.journal_detail;

View File

@@ -280,7 +280,7 @@ that.orderInfo=res.data.detail
article_id: this.articleId article_id: this.articleId
}) })
.then((res) => { .then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.articleInfo = res.data.article_detail; this.articleInfo = res.data.article_detail;
this.journalInfo = res.data.journal_detail; this.journalInfo = res.data.journal_detail;

View File

@@ -147,7 +147,7 @@ export default {
.then((res) => { .then((res) => {
loading.close(); loading.close();
this.paymentChecking = true; this.paymentChecking = true;
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.articleBaseInfo = res.data.article_detail; this.articleBaseInfo = res.data.article_detail;
this.journalBaseInfo = res.data.journal_detail; this.journalBaseInfo = res.data.journal_detail;
@@ -169,7 +169,7 @@ export default {
article_id: this.articleId article_id: this.articleId
}) })
.then((res) => { .then((res) => {
console.log('res at line 191:', res);
if (res.code == 0) { if (res.code == 0) {
this.hideAlert(); this.hideAlert();

View File

@@ -577,7 +577,7 @@ export default {
chekEmail(value) { chekEmail(value) {
setTimeout(() => { setTimeout(() => {
this.reviewerForm = {}; this.reviewerForm = {};
console.log('value at line 504:', value, this.reviewerForm);
if (value) { if (value) {
this.chaSelChose({ this.chaSelChose({
email: value email: value
@@ -602,7 +602,7 @@ export default {
restaurants[i].value = restaurants[i].email; restaurants[i].value = restaurants[i].email;
} }
var results = value ? restaurants.filter(this.createMata(value)) : restaurants; var results = value ? restaurants.filter(this.createMata(value)) : restaurants;
console.log('🚀 ~ .then ~ results177:', results);
// 调用 callback 返回建议列表的数据 // 调用 callback 返回建议列表的数据
cb(results); cb(results);
// this.form.authorList[num].load = false; // this.form.authorList[num].load = false;
@@ -659,8 +659,7 @@ export default {
}, },
// 选中用户 // 选中用户
async chaSelChose(value, num) { async chaSelChose(value, num) {
console.log('value at line 545:', value);
// console.log(value); // console.log(value);
// console.log(num); // console.log(num);
if (!this.addForm.email) { if (!this.addForm.email) {
@@ -673,7 +672,7 @@ export default {
email: this.addForm.email email: this.addForm.email
}) })
.then((res) => { .then((res) => {
console.log('res at line 554:', res);
if (res.code == 0) { if (res.code == 0) {
this.btn_alert = false; this.btn_alert = false;
this.reviewerForm = res.data.result; this.reviewerForm = res.data.result;
@@ -735,7 +734,7 @@ export default {
? item.shu.split(',').map(Number) ? item.shu.split(',').map(Number)
: [item.shu] : [item.shu]
})); }));
console.log('this.majorValueList at line 903:', this.majorValueList);
// if (this.reviewerForm.majorList) { // if (this.reviewerForm.majorList) {
// if (this.reviewerForm.majorList.length >= 1) { // if (this.reviewerForm.majorList.length >= 1) {
// this.reviewerForm.major_a = this.reviewerForm.majorList[0]; // this.reviewerForm.major_a = this.reviewerForm.majorList[0];
@@ -755,7 +754,7 @@ export default {
// this.addForm.major = this.addForm.major_a; // this.addForm.major = this.addForm.major_a;
// } // }
this.$forceUpdate(); this.$forceUpdate();
console.log('this.addForm.majorList at line 674:', this.reviewerForm);
this.$nextTick(async () => { this.$nextTick(async () => {
// await this.jiLInaoan(); // await this.jiLInaoan();
await this.getJournalsForReviewerInEditor(); await this.getJournalsForReviewerInEditor();
@@ -778,7 +777,7 @@ export default {
// this.reviewerForm = { // this.reviewerForm = {
// email: value.email // email: value.email
// }; // };
console.log('value at line 529:', value, this.reviewerForm);
// this.$forceUpdate(); // this.$forceUpdate();
}, },

View File

@@ -351,7 +351,7 @@ export default {
onAction: function () { onAction: function () {
// 在选中的文本周围包裹 <blue> 标签 // 在选中的文本周围包裹 <blue> 标签
var selectedText = ed.selection.getContent(); var selectedText = ed.selection.getContent();
console.log('selectedText at line 529:', selectedText);
if (selectedText) { if (selectedText) {
var wrappedText = `<blue>${selectedText}</blue>`; var wrappedText = `<blue>${selectedText}</blue>`;
ed.selection.setContent(wrappedText); ed.selection.setContent(wrappedText);

View File

@@ -5,6 +5,7 @@
<!-- image --> <!-- image -->
<tinymce <tinymce
type="table" type="table"
:articleId="articleId"
ref="tinymceChild1" ref="tinymceChild1"
:wordStyle="wordStyle" :wordStyle="wordStyle"
@getContent="getContent" @getContent="getContent"
@@ -33,7 +34,7 @@
<script> <script>
import Tinymce from '@/components/page/components/Tinymce'; import Tinymce from '@/components/page/components/Tinymce';
export default { export default {
props: ['lineStyle'], props: ['lineStyle','articleId'],
components: { components: {
Tinymce Tinymce
}, },

View File

@@ -59,48 +59,48 @@ async function loadJournalType() {
let parsedData = null; let parsedData = null;
if (cachedString) { if (cachedString) {
try { try {
// 必须先解析 JSON 字符串 // 必须先解析 JSON 字符串
parsedData = JSON.parse(cachedString); parsedData = JSON.parse(cachedString);
} catch (e) { } catch (e) {
console.error("缓存数据解析失败,将重新请求 API:", e); console.error("缓存数据解析失败,将重新请求 API:", e);
} }
} }
// 2. 检查解析后的数据是否有效(是数组且长度大于 0 // 2. 检查解析后的数据是否有效(是数组且长度大于 0
if (parsedData && Array.isArray(parsedData) && parsedData.length > 0) { if (parsedData && Array.isArray(parsedData) && parsedData.length > 0) {
// 缓存有效,直接返回缓存数据 // 缓存有效,直接返回缓存数据
return parsedData; return parsedData;
} }
// 3. 如果缓存无效或不存在,执行 API 调用 // 3. 如果缓存无效或不存在,执行 API 调用
try { try {
// 第一个 API 调用,使用 await 接收结果 // 第一个 API 调用,使用 await 接收结果
const journalRes = await api.post('api/Articletype/getArticleType', {}); const journalRes = await api.post('api/Articletype/getArticleType', {});
if (journalRes.status === 1) { if (journalRes.status === 1) {
// 存储 journal data // 存储 journal data
localStorage.setItem('journalTypeData', JSON.stringify(journalRes.data.base)); localStorage.setItem('journalTypeData', JSON.stringify(journalRes.data.base));
localStorage.setItem('journalTypeDataAll', JSON.stringify([...journalRes.data.base, ...journalRes.data.supplement])); localStorage.setItem('journalTypeDataAll', JSON.stringify([...journalRes.data.base, ...journalRes.data.supplement]));
} }
// 第二个 API 调用,串行执行 // 第二个 API 调用,串行执行
const medicalRes = await api.post('api/Articletype/getMedicalType', {}); const medicalRes = await api.post('api/Articletype/getMedicalType', {});
if (medicalRes.status === 1) { if (medicalRes.status === 1) {
// 存储 medical data // 存储 medical data
localStorage.setItem('opMedicalListData', JSON.stringify(medicalRes.data)); localStorage.setItem('opMedicalListData', JSON.stringify(medicalRes.data));
} }
// 4. 返回第一个 API 调用的主要数据 // 4. 返回第一个 API 调用的主要数据
if (journalRes.status === 1) { if (journalRes.status === 1) {
return journalRes.data.base; return journalRes.data.base;
} }
} catch (error) { } catch (error) {
// 集中处理 API 调用失败 // 集中处理 API 调用失败
console.error('Error loading data:', error); console.error('Error loading data:', error);
return []; // 失败时返回一个默认的空数组,避免程序崩溃 return []; // 失败时返回一个默认的空数组,避免程序崩溃
} }
// 如果所有流程都没有返回,默认返回空数组 // 如果所有流程都没有返回,默认返回空数组
return []; return [];
} }
@@ -110,7 +110,7 @@ async function loadJournalType() {
async function loadJournalList() { async function loadJournalList() {
try { try {
const localData = store.state.journalList; const localData = store.state.journalList;
if (localData && Array.isArray(localData) && localData.length > 0) { if (localData && Array.isArray(localData) && localData.length > 0) {
return localData; return localData;
} }
@@ -171,51 +171,36 @@ Vue.filter('jtName', function (value) {
// 使用 ES Module // 使用 ES Module
import * as echarts from 'echarts'; import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts Vue.prototype.$echarts = echarts
Vue.prototype.$api = api Vue.prototype.$api = api
Vue.config.productionTip = false; Vue.config.productionTip = false;
import Editor from "@tinymce/tinymce-vue"; // 默认导入 import Editor from "@tinymce/tinymce-vue"; // 默认导入
Vue.component("Editor", Editor); Vue.component("Editor", Editor);
//自定义组件
const components = {
'common-table': () => import('@/components/page/components/table/table.vue'),
'common-review-article': () => import('@/components/page/components/reviewArticle/index.vue'),
'common-editor-article': () => import('@/components/page/components/EditorArticle/index.vue'),
'common-editor-article-detail': () => import('@/components/page/components/EditorArticle/detail.vue'),
'common-late-x': () => import('@/components/page/components/table/LateX.vue'),
'common-major': () => import('@/components/page/components/major/index.vue'),
'common-major-list': () => import('@/components/page/components/major/list.vue'),
'common-paypal-button': () => import('@/components/page/components/pendingPayment/PayPalButton.vue'),
'common-tiff': () => import('@/components/page/components/table/tiff.vue'),
'common-content': () => import('@/components/page/components/table/content.vue'),
'common-word': () => import('@/components/page/components/table/word.vue'),
'common-comment': () => import('@/components/page/components/table/comment.vue'),
'common-edit-table': () => import('@/components/page/components/table/editTable.vue'),
'common-annotations': () => import('@/components/page/components/table/annotations.vue'),
'common-word-html': () => import('@/components/page/components/table/wordHtml.vue'),
'common-word-html-type-setting': () => import('@/components/page/components/table/wordHtmlTypesetting.vue'),
'common-drag-word': () => import('@/components/page/components/table/dragWord.vue'),
};
import commonTable from '@/components/page/components/table/table.vue' Object.keys(components).forEach(key => {
Vue.component('common-table', commonTable); Vue.component(key, components[key]);
import commonReviewArticle from '@/components/page/components/reviewArticle/index.vue' });
Vue.component('common-review-article', commonReviewArticle);
import commonEditorArticle from '@/components/page/components/EditorArticle/index.vue'
Vue.component('common-editor-article', commonEditorArticle);
import commonEditorArticleDetail from '@/components/page/components/EditorArticle/detail.vue'
Vue.component('common-editor-article-detail', commonEditorArticleDetail);
import commonLateX from '@/components/page/components/table/LateX.vue'
Vue.component('common-late-x', commonLateX);
import commonMajor from '@/components/page/components/major/index.vue'
Vue.component('common-major', commonMajor);
import commonMajorList from '@/components/page/components/major/list.vue'
Vue.component('common-major-list', commonMajorList);
import commonPayPalButton from '@/components/page/components/pendingPayment/PayPalButton.vue'
Vue.component('common-paypal-button', commonPayPalButton);
import commonTiff from '@/components/page/components/table/tiff.vue'
Vue.component('common-tiff', commonTiff);
import commonContent from '@/components/page/components/table/content.vue'
Vue.component('common-content', commonContent);
import commonWord from '@/components/page/components/table/word.vue'
Vue.component('common-comment', commonComment);
import commonEditTable from '@/components/page/components/table/editTable.vue'
Vue.component('common-edit-table', commonEditTable);
import commonComment from '@/components/page/components/table/comment.vue'
Vue.component('common-word', commonWord);
import commonAnnotations from '@/components/page/components/table/annotations.vue'
Vue.component('common-annotations', commonAnnotations);
import commonWordHtml from '@/components/page/components/table/wordHtml.vue'
Vue.component('common-word-html', commonWordHtml);
import commonWordHtmlTypesetting from '@/components/page/components/table/wordHtmlTypesetting.vue'
Vue.component('common-word-html-type-setting', commonWordHtmlTypesetting);
import commonDragWord from '@/components/page/components/table/dragWord.vue'
Vue.component('common-drag-word', commonDragWord);
Vue.use(VueI18n); Vue.use(VueI18n);
Vue.use(ElementUI, { Vue.use(ElementUI, {
size: 'small', size: 'small',
@@ -228,22 +213,22 @@ const i18n = new VueI18n({
//使用钩子函数对路由进行权限跳转 //使用钩子函数对路由进行权限跳转
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const currentRoute = to; // 获取当前路由路径,例如 "/home" const currentRoute = to; // 获取当前路由路径,例如 "/home"
console.log('currentRoute at line 211:', currentRoute.meta)
if(currentRoute.meta.hideJournal){
}else{
try {
// 尝试请求接口(即使失败也继续后续逻辑)
await Promise.all([
loadJournalList(),
loadJournalType()
]);
} catch (err) {
// 仅打印错误,不阻断路由
} if (currentRoute.meta.hideJournal) {
} else {
try {
// 尝试请求接口(即使失败也继续后续逻辑)
await Promise.all([
loadJournalList(),
loadJournalType()
]);
} catch (err) {
// 仅打印错误,不阻断路由
}
} }
// 无论接口成功/失败,都执行原有跳转逻辑 // 无论接口成功/失败,都执行原有跳转逻辑
document.title = `${to.meta.title} | Traditional Medicine Research`; document.title = `${to.meta.title} | Traditional Medicine Research`;

50
src/utils/rtfParser.js Normal file
View File

@@ -0,0 +1,50 @@
/**
* 从 RTF 字符串中提取图片并返回 Hex 数组
*/
export function extractHexImagesFromRTF(rtfData) {
const images = [];
if (!rtfData) return images;
// 1. 按照图片起始符切分
const blocks = rtfData.split('\\pict');
for (let i = 1; i < blocks.length; i++) {
const block = blocks[i];
// 2. 识别格式
let mimeType = '';
if (block.includes('\\pngblip')) mimeType = 'image/png';
else if (block.includes('\\jpegblip')) mimeType = 'image/jpeg';
else continue;
// 3. 暴力匹配:寻找块中所有连续的 0-9a-f 字符(忽略空格和换行)
// 我们找的是最短长度超过 128 位的字符串,这通常就是图片主体
const allHexGroups = block.match(/[0-9a-fA-F\s\r\n]{128,}/g);
if (allHexGroups) {
// 取这一组里最长的那段(防止误删中间的控制符)
const longestHex = allHexGroups.sort((a, b) => b.length - a.length)[0];
const cleanHex = longestHex.replace(/[\s\r\n]/g, '');
if (cleanHex.length > 256) { // 再次校验长度
images.push({
mimeType: mimeType,
hex: cleanHex
});
}
}
}
return images;
}
/**
* 将 Hex 转换为 Blob
*/
export function hexToBlob(hexString, type) {
const bytes = new Uint8Array(hexString.length / 2);
for (let i = 0; i < hexString.length; i += 2) {
bytes[i / 2] = parseInt(hexString.substr(i, 2), 16);
}
return new Blob([bytes], { type });
}

View File

@@ -76,8 +76,8 @@ module.exports = {
// target: 'http://192.168.110.110/tougao/public/index.php/', // target: 'http://192.168.110.110/tougao/public/index.php/',
// target: 'http://api.tmrjournals.com/public/index.php/',//正式 // target: 'http://api.tmrjournals.com/public/index.php/',//正式
// target: 'http://zmzm.tougao.dev.com/',//晓玲 // target: 'http://zmzm.tougao.dev.com/',//晓玲
target: 'https://submission.tmrjournals.com/',//正式 // target: 'https://submission.tmrjournals.com/',//正式
// target: 'http://tougaotest.tmrjournals.com/public/index.php/',//测试环境 target: 'http://tougaotest.tmrjournals.com/public/index.php/',//测试环境
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
'^/api': '' '^/api': ''