@@ -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;
diff --git a/src/components/page/components/articleDetail/ReReviewNotifyMailDialog.vue b/src/components/page/components/articleDetail/ReReviewNotifyMailDialog.vue
new file mode 100644
index 0000000..322f432
--- /dev/null
+++ b/src/components/page/components/articleDetail/ReReviewNotifyMailDialog.vue
@@ -0,0 +1,307 @@
+
+
+
+
+ {{ $t('mailboxSend.to') }}
+ {{ toEmail }}
+ -
+
+
+ {{ $t('mailboxSend.subject') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/page/components/autoPromotion/PromotionDetailDrawer.vue b/src/components/page/components/autoPromotion/PromotionDetailDrawer.vue
index 0a15e8f..aa51bd4 100644
--- a/src/components/page/components/autoPromotion/PromotionDetailDrawer.vue
+++ b/src/components/page/components/autoPromotion/PromotionDetailDrawer.vue
@@ -44,15 +44,25 @@
+
- {{ $t('autoPromotionLogs.logRefresh') }}
+ {{ $t('autoPromotionLogs.searchBtn') }}
-
+
{{ $t('autoPromotionLogs.emptyLogs') }}
@@ -147,7 +157,7 @@
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;
}
diff --git a/src/components/page/components/email/TemplateSelectorDialog.vue b/src/components/page/components/email/TemplateSelectorDialog.vue
index ce65894..3e58b9d 100644
--- a/src/components/page/components/email/TemplateSelectorDialog.vue
+++ b/src/components/page/components/email/TemplateSelectorDialog.vue
@@ -40,6 +40,14 @@
+
+
{{ $t('mailTemplate.noStyle') }}
+
{{ $t('mailTemplate.noStyleDesc') }}
+
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;
diff --git a/src/components/page/mailboxCollect.vue b/src/components/page/mailboxCollect.vue
index 46ff825..467ee7c 100644
--- a/src/components/page/mailboxCollect.vue
+++ b/src/components/page/mailboxCollect.vue
@@ -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'));
});
},
/**
diff --git a/src/components/page/mailboxSend.vue b/src/components/page/mailboxSend.vue
index eeab9ca..ee4865b 100644
--- a/src/components/page/mailboxSend.vue
+++ b/src/components/page/mailboxSend.vue
@@ -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"
/>
@@ -139,6 +139,41 @@
+
+
+ {{ sendProgressSummaryText }}
+
+
+ {{ $t('mailboxSend.sendBatchConfirm') }}
+
+
+
@@ -168,11 +203,15 @@
+ 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"
+ />
@@ -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;
+}
+
diff --git a/src/utils/mailTemplatePreview.js b/src/utils/mailTemplatePreview.js
index 149f272..d61ce90 100644
--- a/src/utils/mailTemplatePreview.js
+++ b/src/utils/mailTemplatePreview.js
@@ -74,3 +74,36 @@ export function applyMailTemplateVariableMocks(html, options) {
return full;
});
}
+
+/** 复审通知邮件模板变量:标题、SN、期刊名称、期刊官网 */
+export function applyReviewNotifyTemplateVariables(html, options) {
+ const opts = options || {};
+ if (!html) return '';
+ const title = opts.title != null ? String(opts.title) : '';
+ const acceptSn =
+ opts.accept_sn != null && opts.accept_sn !== ''
+ ? String(opts.accept_sn)
+ : opts.sn != null
+ ? String(opts.sn)
+ : '';
+ const journalName = opts.journal_name != null ? String(opts.journal_name) : '';
+ const journalUrl = opts.journal_url != null ? String(opts.journal_url) : '';
+ const map = {
+ title,
+ article_title: title,
+ manuscript_title: title,
+ accept_sn: acceptSn,
+ article_sn: acceptSn,
+ sn: acceptSn,
+ journal_name: journalName,
+ journal_url: journalUrl
+ };
+ return String(html).replace(/\{\{\s*([^}]+?)\s*\}\}/g, (full, rawKey) => {
+ const key = String(rawKey).trim();
+ if (!key) return full;
+ if (Object.prototype.hasOwnProperty.call(map, key)) {
+ return map[key];
+ }
+ return full;
+ });
+}