作者背调
This commit is contained in:
@@ -947,6 +947,14 @@ const en = {
|
||||
selectTemplateStyleFirst: 'Please select template and style first',
|
||||
recipientLimit: 'You can add up to {count} recipient(s)',
|
||||
recipientLimitPlaceholder: 'Limit reached (max {count})',
|
||||
sendBatchTitle: 'Send result',
|
||||
sendBatchSuccess: 'Sent successfully:',
|
||||
sendBatchFail: 'Failed to send:',
|
||||
sendBatchConfirm: 'OK',
|
||||
sendProgressTitle: 'Sending mail',
|
||||
sendProgressRunning: 'Sending… {done}/{total} completed',
|
||||
sendProgressAllSuccess: 'All sent successfully ({count})',
|
||||
sendProgressDone: 'Done: {ok} sent, {fail} failed',
|
||||
backToInbox: 'Back to email list',
|
||||
},
|
||||
home: {
|
||||
@@ -1287,6 +1295,8 @@ const en = {
|
||||
addTemplateBtn: 'Go add templates',
|
||||
templateTab: 'Template',
|
||||
styleTab: 'Style',
|
||||
noStyle: 'No style',
|
||||
noStyleDesc: 'Apply template body only, without header/footer',
|
||||
loading: 'Loading...',
|
||||
refresh: 'Refresh'
|
||||
},
|
||||
@@ -1627,6 +1637,10 @@ const en = {
|
||||
dialogIntroduction: 'Introduction :',
|
||||
cancel: 'Cancel'
|
||||
},
|
||||
articleDetailEditor: {
|
||||
reReviewNotifyBtn: 'Notify re-review',
|
||||
reReviewNotifyTitle: 'Notify re-review'
|
||||
},
|
||||
refRelevance: {
|
||||
startDetect: 'Batch Audit Reference Context',
|
||||
startDetectTip:
|
||||
|
||||
@@ -932,6 +932,14 @@ const zh = {
|
||||
selectTemplateStyleFirst: '请先选择模板和风格',
|
||||
recipientLimit: '最多只能添加 {count} 个收件人',
|
||||
recipientLimitPlaceholder: '已达上限(最多 {count} 个)',
|
||||
sendBatchTitle: '发送结果',
|
||||
sendBatchSuccess: '发送成功:',
|
||||
sendBatchFail: '发送失败:',
|
||||
sendBatchConfirm: '确定',
|
||||
sendProgressTitle: '正在发送邮件',
|
||||
sendProgressRunning: '正在发送,已完成 {done}/{total}',
|
||||
sendProgressAllSuccess: '全部发送成功,共 {count} 封',
|
||||
sendProgressDone: '发送完成:成功 {ok} 封,失败 {fail} 封',
|
||||
backToInbox: '返回收件箱',
|
||||
},
|
||||
home: {
|
||||
@@ -1267,6 +1275,8 @@ const zh = {
|
||||
addTemplateBtn: '去新增模板',
|
||||
templateTab: '模版',
|
||||
styleTab: '样式',
|
||||
noStyle: '不使用样式',
|
||||
noStyleDesc: '仅应用模板正文,不套页眉页脚',
|
||||
loading: '加载中...',
|
||||
refresh: '刷新'
|
||||
},
|
||||
@@ -1607,6 +1617,10 @@ const zh = {
|
||||
dialogIntroduction: '简介:',
|
||||
cancel: '取消'
|
||||
},
|
||||
articleDetailEditor: {
|
||||
reReviewNotifyBtn: '通知复审',
|
||||
reReviewNotifyTitle: '通知复审'
|
||||
},
|
||||
refRelevance: {
|
||||
startDetect: '全量引文相关性核查',
|
||||
startDetectTip: '一键启动对本篇稿件全部参考文献与正文语境的 AI 一致性核查',
|
||||
|
||||
@@ -812,9 +812,14 @@
|
||||
>
|
||||
</span>
|
||||
<span v-else>
|
||||
<!-- 无数据:补全空内容(可自定义为“-”“无”等) -->
|
||||
|
||||
<span>-</span>
|
||||
<el-button
|
||||
v-if="index1 === 0 && showReReviewNotifyBtn(iken)"
|
||||
type="text"
|
||||
size="mini"
|
||||
style="margin-left: 8px"
|
||||
@click.stop="openReReviewNotifyMail(iken)"
|
||||
>{{ $t('articleDetailEditor.reReviewNotifyBtn') }}</el-button>
|
||||
</span>
|
||||
</td>
|
||||
</template>
|
||||
@@ -1126,6 +1131,16 @@
|
||||
</el-dialog>
|
||||
<!-- 审稿详情 start-->
|
||||
<reviewerDetail ref="reviewerDetail" v-if="reviewerVisible" :reviewerDetail="reviewerDetail" destroy-on-close></reviewerDetail>
|
||||
<re-review-notify-mail-dialog
|
||||
:visible.sync="reReviewNotifyVisible"
|
||||
:reviewer="reReviewNotifyReviewer"
|
||||
:article-id="editform.articleId"
|
||||
:article-title="form.title"
|
||||
:accept-sn="form.accept_sn"
|
||||
:journal-id="form.journal"
|
||||
:journal-name="form.journal_name"
|
||||
:journal-url="form.journal_url"
|
||||
/>
|
||||
<!-- 审稿详情 end-->
|
||||
<el-dialog title="Edit H Index" :visible.sync="HEditVisible" width="400px" :close-on-click-modal="false">
|
||||
<div style="margin: 0 0 20px 10px; font-weight: bold">{{ HIxForm.realname }}</div>
|
||||
@@ -1547,11 +1562,13 @@
|
||||
import timetalk from './time_talk';
|
||||
import reviewerDetail from '../../components/page/components/articleDetail/reviewerdetail.vue';
|
||||
import FigureCopyright from '../../components/page/components/articleDetail/FigureCopyright.vue';
|
||||
import ReReviewNotifyMailDialog from '../../components/page/components/articleDetail/ReReviewNotifyMailDialog.vue';
|
||||
export default {
|
||||
components: {
|
||||
timetalk,
|
||||
reviewerDetail,
|
||||
FigureCopyright
|
||||
FigureCopyright,
|
||||
ReReviewNotifyMailDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -1561,6 +1578,8 @@ export default {
|
||||
finalDecisionData: {},
|
||||
FinalDecisionVisible: false,
|
||||
reviewerVisible: false,
|
||||
reReviewNotifyVisible: false,
|
||||
reReviewNotifyReviewer: null,
|
||||
expanded: false,
|
||||
corresVisible: false,
|
||||
isShowAuthorInfo: false,
|
||||
@@ -1658,6 +1677,8 @@ export default {
|
||||
articleId: this.$route.query.id,
|
||||
journal: '',
|
||||
journalname: '',
|
||||
journal_name: '',
|
||||
journal_url: '',
|
||||
username: '',
|
||||
title: '',
|
||||
accept_sn: '',
|
||||
@@ -2272,6 +2293,23 @@ export default {
|
||||
this.$refs.reviewerDetail.init(item.art_rev_id, type, repeatItem);
|
||||
});
|
||||
},
|
||||
showReReviewNotifyBtn(reviewer) {
|
||||
if (!this.isReReviewNotifyEnabled()) return false;
|
||||
if (!reviewer) return false;
|
||||
const hasFirstReview =
|
||||
Number(reviewer.state) !== 0 && [1, 2, 3, 4].includes(Number(reviewer.recommend));
|
||||
if (!hasFirstReview) return false;
|
||||
const second = Array.isArray(reviewer.repeat) ? reviewer.repeat[0] : null;
|
||||
if (!second) return true;
|
||||
return ![1, 2, 3].includes(Number(second.recommend));
|
||||
},
|
||||
isReReviewNotifyEnabled() {
|
||||
return Object.prototype.hasOwnProperty.call(this.$route.query, 'zy');
|
||||
},
|
||||
openReReviewNotifyMail(reviewer) {
|
||||
this.reReviewNotifyReviewer = reviewer ? { ...reviewer } : null;
|
||||
this.reReviewNotifyVisible = true;
|
||||
},
|
||||
|
||||
goReviewerDetail(id) {
|
||||
console.log('id at line 1112:', id);
|
||||
@@ -2694,7 +2732,9 @@ export default {
|
||||
: '';
|
||||
this.form.title = res.article.title;
|
||||
this.form.journal = res.article.journal_id;
|
||||
this.form.journalname = res.article.journalname;
|
||||
this.form.journal_name = res.article.journal_name || res.article.journalname || '';
|
||||
this.form.journalname = res.article.journalname || res.article.journal_name || '';
|
||||
this.form.journal_url = res.article.journal_url || res.article.website || res.article.journal_website || '';
|
||||
this.form.abstrart = res.article.abstrart;
|
||||
this.form.accept_sn = res.article.accept_sn;
|
||||
this.form.scoring = res.article.scoring;
|
||||
|
||||
@@ -275,41 +275,40 @@
|
||||
>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div style="display: flex; align-items: center; width: calc(100% - 120px)">
|
||||
<span class="reportIcon" style="cursor: pointer" @click="linkEmail(item, v.art_aut_id)"
|
||||
<span class="reportIcon"
|
||||
><i class="el-icon-s-custom"></i
|
||||
></span>
|
||||
<span
|
||||
@click="linkEmail(item, v.art_aut_id)"
|
||||
style="
|
||||
max-width: calc(100% - 60px);
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>{{ v.realname || v.email || '-' }}
|
||||
<span class="author-name">{{ v.realname || v.email || '-' }}</span>
|
||||
<span class="author-action-icons">
|
||||
<span
|
||||
class="author-action-btn author-action-btn--mail"
|
||||
title="Send email"
|
||||
@click.stop="linkEmail(item, v.art_aut_id)"
|
||||
>
|
||||
<svg class="author-action-svg" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2 3.5A1.5 1.5 0 0 1 3.5 2h9A1.5 1.5 0 0 1 14 3.5v9A1.5 1.5 0 0 1 12.5 14h-9A1.5 1.5 0 0 1 2 12.5v-9zm1.2-.5 4.8 3.6L12.8 3H3.2zM3 4.3v7.7h10V4.3l-4.5 3.4a.6.6 0 0 1-.7 0L3 4.3z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="author-action-btn author-action-btn--search"
|
||||
title="Search author"
|
||||
@click.stop="openAuthorSearch(v)"
|
||||
>
|
||||
<svg class="author-action-svg" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M7 1.25a5.75 5.75 0 1 1 0 11.5 5.75 5.75 0 0 1 0-11.5zm0 1.3a4.45 4.45 0 1 0 0 8.9 4.45 4.45 0 0 0 0-8.9z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.05 11.05a.65.65 0 0 1 .92 0l2.98 2.98a.65.65 0 1 1-.92.92l-2.98-2.98a.65.65 0 0 1 0-.92z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<svg
|
||||
@click="linkEmail(item, v.art_aut_id)"
|
||||
t="1763011629734"
|
||||
class="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="11794"
|
||||
width="24"
|
||||
height="16"
|
||||
style="margin-top: 1.5px; margin-left: 4px; cursor: pointer"
|
||||
>
|
||||
<path
|
||||
d="M780.8 0c134.3168 0 243.2 108.8832 243.2 243.2v537.6c0 134.3168-108.8832 243.2-243.2 243.2H243.2c-134.3168 0-243.2-108.8832-243.2-243.2V243.2C0 108.8832 108.8832 0 243.2 0h537.6z m5.3568 604.4864c-7.9936-6.496-13.4912-8.4928-16.4864-5.9904-3.0016 2.496-4.4992 8.2432-4.4992 17.2352v32.9792c0 8.9984-2.1248 15.2448-6.368 18.7392-4.2496 3.5008-11.3728 5.248-21.3632 5.248h-34.432a455.7504 455.7504 0 0 1-17.664-0.3776 357.76 357.76 0 0 0-15.36-0.3712h-14.9952c-11.4944 0-19.488 1.4976-23.9872 4.4992-4.4928 2.9952-6.7456 11.488-6.7456 25.4848v38.2208c0 8 3.3728 14.496 10.1184 19.488 6.7456 4.9984 13.6192 7.5008 20.6144 7.5008h86.944c7.0016 0 12.6208 2.7456 16.8704 8.2432 4.2432 5.4976 6.368 12.4928 6.368 20.992v33.728c0 13.4848 2.1248 19.9808 6.3744 19.4816 4.2432-0.4992 11.616-4.992 22.1056-13.4912a919.7312 919.7312 0 0 0 28.1088-22.4832c10.24-8.4992 20.736-16.992 31.488-25.4848a1926.9952 1926.9952 0 0 0 31.104-25.1136c9.9904-8.2432 18.7328-15.36 26.2272-21.3568 5.504-4 8.128-10.496 7.872-19.488-0.2496-8.9984-3.6224-15.9936-10.112-20.992a1228.544 1228.544 0 0 1-28.864-22.8608 1902.9184 1902.9184 0 0 0-32.9792-26.2336 2137.6256 2137.6256 0 0 1-32.6016-25.856 968.064 968.064 0 0 0-27.7376-21.7408zM180.5248 389.376c-7.488-5.4976-13.7344-6.8672-18.7328-4.1216-4.992 2.752-7.4944 9.3696-7.4944 19.8656v277.3248c0 10.496 1.248 20.6144 3.744 30.3616a62.72 62.72 0 0 0 13.4976 25.856c6.496 7.4944 15.488 13.6192 26.9824 18.368 11.488 4.7424 26.2336 7.1168 44.224 7.1168h56.16c22.464 0.0192 48.2112 0.1408 77.2544 0.3776 30.976 0.2496 64.2112 0.3712 99.6864 0.3712h103.4368a42.112 42.112 0 0 1-0.7488-8.2432v-61.4656c0-7.9936 0.6272-16.3648 1.8752-25.1072 1.248-8.7424 3.7504-16.6144 7.4944-23.6096a48.5568 48.5568 0 0 1 15.3664-17.2416c6.496-4.4928 14.9888-6.7456 25.4848-6.7456h87.6992c0-1.4976 0.2496-3.4944 0.7488-5.9968 0-2.496 0.128-5.4976 0.3712-8.992 0.256-3.5008 0.3776-8 0.3776-13.4912 0-8 1.376-16.992 4.1216-26.9824 2.752-9.9968 6.7456-18.7392 11.9936-26.24 5.248-7.488 11.9936-12.3648 20.2368-14.6112 8.2432-2.2464 17.8624 0.3712 28.8576 7.872 10.9952 6.9952 23.104 15.488 36.352 25.4848a1266.0096 1266.0096 0 0 1 40.8512 32.2304V396.864c0-7.0016-2.624-11.1232-7.872-12.3712-5.248-1.248-12.6144 1.1264-22.112 7.1232-2.9952 1.9968-8 5.248-14.9888 9.7408a5917.1648 5917.1648 0 0 1-22.8608 14.6176c-8.2432 5.248-16.992 10.8672-26.24 16.864a12420.544 12420.544 0 0 1-25.4784 16.4928c-7.744 4.992-14.24 9.2416-19.488 12.736-5.248 3.5008-8.3712 5.504-9.3696 5.9968l-94.4448 58.464c-3.4944 2.0032-8.8704 5.248-16.1152 9.7472a2571.0336 2571.0336 0 0 1-23.232 14.24c-8.2496 4.992-15.872 9.6192-22.8608 13.8688a3873.9264 3873.9264 0 0 1-14.24 8.6208c-2.496 1.4976-6.2464 3.1232-11.2448 4.864-4.9984 1.7536-10.624 2.88-16.864 3.3792-6.2464 0.4992-12.7424 0.2496-19.488-0.7488a46.4064 46.4064 0 0 1-19.1168-7.4944l-20.2368-13.4912A3314.24 3314.24 0 0 0 432 544.896a2994.4 2994.4 0 0 1-19.8592-13.12 260.5568 260.5568 0 0 0-14.2464-8.992c-5.4912-3.0016-11.8656-3.6224-19.1104-1.8752-7.2448 1.7472-13.12 4.6208-17.6128 8.6208-2.496 1.4976-7.1232 5.8688-13.8688 13.12a2662.8928 2662.8928 0 0 0-21.3632 23.232 654.7392 654.7392 0 0 1-21.3568 22.4832c-6.7456 6.752-10.8736 10.624-12.3712 11.6224-7.4944 4.4928-12.992 5.4976-16.4864 2.9952-3.5008-2.496-4-7.2448-1.504-14.24 1.504-4 4.3776-9.7408 8.6208-17.2416 4.2496-7.488 8.6208-15.36 13.12-23.6096a770.4192 770.4192 0 0 0 12.736-24.3584c4-8 7.0016-14.4896 8.9984-19.488 2.496-4.992 3.2512-10.8672 2.2464-17.6128-0.9984-6.7456-4.992-12.3712-11.9872-16.864-2.0032-0.9984-6.1248-3.5008-12.3712-7.4944a3333.7728 3333.7728 0 0 0-22.4832-14.2464 3710.0032 3710.0032 0 0 1-27.7376-17.6128 1545.984 1545.984 0 0 0-28.1024-17.6128 915.1872 915.1872 0 0 1-23.2384-14.6176 494.88 494.88 0 0 0-13.4912-8.6208z m17.9968-139.4112c-15.9936 0-27.232 3.744-33.728 11.2448-6.5024 7.488-9.7472 17.7344-9.7472 30.7264v6.7456c0 4.4992 0.7488 8 2.2464 10.496 1.504 2.496 4.9984 5.7472 10.496 9.7408l306.56 183.6416c7.4944 4.4928 14.24 8.1216 20.2368 10.8672 5.9968 2.752 10.496 4.1216 13.4912 4.1216 2.496-0.4992 7.3728-2.496 14.6176-5.9968a299.5712 299.5712 0 0 1 18.368-8.2432l306.56-184.384c6.9952-5.504 10.9888-9.12 11.9936-10.8736 0.9984-1.7472 1.4976-4.8704 1.4976-9.3696l-0.7488-8.2432c0-12.4928-3.2512-22.2336-9.7472-29.2288-6.496-7.0016-17.984-10.496-34.4768-10.496z"
|
||||
fill="#409eff"
|
||||
p-id="11795"
|
||||
data-spm-anchor-id="a313x.search_index.0.i17.7fe43a81QbZr1X"
|
||||
class="selected"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div style="max-width: 260px; width: auto" v-if="v.user_id">
|
||||
@@ -2758,6 +2757,16 @@ export default {
|
||||
query: data
|
||||
});
|
||||
},
|
||||
openAuthorSearch(author) {
|
||||
const artAutId = author && author.art_aut_id != null && author.art_aut_id !== '' ? author.art_aut_id : '';
|
||||
if (!artAutId) {
|
||||
return;
|
||||
}
|
||||
window.open(
|
||||
'https://submission.tmrjournals.com/api/author/index?artAutId=' + encodeURIComponent(artAutId),
|
||||
'_blank'
|
||||
);
|
||||
},
|
||||
//超出传送文件个数限制
|
||||
alertlimit() {
|
||||
this.$message.error('The maximum number of uploaded files has been exceeded');
|
||||
@@ -3382,6 +3391,58 @@ td {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.author-name {
|
||||
max-width: calc(100% - 100px);
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #303133;
|
||||
}
|
||||
.author-action-icons {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.author-action-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
|
||||
transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
.author-action-svg {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
display: block;
|
||||
}
|
||||
.author-action-btn--mail {
|
||||
background: linear-gradient(180deg, #66b1ff 0%, #409eff 100%);
|
||||
box-shadow: 0 1px 4px rgba(64, 158, 255, 0.32);
|
||||
}
|
||||
.author-action-btn--mail:hover {
|
||||
background: linear-gradient(180deg, #79bbff 0%, #53a8ff 100%);
|
||||
box-shadow: 0 3px 8px rgba(64, 158, 255, 0.38);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.author-action-btn--search {
|
||||
background: linear-gradient(180deg, #0088bf 0%, #006699 100%);
|
||||
box-shadow: 0 1px 4px rgba(0, 102, 153, 0.32);
|
||||
}
|
||||
.author-action-btn--search:hover {
|
||||
background: linear-gradient(180deg, #0099cc 0%, #007bb8 100%);
|
||||
box-shadow: 0 3px 8px rgba(0, 102, 153, 0.38);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.author-information {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="$t('articleDetailEditor.reReviewNotifyTitle')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="920px"
|
||||
top="5vh"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
@open="handleOpen"
|
||||
@closed="handleClosed"
|
||||
>
|
||||
<div v-loading="loading" class="re-review-mail-dialog">
|
||||
<div class="mail_shuru">
|
||||
<span class="mail_tit">{{ $t('mailboxSend.to') }}</span>
|
||||
<el-tag v-if="toEmail" type="info" size="small">{{ toEmail }}</el-tag>
|
||||
<span v-else class="mail-empty-tip">-</span>
|
||||
</div>
|
||||
<div class="mail_shuru">
|
||||
<span class="mail_tit">{{ $t('mailboxSend.subject') }}</span>
|
||||
<el-input v-model="mailForm.subject" class="mail_inp" />
|
||||
</div>
|
||||
<div class="mail-editor-wrap">
|
||||
<ckeditor-mail
|
||||
v-if="editorMounted"
|
||||
ref="mailEditor"
|
||||
:key="editorId"
|
||||
:id="editorId"
|
||||
v-model="mailForm.content"
|
||||
:use-safe-init-content="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="mail-footer-bar">
|
||||
<div class="sender-info">
|
||||
<span class="sender-label">{{ $t('mailboxSend.sender') }}</span>
|
||||
<span class="sender-content">
|
||||
<template v-if="senderName && senderEmail">{{ senderName }} <{{ senderEmail }}></template>
|
||||
<template v-else>-</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<el-button @click="dialogVisible = false">{{ $t('mailboxSend.cancel') || 'Cancel' }}</el-button>
|
||||
<el-button type="primary" icon="el-icon-s-promotion" :loading="sendLoading" @click="handleSend">
|
||||
{{ $t('mailboxSend.send') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CkeditorMail from '@/components/page/components/email/CkeditorMail.vue';
|
||||
import { applyReviewNotifyTemplateVariables } from '@/utils/mailTemplatePreview';
|
||||
|
||||
const RE_REVIEW_TEMPLATE_ID = '82';
|
||||
/** 复审通知固定发件邮箱 j_email_id */
|
||||
const RE_REVIEW_SENDER_J_EMAIL_ID = '23';
|
||||
|
||||
export default {
|
||||
name: 'ReReviewNotifyMailDialog',
|
||||
components: {
|
||||
CkeditorMail
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
reviewer: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
articleId: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
articleTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 稿件 SN,对应接口字段 accept_sn */
|
||||
acceptSn: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
journalId: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
/** 期刊名称,对应 getArticleDetail 返回字段 journal_name */
|
||||
journalName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 期刊官网,对应 getArticleDetail 返回字段 */
|
||||
journalUrl: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
sendLoading: false,
|
||||
editorMounted: false,
|
||||
editorId: 're-review-mail-' + Date.now(),
|
||||
mailForm: {
|
||||
subject: '',
|
||||
content: ''
|
||||
},
|
||||
toEmail: '',
|
||||
senderName: '',
|
||||
senderEmail: '',
|
||||
jEmailId: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible;
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleOpen() {
|
||||
this.editorMounted = false;
|
||||
this.editorId = 're-review-mail-' + Date.now();
|
||||
this.resetForm();
|
||||
this.loadMailData();
|
||||
},
|
||||
handleClosed() {
|
||||
this.editorMounted = false;
|
||||
this.resetForm();
|
||||
},
|
||||
resetForm() {
|
||||
this.mailForm = { subject: '', content: '' };
|
||||
this.toEmail = '';
|
||||
this.senderName = '';
|
||||
this.senderEmail = '';
|
||||
this.jEmailId = '';
|
||||
},
|
||||
async loadMailData() {
|
||||
this.loading = true;
|
||||
this.editorMounted = false;
|
||||
try {
|
||||
await Promise.all([this.loadReviewerEmail(), this.loadSenderAccount()]);
|
||||
await this.loadTemplate();
|
||||
await this.$nextTick();
|
||||
this.editorMounted = true;
|
||||
} catch (e) {
|
||||
console.error('loadMailData failed', e);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async loadReviewerEmail() {
|
||||
const reviewer = this.reviewer || {};
|
||||
if (reviewer.email) {
|
||||
this.toEmail = reviewer.email;
|
||||
return;
|
||||
}
|
||||
if (!reviewer.art_rev_id || !this.articleId) return;
|
||||
const res = await this.$api.post('api/Workbench/getArticleReviewDetail', {
|
||||
article_id: this.articleId,
|
||||
art_rev_id: reviewer.art_rev_id,
|
||||
account: localStorage.getItem('U_name')
|
||||
});
|
||||
if (res && res.status === 1 && res.data && res.data.article_reviewer) {
|
||||
this.toEmail = res.data.article_reviewer.email || '';
|
||||
}
|
||||
},
|
||||
async loadSenderAccount() {
|
||||
this.jEmailId = RE_REVIEW_SENDER_J_EMAIL_ID;
|
||||
const emailRes = await this.$api.post('api/email_client/getOneEmail', {
|
||||
j_email_id: this.jEmailId
|
||||
});
|
||||
if (emailRes && emailRes.code === 0 && emailRes.data && emailRes.data.email) {
|
||||
const email = emailRes.data.email;
|
||||
this.senderName = email.smtp_from_name || email.smtp_user || '';
|
||||
this.senderEmail = email.smtp_user || '';
|
||||
}
|
||||
},
|
||||
async loadTemplate() {
|
||||
const res = await this.$api.post('api/mail_template/getTemplate', {
|
||||
template_id: RE_REVIEW_TEMPLATE_ID
|
||||
});
|
||||
if (!res || res.code !== 0) {
|
||||
this.$message.error((res && res.msg) || 'Failed to load mail template');
|
||||
return;
|
||||
}
|
||||
const data = (res && res.data) || {};
|
||||
const t = data.template || data.detail || data || {};
|
||||
const vars = {
|
||||
title: this.articleTitle,
|
||||
accept_sn: this.acceptSn,
|
||||
journal_name: this.journalName,
|
||||
journal_url: this.journalUrl
|
||||
};
|
||||
const subjectRaw = t.subject != null ? String(t.subject) : '';
|
||||
const bodyRaw = t.body_html != null ? t.body_html : t.body != null ? t.body : '';
|
||||
this.mailForm.subject = applyReviewNotifyTemplateVariables(subjectRaw, vars);
|
||||
this.mailForm.content = applyReviewNotifyTemplateVariables(String(bodyRaw || ''), vars);
|
||||
},
|
||||
async handleSend() {
|
||||
if (!this.toEmail) {
|
||||
this.$message.warning(this.$t('mailboxSend.validateTo'));
|
||||
return;
|
||||
}
|
||||
if (!this.mailForm.subject) {
|
||||
this.$message.warning(this.$t('mailboxSend.validateSubject'));
|
||||
return;
|
||||
}
|
||||
if (!this.jEmailId) {
|
||||
this.$message.warning(this.$t('mailboxSend.needAccount'));
|
||||
return;
|
||||
}
|
||||
if (!this.journalId) {
|
||||
this.$message.warning(this.$t('mailboxSend.needAccount'));
|
||||
return;
|
||||
}
|
||||
this.sendLoading = true;
|
||||
try {
|
||||
let content = this.mailForm.content || '';
|
||||
const editorRef = this.$refs.mailEditor;
|
||||
if (editorRef && typeof editorRef.getInlinedContent === 'function') {
|
||||
content = editorRef.getInlinedContent() || content;
|
||||
}
|
||||
const res = await this.$api.post('api/email_client/sendOne', {
|
||||
to_email: this.toEmail,
|
||||
subject: this.mailForm.subject,
|
||||
content,
|
||||
j_email_id: this.jEmailId,
|
||||
journal_id: String(this.journalId)
|
||||
});
|
||||
if (res && res.code === 0) {
|
||||
this.$message.success(this.$t('mailboxSend.sendSuccess'));
|
||||
this.dialogVisible = false;
|
||||
this.$emit('sent');
|
||||
} else {
|
||||
this.$message.error((res && res.msg) || this.$t('mailboxSend.sendFail'));
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error(this.$t('mailboxSend.sendFail'));
|
||||
} finally {
|
||||
this.sendLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.re-review-mail-dialog {
|
||||
min-height: 420px;
|
||||
}
|
||||
.mail_shuru {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 40px;
|
||||
line-height: 40px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.mail_tit {
|
||||
width: 72px;
|
||||
flex-shrink: 0;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
.mail_inp {
|
||||
flex: 1;
|
||||
}
|
||||
.mail_inp ::v-deep .el-input__inner {
|
||||
border: none;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
border-radius: 0;
|
||||
}
|
||||
.mail-editor-wrap {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.mail-footer-bar {
|
||||
margin-top: 16px;
|
||||
padding: 10px 15px;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.sender-info {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
.sender-label {
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.sender-content {
|
||||
color: #006699;
|
||||
}
|
||||
.mail-empty-tip {
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
@@ -44,15 +44,25 @@
|
||||
<el-option :label="$t('autoPromotionLogs.taskLogState3')" value="3"></el-option>
|
||||
<el-option :label="$t('autoPromotionLogs.taskLogState4')" value="4"></el-option>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-model="logKeyword"
|
||||
size="mini"
|
||||
clearable
|
||||
:placeholder="$t('autoPromotionLogs.searchPlaceholder')"
|
||||
prefix-icon="el-icon-search"
|
||||
class="log-keyword-input"
|
||||
@keyup.enter.native="handleLogKeywordSearch"
|
||||
@clear="handleLogKeywordSearch"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
icon="el-icon-refresh"
|
||||
icon="el-icon-search"
|
||||
:loading="loading"
|
||||
class="log-refresh-btn"
|
||||
@click="handleRefreshLogs"
|
||||
class="log-search-btn"
|
||||
@click="handleLogKeywordSearch"
|
||||
>
|
||||
{{ $t('autoPromotionLogs.logRefresh') }}
|
||||
{{ $t('autoPromotionLogs.searchBtn') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -69,7 +79,7 @@
|
||||
|
||||
<div class="list-wrapper">
|
||||
<div
|
||||
v-for="(item, rowIndex) in fullData"
|
||||
v-for="(item, rowIndex) in displayLogData"
|
||||
:key="item.id"
|
||||
class="log-row"
|
||||
:class="{ 'row-error': item.isErrorRow }"
|
||||
@@ -137,7 +147,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && fullData.length === 0" class="empty-ui">
|
||||
<div v-if="!loading && displayLogData.length === 0" class="empty-ui">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>{{ $t('autoPromotionLogs.emptyLogs') }}</p>
|
||||
</div>
|
||||
@@ -147,7 +157,7 @@
|
||||
<el-pagination
|
||||
:current-page.sync="currentPage"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:page-sizes="[20, 50, 100, 500]"
|
||||
:total="totalCount"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handlePageSizeChange"
|
||||
@@ -306,10 +316,11 @@ export default {
|
||||
return {
|
||||
loading: false,
|
||||
logState: '',
|
||||
logKeyword: '',
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
totalCount: 0,
|
||||
fullData: [],
|
||||
displayLogData: [],
|
||||
logDetailVisible: false,
|
||||
logDetailLoading: false,
|
||||
logDetailMode: 'preview',
|
||||
@@ -376,6 +387,7 @@ export default {
|
||||
if (oldVal === '' || oldVal == null) return;
|
||||
this.currentPage = 1;
|
||||
this.logState = '';
|
||||
this.logKeyword = '';
|
||||
this.loadData();
|
||||
}
|
||||
},
|
||||
@@ -383,13 +395,15 @@ export default {
|
||||
handleOpen() {
|
||||
this.currentPage = 1;
|
||||
this.logState = '';
|
||||
this.logKeyword = '';
|
||||
this.loadData();
|
||||
},
|
||||
handleLogStateChange() {
|
||||
this.currentPage = 1;
|
||||
this.loadData();
|
||||
},
|
||||
handleRefreshLogs() {
|
||||
handleLogKeywordSearch() {
|
||||
this.currentPage = 1;
|
||||
this.loadData();
|
||||
},
|
||||
handlePageSizeChange(size) {
|
||||
@@ -399,7 +413,7 @@ export default {
|
||||
},
|
||||
async loadData() {
|
||||
if (!this.taskId) {
|
||||
this.fullData = [];
|
||||
this.displayLogData = [];
|
||||
this.totalCount = 0;
|
||||
return;
|
||||
}
|
||||
@@ -413,10 +427,14 @@ export default {
|
||||
if (this.logState !== '' && this.logState != null) {
|
||||
params.state = String(this.logState);
|
||||
}
|
||||
const keyword = String(this.logKeyword || '').trim();
|
||||
if (keyword) {
|
||||
params.keyword = keyword;
|
||||
}
|
||||
const res = await this.$api.post(API_GET_TASK_LOGS, params);
|
||||
if (res && res.code != null && Number(res.code) !== 0) {
|
||||
this.$message.error(res.msg || this.$t('autoPromotionLogs.logLoadFailed'));
|
||||
this.fullData = [];
|
||||
this.displayLogData = [];
|
||||
this.totalCount = 0;
|
||||
return;
|
||||
}
|
||||
@@ -431,9 +449,9 @@ export default {
|
||||
this.totalCount = Number(
|
||||
(payload && (payload.total != null ? payload.total : payload.count)) || rawList.length || 0
|
||||
);
|
||||
this.fullData = rawList.map((row, idx) => this.mapLogItem(row, idx));
|
||||
this.displayLogData = rawList.map((row, idx) => this.mapLogItem(row, idx));
|
||||
} catch (e) {
|
||||
this.fullData = [];
|
||||
this.displayLogData = [];
|
||||
this.totalCount = 0;
|
||||
this.$message.error((e && e.message) || this.$t('autoPromotionLogs.logLoadFailed'));
|
||||
} finally {
|
||||
@@ -771,7 +789,11 @@ export default {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.log-refresh-btn {
|
||||
.log-keyword-input {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.log-search-btn {
|
||||
padding: 7px 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
|
||||
<el-tab-pane :label="$t('mailTemplate.styleTab')" name="style">
|
||||
<div class="card-grid">
|
||||
<div
|
||||
v-if="styleOptional"
|
||||
:class="['card-item', 'card-item-none', { active: !selectedHeaderId }]"
|
||||
@click="selectedHeaderId = null"
|
||||
>
|
||||
<p class="card-title">{{ $t('mailTemplate.noStyle') }}</p>
|
||||
<p class="card-desc">{{ $t('mailTemplate.noStyleDesc') }}</p>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in headerStyles"
|
||||
:key="item.id"
|
||||
@@ -111,6 +119,8 @@ export default {
|
||||
// 可选:打开时回显的风格/模板
|
||||
initialStyleId: { type: [String, Number], default: '' },
|
||||
initialTemplateId: { type: [String, Number], default: '' },
|
||||
// 为 true 时仅选模板即可应用,Style 可选(可不选)
|
||||
styleOptional: { type: Boolean, default: false },
|
||||
// 可选:来源页面标识,用于回跳时决定 mailboxMouldDetail 返回到哪里
|
||||
// 例如:'autoPromotion':返回自动化推广;默认返回邮件模版列表
|
||||
returnSource: { type: String, default: '' }
|
||||
@@ -163,24 +173,36 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
applyDisabled() {
|
||||
return this.initLoading || this.contentLoading || !this.selectedHeaderId || !this.selectedContentId;
|
||||
if (this.initLoading || this.contentLoading) return true;
|
||||
if (!this.selectedContentId) return true;
|
||||
if (!this.styleOptional && !this.selectedHeaderId) return true;
|
||||
return false;
|
||||
},
|
||||
hasValidPreview() {
|
||||
const header = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
const content = this.contentTemplates.find((c) => c.id === this.selectedContentId);
|
||||
if (!content) return false;
|
||||
if (this.styleOptional && !this.selectedHeaderId) return true;
|
||||
const header = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
return !!(header && content);
|
||||
},
|
||||
// 【关键】拼接 HTML
|
||||
combinedHtml() {
|
||||
if (this.initLoading) return '';
|
||||
if (!this.hasValidPreview) return '';
|
||||
const header = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
const content = this.contentTemplates.find((c) => c.id === this.selectedContentId);
|
||||
if (!content) return '';
|
||||
if (this.styleOptional && !this.selectedHeaderId) {
|
||||
return content.bodyHtml || '';
|
||||
}
|
||||
const header = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
return `${header.htmlHeader}${content.bodyHtml}${header.htmlFooter}`;
|
||||
},
|
||||
currentSelectionText() {
|
||||
const h = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
const c = this.contentTemplates.find((c) => c.id === this.selectedContentId);
|
||||
if (this.styleOptional && !this.selectedHeaderId) {
|
||||
return c ? c.name : '';
|
||||
}
|
||||
return `${c ? c.name : ''} + ${h ? h.name : ''}`;
|
||||
},
|
||||
currentJournalLabel() {
|
||||
@@ -306,8 +328,8 @@ export default {
|
||||
htmlFooter: item.footer_html || ''
|
||||
}));
|
||||
|
||||
// 默认选中第一条
|
||||
if (this.headerStyles.length && !this.selectedHeaderId) {
|
||||
// 默认选中第一条(Style 可选时不自动选中)
|
||||
if (this.headerStyles.length && !this.selectedHeaderId && !this.styleOptional) {
|
||||
this.selectedHeaderId = this.headerStyles[0].id;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -382,13 +404,14 @@ export default {
|
||||
},
|
||||
submit() {
|
||||
if (this.applyDisabled) return;
|
||||
// 将拼接好的 HTML 及选择信息抛给父组件(兼容:父组件也可只用 html)
|
||||
const header = this.headerStyles.find((h) => h.id === this.selectedHeaderId);
|
||||
const header = this.selectedHeaderId
|
||||
? this.headerStyles.find((h) => h.id === this.selectedHeaderId)
|
||||
: null;
|
||||
const content = this.contentTemplates.find((c) => c.id === this.selectedContentId);
|
||||
this.$emit('confirm', {
|
||||
html: this.combinedHtml,
|
||||
journal_id: this.selectedJournalId,
|
||||
style_id: this.selectedHeaderId,
|
||||
style_id: this.selectedHeaderId || '',
|
||||
template_id: this.selectedContentId,
|
||||
style: header || null,
|
||||
template: content || null
|
||||
@@ -494,6 +517,12 @@ export default {
|
||||
background: #f5f7ff;
|
||||
outline: 1px solid #6366f1;
|
||||
}
|
||||
.card-item-none {
|
||||
min-height: 56px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.card-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
||||
@@ -229,6 +229,16 @@ import {
|
||||
created() {
|
||||
this.loadJournals();
|
||||
this.initAccountSelection();
|
||||
this._skipNextActivatedSync = true;
|
||||
},
|
||||
activated() {
|
||||
if (this._skipNextActivatedSync) {
|
||||
this._skipNextActivatedSync = false;
|
||||
return;
|
||||
}
|
||||
if (this.selectedAccount) {
|
||||
this.autoSyncInbox();
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.stopInboxSse(true);
|
||||
@@ -311,7 +321,7 @@ import {
|
||||
: null;
|
||||
if (res && Number(res.code) === 0 && email) {
|
||||
this.selectedAccount = email;
|
||||
this.fetchData();
|
||||
this.autoSyncInbox();
|
||||
this.startInboxSse();
|
||||
return;
|
||||
}
|
||||
@@ -381,8 +391,8 @@ import {
|
||||
localStorage.setItem('mailboxCollect_journal_id', String(row.journal_id));
|
||||
}
|
||||
|
||||
// 不再写入路由 query,直接拉取数据
|
||||
this.fetchData();
|
||||
// 切换账号后自动收信并刷新列表
|
||||
this.autoSyncInbox();
|
||||
this.startInboxSse();
|
||||
},
|
||||
handleAccountDialogBeforeClose(done) {
|
||||
@@ -651,29 +661,52 @@ fetchLatestSingleMail(jEmailId, journalId) {
|
||||
.catch(() => {});
|
||||
});
|
||||
},
|
||||
// 同步收件箱:api/email_client/syncInbox 参数 j_email_id、journal_id(均为 String),完成后重新拉取 displayList
|
||||
autoSyncInbox() {
|
||||
return this.syncInboxAndRefresh({ showMessage: false, fetchOnFail: true });
|
||||
},
|
||||
handleSyncInbox() {
|
||||
if (!this.selectedAccount) return;
|
||||
this.syncInboxAndRefresh({ showMessage: true, fetchOnFail: false });
|
||||
},
|
||||
syncInboxAndRefresh(options = {}) {
|
||||
const showMessage = options.showMessage !== false;
|
||||
const fetchOnFail = options.fetchOnFail === true;
|
||||
if (!this.selectedAccount) return Promise.resolve(false);
|
||||
if (this.syncLoading) return Promise.resolve(false);
|
||||
this.syncLoading = true;
|
||||
const params = {
|
||||
j_email_id: String(this.selectedAccount.j_email_id),
|
||||
journal_id: String(this.selectedAccount.journal_id)
|
||||
};
|
||||
this.$api
|
||||
return this.$api
|
||||
.post(API.syncInbox, params)
|
||||
.then((res) => {
|
||||
this.syncLoading = false;
|
||||
if (res && res.code === 0) {
|
||||
this.newMailsBuffer=[]
|
||||
this.$message.success(this.$t('mailboxCollect.syncSuccess'));
|
||||
this.newMailsBuffer = [];
|
||||
if (showMessage) {
|
||||
this.$message.success(this.$t('mailboxCollect.syncSuccess'));
|
||||
}
|
||||
this.fetchData();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
if (showMessage) {
|
||||
this.$message.error((res && res.msg) || this.$t('mailboxCollect.syncFail'));
|
||||
}
|
||||
if (fetchOnFail) {
|
||||
this.fetchData();
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch(() => {
|
||||
if (showMessage) {
|
||||
this.$message.error(this.$t('mailboxCollect.syncFail'));
|
||||
}
|
||||
if (fetchOnFail) {
|
||||
this.fetchData();
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.finally(() => {
|
||||
this.syncLoading = false;
|
||||
this.$message.error(this.$t('mailboxCollect.syncFail'));
|
||||
});
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
:source-content.sync="sourceContent"
|
||||
:source-rows="16"
|
||||
:source-placeholder="$t('mailboxSend.sourcePlaceholder')"
|
||||
:show-select-template-button="false"
|
||||
:show-select-template-button="true"
|
||||
@onSelectTemplate="showTemplateDialog = true"
|
||||
/>
|
||||
</div>
|
||||
@@ -139,6 +139,41 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 批量发送进度 -->
|
||||
<el-dialog
|
||||
:title="$t('mailboxSend.sendProgressTitle')"
|
||||
:visible.sync="sendProgressVisible"
|
||||
width="520px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="sendProgressDone"
|
||||
>
|
||||
<div class="send-progress-summary">{{ sendProgressSummaryText }}</div>
|
||||
<ul class="send-progress-list">
|
||||
<li
|
||||
v-for="(item, index) in sendProgressList"
|
||||
:key="item.email + '-' + index"
|
||||
class="send-progress-item"
|
||||
:class="'send-progress-item--' + item.status"
|
||||
>
|
||||
<span class="send-progress-icon">
|
||||
<i v-if="item.status === 'pending'" class="el-icon-more-outline"></i>
|
||||
<i v-else-if="item.status === 'sending'" class="el-icon-loading"></i>
|
||||
<i v-else-if="item.status === 'success'" class="el-icon-circle-check"></i>
|
||||
<i v-else-if="item.status === 'fail'" class="el-icon-circle-close"></i>
|
||||
</span>
|
||||
<div class="send-progress-body">
|
||||
<span class="send-progress-email">{{ item.email }}</span>
|
||||
<span v-if="item.msg" class="send-progress-msg">{{ item.msg }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<span slot="footer" v-if="sendProgressDone">
|
||||
<el-button type="primary" @click="handleSendProgressClose">{{ $t('mailboxSend.sendBatchConfirm') }}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 选择通讯录 -->
|
||||
<el-dialog :title="$t('mailboxSend.selectUser')" :visible.sync="Librarybox" width="900px" :close-on-click-modal="false">
|
||||
<el-button type="primary" style="margin: 0 0 15px 0;" icon="el-icon-plus" @click="mailLiyAll()" v-if="LibrarySelection!=''">
|
||||
@@ -168,11 +203,15 @@
|
||||
</el-dialog>
|
||||
|
||||
<template-selector-dialog
|
||||
v-if="showTemplateDialog"
|
||||
:visible.sync="showTemplateDialog"
|
||||
@confirm="handleTemplateApply"
|
||||
@close-all-dialogs="closeAllDialogs"
|
||||
/>
|
||||
v-if="showTemplateDialog"
|
||||
:visible.sync="showTemplateDialog"
|
||||
:journal-id="mailJournalId"
|
||||
:initial-style-id="selectedStyleId"
|
||||
:initial-template-id="selectedTemplateId"
|
||||
:style-optional="true"
|
||||
@confirm="handleTemplateApply"
|
||||
@close-all-dialogs="closeAllDialogs"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -221,8 +260,7 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
sourceContent: '',
|
||||
|
||||
toInput: '',
|
||||
// 默认只允许 1 个收件人,后续可按需动态修改
|
||||
maxToRecipients: 1,
|
||||
maxToRecipients: 0,
|
||||
toSelecting: false,
|
||||
nextToUid: 1,
|
||||
ccList: [],
|
||||
@@ -245,7 +283,11 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
cb: null
|
||||
},
|
||||
recipientSuggestScrollHandler: null,
|
||||
showSendEmail:true
|
||||
showSendEmail:true,
|
||||
sendProgressVisible: false,
|
||||
sendProgressDone: false,
|
||||
sendProgressList: [],
|
||||
sendProgressSuccessList: []
|
||||
};
|
||||
},
|
||||
components: {
|
||||
@@ -256,6 +298,26 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
footerBarLeft() {
|
||||
const collapsed = this.collapseValue === true || this.collapseValue === 'true';
|
||||
return (collapsed ? 64: 260) + 'px';
|
||||
},
|
||||
mailJournalId() {
|
||||
const stored = localStorage.getItem('mailboxCollect_journal_id');
|
||||
const fromRoute = this.$route.query.journal_id;
|
||||
return stored || fromRoute || '';
|
||||
},
|
||||
sendProgressSummaryText() {
|
||||
const list = this.sendProgressList || [];
|
||||
const total = list.length;
|
||||
if (!total) return '';
|
||||
if (!this.sendProgressDone) {
|
||||
const done = list.filter((item) => item.status === 'success' || item.status === 'fail').length;
|
||||
return this.$t('mailboxSend.sendProgressRunning', { done, total });
|
||||
}
|
||||
const ok = list.filter((item) => item.status === 'success').length;
|
||||
const fail = list.filter((item) => item.status === 'fail').length;
|
||||
if (!fail) {
|
||||
return this.$t('mailboxSend.sendProgressAllSuccess', { count: ok });
|
||||
}
|
||||
return this.$t('mailboxSend.sendProgressDone', { ok, fail });
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -424,8 +486,11 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
this.queryMail.content = html;
|
||||
this.sourceContent = html;
|
||||
|
||||
// 优先回填 TinyMCE 实例
|
||||
if (window.tinymce && window.tinymce.activeEditor && window.tinymce.activeEditor.setContent) {
|
||||
// 优先回填编辑器实例
|
||||
const editorRef = this.$refs.myTextEditor;
|
||||
if (editorRef && editorRef.editor && typeof editorRef.editor.setContent === 'function') {
|
||||
editorRef.editor.setContent(html);
|
||||
} else if (window.tinymce && window.tinymce.activeEditor && window.tinymce.activeEditor.setContent) {
|
||||
window.tinymce.activeEditor.setContent(html);
|
||||
}
|
||||
this.selectedTemplateId = templateId ? String(templateId) : '';
|
||||
@@ -654,7 +719,97 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
});
|
||||
},
|
||||
|
||||
// 发送邮件:api/email_client/sendTemplateStyleText
|
||||
getSendContent() {
|
||||
if (this.isSourceMode) {
|
||||
return this.sourceContent || this.queryMail.content || '';
|
||||
}
|
||||
const editorRef = this.$refs.myTextEditor;
|
||||
if (editorRef && typeof editorRef.getInlinedContent === 'function') {
|
||||
return editorRef.getInlinedContent() || this.queryMail.content || '';
|
||||
}
|
||||
return this.queryMail.content || '';
|
||||
},
|
||||
initSendProgress(toList) {
|
||||
this.sendProgressList = (toList || []).map((email) => ({
|
||||
email,
|
||||
status: 'pending',
|
||||
msg: ''
|
||||
}));
|
||||
this.sendProgressDone = false;
|
||||
this.sendProgressSuccessList = [];
|
||||
this.sendProgressVisible = true;
|
||||
},
|
||||
setSendProgressItemStatus(index, status, msg) {
|
||||
const item = this.sendProgressList[index];
|
||||
if (!item) return;
|
||||
this.$set(this.sendProgressList, index, {
|
||||
...item,
|
||||
status,
|
||||
msg: msg || ''
|
||||
});
|
||||
},
|
||||
closeSendProgressDialog() {
|
||||
this.sendProgressVisible = false;
|
||||
this.sendProgressDone = false;
|
||||
this.sendProgressList = [];
|
||||
this.sendProgressSuccessList = [];
|
||||
},
|
||||
handleSendProgressClose() {
|
||||
if (this.sendProgressSuccessList.length) {
|
||||
const successSet = new Set(this.sendProgressSuccessList.map((item) => item.email));
|
||||
this.queryMail.sendnamelist = (this.queryMail.sendnamelist || []).filter(
|
||||
(item) => !successSet.has(item.name)
|
||||
);
|
||||
this.queryMail.sendname = (this.queryMail.sendnamelist || []).map((i) => i.name);
|
||||
}
|
||||
this.closeSendProgressDialog();
|
||||
},
|
||||
resetMailFormAfterSend() {
|
||||
this.queryMail.sendnamelist = [];
|
||||
this.queryMail.sendtitle = '';
|
||||
this.queryMail.sendcc = '';
|
||||
this.ccList = [];
|
||||
this.queryMail.content = '';
|
||||
this.sourceContent = '';
|
||||
this.selectedTemplateId = '';
|
||||
this.selectedStyleId = '';
|
||||
this.fileL_atta = [];
|
||||
},
|
||||
async sendMailToRecipients(toList, journalId, jEmailId, content) {
|
||||
this.initSendProgress(toList);
|
||||
const successList = [];
|
||||
const failList = [];
|
||||
for (let i = 0; i < toList.length; i++) {
|
||||
const email = toList[i];
|
||||
this.setSendProgressItemStatus(i, 'sending');
|
||||
await this.$nextTick();
|
||||
try {
|
||||
const res = await this.$api.post('api/email_client/sendOne', {
|
||||
to_email: email,
|
||||
subject: this.queryMail.sendtitle || '',
|
||||
content,
|
||||
j_email_id: String(jEmailId),
|
||||
journal_id: String(journalId)
|
||||
});
|
||||
if (res && res.code === 0) {
|
||||
successList.push({ email });
|
||||
this.setSendProgressItemStatus(i, 'success');
|
||||
} else {
|
||||
const msg = (res && res.msg) || this.$t('mailboxSend.sendFail');
|
||||
failList.push({ email, msg });
|
||||
this.setSendProgressItemStatus(i, 'fail', msg);
|
||||
}
|
||||
} catch (e) {
|
||||
const msg = this.$t('mailboxSend.sendFail');
|
||||
failList.push({ email, msg });
|
||||
this.setSendProgressItemStatus(i, 'fail', msg);
|
||||
}
|
||||
}
|
||||
this.sendProgressDone = true;
|
||||
this.sendProgressSuccessList = successList;
|
||||
return { successList, failList };
|
||||
},
|
||||
// 发送邮件:多个收件人时逐封调用 sendOne
|
||||
handleSend() {
|
||||
// 防抖:快速连点只触发最后一次
|
||||
if (this.sendLoading) return;
|
||||
@@ -664,7 +819,6 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
if (this.sendLoading) return;
|
||||
|
||||
const toList = (this.queryMail.sendnamelist || []).map((item) => item.name).filter(Boolean);
|
||||
const expert_id_list = (this.queryMail.sendnamelist || []).map((item) => item.expert_id).filter(Boolean);
|
||||
if (!toList.length) {
|
||||
this.$message.warning(this.$t('mailboxSend.validateTo'));
|
||||
return;
|
||||
@@ -674,7 +828,6 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
return;
|
||||
}
|
||||
|
||||
// journal_id 优先从本地缓存获取,兼容旧的路由参数
|
||||
const storedJournalId = localStorage.getItem('mailboxCollect_journal_id');
|
||||
const journalId = storedJournalId || this.$route.query.journal_id;
|
||||
const storedEmailId = localStorage.getItem('mailboxCollect_j_email_id');
|
||||
@@ -688,42 +841,22 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
this.$message.warning(this.$t('mailboxSend.needAccount'));
|
||||
return;
|
||||
}
|
||||
// if (!this.selectedTemplateId || !this.selectedStyleId) {
|
||||
// this.$message.warning(this.$t('mailboxSend.selectTemplateStyleFirst'));
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.sendLoading = true;
|
||||
const params = {
|
||||
to_email: toList.join(','),
|
||||
subject: this.queryMail.sendtitle || '',
|
||||
content: this.queryMail.content || '',
|
||||
j_email_id: String(jEmailId),
|
||||
journal_id: String(journalId),
|
||||
};
|
||||
|
||||
const self = this;
|
||||
this.$api
|
||||
.post('api/email_client/sendOne', params)
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
const content = this.getSendContent();
|
||||
this.sendMailToRecipients(toList, journalId, jEmailId, content)
|
||||
.then(({ successList, failList }) => {
|
||||
if (!failList.length) {
|
||||
self.$message.success(self.$t('mailboxSend.sendSuccess'));
|
||||
self.queryMail.sendnamelist = [];
|
||||
self.queryMail.sendtitle = '';
|
||||
self.queryMail.sendcc = '';
|
||||
self.ccList = [];
|
||||
self.queryMail.content = '';
|
||||
self.sourceContent = '';
|
||||
self.selectedTemplateId = '';
|
||||
self.selectedStyleId = '';
|
||||
self.fileL_atta = [];
|
||||
self.goBackInbox();
|
||||
} else {
|
||||
self.$message.error((res && res.msg) || self.$t('mailboxSend.sendFail'));
|
||||
setTimeout(() => {
|
||||
self.closeSendProgressDialog();
|
||||
self.resetMailFormAfterSend();
|
||||
self.goBackInbox();
|
||||
}, 900);
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
self.$message.error(self.$t('mailboxSend.sendFail'));
|
||||
self.sendProgressSuccessList = successList;
|
||||
})
|
||||
.finally(() => {
|
||||
self.sendLoading = false;
|
||||
@@ -1105,4 +1238,65 @@ import TemplateSelectorDialog from '@/components/page/components/email/TemplateS
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.send-progress-summary {
|
||||
margin-bottom: 14px;
|
||||
padding: 10px 12px;
|
||||
background: #f4f8ff;
|
||||
border-radius: 4px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.send-progress-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.send-progress-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
.send-progress-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.send-progress-icon {
|
||||
width: 22px;
|
||||
flex-shrink: 0;
|
||||
margin-right: 10px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
.send-progress-item--sending .send-progress-icon {
|
||||
color: #409eff;
|
||||
}
|
||||
.send-progress-item--success .send-progress-icon {
|
||||
color: #67c23a;
|
||||
}
|
||||
.send-progress-item--fail .send-progress-icon {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.send-progress-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.send-progress-email {
|
||||
display: block;
|
||||
color: #303133;
|
||||
word-break: break-all;
|
||||
line-height: 22px;
|
||||
}
|
||||
.send-progress-msg {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
color: #f56c6c;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user