tijiao
This commit is contained in:
@@ -19,8 +19,8 @@ const service = axios.create({
|
|||||||
// baseURL: 'https://submission.tmrjournals.com/', //正式 记得切换
|
// baseURL: 'https://submission.tmrjournals.com/', //正式 记得切换
|
||||||
// baseURL: 'http://www.tougao.com/', //测试本地 记得切换
|
// baseURL: 'http://www.tougao.com/', //测试本地 记得切换
|
||||||
// baseURL: 'http://192.168.110.110/tougao/public/index.php/',
|
// baseURL: 'http://192.168.110.110/tougao/public/index.php/',
|
||||||
// baseURL: '/api', //本地
|
baseURL: '/api', //本地
|
||||||
baseURL: '/', //正式
|
// baseURL: '/', //正式
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,12 @@
|
|||||||
<el-menu-item index="mailboxManagement">
|
<el-menu-item index="mailboxManagement">
|
||||||
{{ $t('sidebar.mailboxManagement') }}
|
{{ $t('sidebar.mailboxManagement') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
<el-menu-item index="mailboxConfig">
|
||||||
|
{{ $t('sidebar.mailboxConfig') }}
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="mailboxCollect">
|
||||||
|
{{ $t('sidebar.mailboxCollect') }}
|
||||||
|
</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
<el-submenu index="tools">
|
<el-submenu index="tools">
|
||||||
<template slot="title"> <i class="el-icon-paperclip"></i> {{ $t('sidebar.tools') }} </template>
|
<template slot="title"> <i class="el-icon-paperclip"></i> {{ $t('sidebar.tools') }} </template>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index">
|
<li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index">
|
||||||
<router-link :to="item.path" class="tags-li-title">
|
<router-link :to="item.path" class="tags-li-title">
|
||||||
{{item.title}}
|
{{ item.titleKey ? $t(item.titleKey) : item.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span>
|
<span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span>
|
||||||
</li>
|
</li>
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
}
|
}
|
||||||
this.tagsList.push({
|
this.tagsList.push({
|
||||||
title: route.meta.title,
|
title: route.meta.title,
|
||||||
|
titleKey: route.meta.titleKey || null,
|
||||||
path: route.fullPath,
|
path: route.fullPath,
|
||||||
name: route.matched[1].components.default.name
|
name: route.matched[1].components.default.name
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ const en = {
|
|||||||
mailbox3: 'Mailbox template',
|
mailbox3: 'Mailbox template',
|
||||||
tools: 'Assistant tools',
|
tools: 'Assistant tools',
|
||||||
mailboxManagement: 'Mailbox Management',
|
mailboxManagement: 'Mailbox Management',
|
||||||
|
mailboxConfig: 'Mailbox config',
|
||||||
|
mailboxCollect: 'Mailbox list',
|
||||||
scholarCrawlers: 'Scholar Crawlers',
|
scholarCrawlers: 'Scholar Crawlers',
|
||||||
ReArticles: 'Rejected Manuscripts', // 被拒稿件
|
ReArticles: 'Rejected Manuscripts', // 被拒稿件
|
||||||
editorialBoard: 'Boss System',
|
editorialBoard: 'Boss System',
|
||||||
@@ -282,6 +284,144 @@ const en = {
|
|||||||
GroupClassification: 'Group List',
|
GroupClassification: 'Group List',
|
||||||
JournalInstallment: 'Journal Installment',
|
JournalInstallment: 'Journal Installment',
|
||||||
},
|
},
|
||||||
|
mailboxConfig: {
|
||||||
|
mailSystem: 'Mailbox system',
|
||||||
|
title: 'Mailbox config',
|
||||||
|
journal: 'Journal',
|
||||||
|
allJournal: 'All journals',
|
||||||
|
query: 'Search',
|
||||||
|
addAccount: 'Add email account',
|
||||||
|
noData: 'No data',
|
||||||
|
smtpFromName: 'Sender name',
|
||||||
|
smtpFromNamePlaceholder: 'Display name when sending',
|
||||||
|
smtpHost: 'SMTP host',
|
||||||
|
smtpPort: 'SMTP port',
|
||||||
|
smtpPortPlaceholder: 'eg: 465',
|
||||||
|
smtpEncryption: 'SMTP encryption',
|
||||||
|
smtpEncryptionPlaceholder: 'eg: ssl',
|
||||||
|
imapHost: 'IMAP host',
|
||||||
|
imapPort: 'IMAP port',
|
||||||
|
imapPortPlaceholder: 'eg: 993',
|
||||||
|
todaySent: 'Today sent',
|
||||||
|
remainingToday: 'Remaining today',
|
||||||
|
state: 'State',
|
||||||
|
primary: 'Primary',
|
||||||
|
primaryTag: 'Primary',
|
||||||
|
operation: 'Operation',
|
||||||
|
edit: 'Edit',
|
||||||
|
delete: 'Delete',
|
||||||
|
mailManage: 'Mail manage',
|
||||||
|
dialogAdd: 'Add email account',
|
||||||
|
dialogEdit: 'Edit email account',
|
||||||
|
selectJournal: 'Select journal',
|
||||||
|
account: 'Email account',
|
||||||
|
accountPlaceholder: 'Sender / login email',
|
||||||
|
password: 'Password',
|
||||||
|
passwordPlaceholder: 'Password',
|
||||||
|
passwordTip: 'Leave blank to keep unchanged when editing',
|
||||||
|
smtpPlaceholder: 'eg: mail.tmrjournals.co.nz',
|
||||||
|
imapPlaceholder: 'eg: mail.tmrjournals.co.nz',
|
||||||
|
isPrimary: 'Set as primary',
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No',
|
||||||
|
primaryTip: 'Each journal has exactly one primary mailbox for sending and receiving.',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
save: 'Save',
|
||||||
|
deleteConfirm: 'Delete this email config?',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
addSuccess: 'Added successfully',
|
||||||
|
editSuccess: 'Updated successfully',
|
||||||
|
deleteSuccess: 'Deleted successfully',
|
||||||
|
addFail: 'Add failed',
|
||||||
|
editFail: 'Update failed',
|
||||||
|
deleteFail: 'Delete failed',
|
||||||
|
addSuccessMock: 'Added (mock)',
|
||||||
|
editSuccessMock: 'Updated (mock)',
|
||||||
|
deleteSuccessMock: 'Deleted (mock)',
|
||||||
|
rulesJournal: 'Please select journal',
|
||||||
|
rulesAccount: 'Please enter email account',
|
||||||
|
rulesAccountFormat: 'Please enter a valid email',
|
||||||
|
rulesPassword: 'Please enter password',
|
||||||
|
rulesSmtpFromName: 'Please enter sender name',
|
||||||
|
rulesSmtpHost: 'Please enter SMTP host',
|
||||||
|
rulesSmtpPort: 'Please enter SMTP port',
|
||||||
|
rulesSmtpEncryption: 'Please enter SMTP encryption',
|
||||||
|
rulesImapHost: 'Please enter IMAP host',
|
||||||
|
rulesImapPort: 'Please enter IMAP port',
|
||||||
|
rulesIsPrimary: 'Please set primary or not',
|
||||||
|
},
|
||||||
|
mailboxCollect: {
|
||||||
|
inboxTab: 'Mail received',
|
||||||
|
outboxTab: 'Mail sent',
|
||||||
|
draftsTab: 'Drafts',
|
||||||
|
deletedTab: 'Deleted',
|
||||||
|
spamTab: 'Spam',
|
||||||
|
searchPlaceholder: 'Please enter name or email',
|
||||||
|
searchBtn: 'Search',
|
||||||
|
syncBtn: 'Sync remote mail',
|
||||||
|
writeBtn: 'Write letter',
|
||||||
|
email: 'Email',
|
||||||
|
account: 'Account',
|
||||||
|
time: 'Time',
|
||||||
|
look: 'Look',
|
||||||
|
emptyText: 'New messages (0)',
|
||||||
|
detailTitle: 'Mail detail',
|
||||||
|
from: 'From',
|
||||||
|
to: 'To',
|
||||||
|
subject: 'Subject',
|
||||||
|
close: 'Close',
|
||||||
|
noSubject: '(No subject)',
|
||||||
|
reply: 'Reply',
|
||||||
|
forward: 'Forward',
|
||||||
|
delete: 'Delete',
|
||||||
|
featureDev: 'This feature is under development',
|
||||||
|
selectMailTip: 'Select an email to read',
|
||||||
|
selectAccountTitle: 'Select email account',
|
||||||
|
journal: 'Journal',
|
||||||
|
accountColumn: 'Email account',
|
||||||
|
nameColumn: 'Name',
|
||||||
|
switchColumn: 'Switch',
|
||||||
|
useBtn: 'Switch',
|
||||||
|
changeAccountBtn: 'Change account',
|
||||||
|
syncSuccess: 'Sync succeeded',
|
||||||
|
syncFail: 'Sync failed',
|
||||||
|
operation: 'Operation',
|
||||||
|
},
|
||||||
|
mailboxSend: {
|
||||||
|
title: 'Write mail',
|
||||||
|
to: 'To:',
|
||||||
|
selectFromLibrary: 'Select from address book',
|
||||||
|
subject: 'Subject:',
|
||||||
|
cc: 'Cc:',
|
||||||
|
attachments: 'Attachments:',
|
||||||
|
upload: 'Upload',
|
||||||
|
templateSelection: 'Template selection',
|
||||||
|
sender: 'Sender:',
|
||||||
|
send: 'Send',
|
||||||
|
selectUser: 'Select User',
|
||||||
|
batchSelection: 'Batch selection',
|
||||||
|
email: 'Email',
|
||||||
|
account: 'Account',
|
||||||
|
operation: 'Operation',
|
||||||
|
selectBtn: 'Select',
|
||||||
|
emptyText: 'No data',
|
||||||
|
selectTemplate: 'Select template',
|
||||||
|
chooseTemplate: 'Choose Template:',
|
||||||
|
chooseTemplatePlaceholder: 'Please select template',
|
||||||
|
none: 'None',
|
||||||
|
previewTemplate: 'Preview Formatted Document:',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
save: 'Save',
|
||||||
|
saveDraft: 'Save draft',
|
||||||
|
editorPlaceholder: 'Please enter...',
|
||||||
|
validateTo: 'Please add at least one addressee',
|
||||||
|
validateSubject: 'Please enter mail subject',
|
||||||
|
sendSuccess: 'Send success',
|
||||||
|
sendFail: 'Send failed',
|
||||||
|
sendMock: 'Send (mock): will really send when api/Mail/sendMail is ready',
|
||||||
|
needAccount: 'Please select a sender account from the mailbox list first',
|
||||||
|
backToInbox: 'Back to inbox',
|
||||||
|
},
|
||||||
home: {
|
home: {
|
||||||
authortop: 'Author guide',
|
authortop: 'Author guide',
|
||||||
usermsg: 'New messages',
|
usermsg: 'New messages',
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ const zh = {
|
|||||||
mailbox3: '模板管理',
|
mailbox3: '模板管理',
|
||||||
tools: '辅助工具',
|
tools: '辅助工具',
|
||||||
mailboxManagement: '邮箱管理',
|
mailboxManagement: '邮箱管理',
|
||||||
|
mailboxConfig: '邮箱配置管理',
|
||||||
|
mailboxCollect: '邮箱列表',
|
||||||
scholarCrawlers: '学者抓取',
|
scholarCrawlers: '学者抓取',
|
||||||
ReArticles: '被拒稿件', // 被拒稿件
|
ReArticles: '被拒稿件', // 被拒稿件
|
||||||
editorialBoard: '编委管理',
|
editorialBoard: '编委管理',
|
||||||
@@ -268,6 +270,144 @@ const zh = {
|
|||||||
JournalInstallment: '分期列表',
|
JournalInstallment: '分期列表',
|
||||||
|
|
||||||
},
|
},
|
||||||
|
mailboxConfig: {
|
||||||
|
mailSystem: '邮件系统',
|
||||||
|
title: '邮箱配置管理',
|
||||||
|
journal: '所属期刊',
|
||||||
|
allJournal: '全部期刊',
|
||||||
|
query: '搜索',
|
||||||
|
addAccount: '添加邮箱账号',
|
||||||
|
noData: '暂无数据',
|
||||||
|
smtpFromName: '发件人名称',
|
||||||
|
smtpFromNamePlaceholder: '发信时显示的名称',
|
||||||
|
smtpHost: 'SMTP 地址',
|
||||||
|
smtpPort: 'SMTP 端口',
|
||||||
|
smtpPortPlaceholder: 'eg: 465',
|
||||||
|
smtpEncryption: 'SMTP 加密',
|
||||||
|
smtpEncryptionPlaceholder: 'ssl',
|
||||||
|
imapHost: 'IMAP 地址',
|
||||||
|
imapPort: 'IMAP 端口',
|
||||||
|
imapPortPlaceholder: 'eg: 993',
|
||||||
|
todaySent: '今日已发',
|
||||||
|
remainingToday: '今日剩余',
|
||||||
|
state: '状态',
|
||||||
|
primary: '主邮箱',
|
||||||
|
primaryTag: '主邮箱',
|
||||||
|
operation: '操作',
|
||||||
|
edit: '编辑',
|
||||||
|
delete: '删除',
|
||||||
|
mailManage: '邮箱管理',
|
||||||
|
dialogAdd: '添加邮箱账号',
|
||||||
|
dialogEdit: '修改邮箱账号信息',
|
||||||
|
selectJournal: '请选择期刊',
|
||||||
|
account: '邮箱账号',
|
||||||
|
accountPlaceholder: '发件/登录邮箱',
|
||||||
|
password: '密码',
|
||||||
|
passwordPlaceholder: '密码',
|
||||||
|
passwordTip: '编辑时留空表示不修改',
|
||||||
|
smtpPlaceholder: 'eg: mail.tmrjournals.co.nz',
|
||||||
|
imapPlaceholder: 'eg: mail.tmrjournals.co.nz',
|
||||||
|
isPrimary: '设为主邮箱',
|
||||||
|
yes: '是',
|
||||||
|
no: '否',
|
||||||
|
primaryTip: '每个期刊有且仅有一个主邮箱,用于默认发信与收信。',
|
||||||
|
cancel: '取消',
|
||||||
|
save: '保存',
|
||||||
|
deleteConfirm: '确定删除该邮箱配置?',
|
||||||
|
confirm: '确定',
|
||||||
|
addSuccess: '添加成功',
|
||||||
|
editSuccess: '修改成功',
|
||||||
|
deleteSuccess: '删除成功',
|
||||||
|
addFail: '添加失败',
|
||||||
|
editFail: '修改失败',
|
||||||
|
deleteFail: '删除失败',
|
||||||
|
addSuccessMock: '添加成功(模拟)',
|
||||||
|
editSuccessMock: '修改成功(模拟)',
|
||||||
|
deleteSuccessMock: '删除成功(模拟)',
|
||||||
|
rulesJournal: '请选择所属期刊',
|
||||||
|
rulesAccount: '请输入邮箱账号',
|
||||||
|
rulesAccountFormat: '请输入正确的邮箱格式',
|
||||||
|
rulesPassword: '请输入密码',
|
||||||
|
rulesSmtpFromName: '请输入发件人显示名称',
|
||||||
|
rulesSmtpHost: '请输入 SMTP 地址',
|
||||||
|
rulesSmtpPort: '请输入 SMTP 端口',
|
||||||
|
rulesSmtpEncryption: '请输入 SMTP 加密方式',
|
||||||
|
rulesImapHost: '请输入 IMAP 地址',
|
||||||
|
rulesImapPort: '请输入 IMAP 端口',
|
||||||
|
rulesIsPrimary: '请选择是否主邮箱',
|
||||||
|
},
|
||||||
|
mailboxCollect: {
|
||||||
|
inboxTab: '收件箱',
|
||||||
|
outboxTab: '发件箱',
|
||||||
|
draftsTab: '草稿箱',
|
||||||
|
deletedTab: '已删除',
|
||||||
|
spamTab: '垃圾邮件',
|
||||||
|
searchPlaceholder: '请输入姓名或邮箱',
|
||||||
|
searchBtn: '搜索',
|
||||||
|
syncBtn: '同步远程邮箱',
|
||||||
|
writeBtn: '写邮件',
|
||||||
|
email: '邮箱',
|
||||||
|
account: '账户',
|
||||||
|
time: '时间',
|
||||||
|
look: '查看',
|
||||||
|
emptyText: '暂无邮件',
|
||||||
|
detailTitle: '邮件详情',
|
||||||
|
from: '发件人',
|
||||||
|
to: '收件人',
|
||||||
|
subject: '主题',
|
||||||
|
close: '关闭',
|
||||||
|
noSubject: '(无主题)',
|
||||||
|
reply: '回复',
|
||||||
|
forward: '转发',
|
||||||
|
delete: '删除',
|
||||||
|
featureDev: '该功能正在开发中',
|
||||||
|
selectMailTip: '选择一封邮件进行阅读',
|
||||||
|
selectAccountTitle: '选择邮箱账号',
|
||||||
|
journal: '期刊',
|
||||||
|
accountColumn: '邮箱账号',
|
||||||
|
nameColumn: '名称',
|
||||||
|
switchColumn: '切换',
|
||||||
|
useBtn: '切换',
|
||||||
|
changeAccountBtn: '切换邮箱账号',
|
||||||
|
syncSuccess: '同步成功',
|
||||||
|
syncFail: '同步失败',
|
||||||
|
operation: '操作',
|
||||||
|
},
|
||||||
|
mailboxSend: {
|
||||||
|
title: '写邮件',
|
||||||
|
to: '收件人:',
|
||||||
|
selectFromLibrary: '从通讯录选择',
|
||||||
|
subject: '主题:',
|
||||||
|
cc: '抄送:',
|
||||||
|
attachments: '附件:',
|
||||||
|
upload: '上传',
|
||||||
|
templateSelection: '模板选择',
|
||||||
|
sender: '发件人:',
|
||||||
|
send: '发送',
|
||||||
|
selectUser: '选择用户',
|
||||||
|
batchSelection: '批量选择',
|
||||||
|
email: '邮箱',
|
||||||
|
account: '账户',
|
||||||
|
operation: '操作',
|
||||||
|
selectBtn: '选择',
|
||||||
|
emptyText: '暂无数据',
|
||||||
|
selectTemplate: '选择模板',
|
||||||
|
chooseTemplate: '选择模板:',
|
||||||
|
chooseTemplatePlaceholder: '请选择模板',
|
||||||
|
none: '无',
|
||||||
|
previewTemplate: '模板预览:',
|
||||||
|
cancel: '取消',
|
||||||
|
save: '保存',
|
||||||
|
saveDraft: '保存草稿',
|
||||||
|
editorPlaceholder: '请输入邮件内容...',
|
||||||
|
validateTo: '请至少添加一个收件人',
|
||||||
|
validateSubject: '请输入邮件主题',
|
||||||
|
sendSuccess: '发送成功',
|
||||||
|
sendFail: '发送失败',
|
||||||
|
sendMock: '发送(模拟):接口 api/Mail/sendMail 就绪后将真实发送',
|
||||||
|
needAccount: '请从邮箱列表选择发件账号后再发送',
|
||||||
|
backToInbox: '返回收件箱',
|
||||||
|
},
|
||||||
home: {
|
home: {
|
||||||
authortop: '用户指南',
|
authortop: '用户指南',
|
||||||
usermsg: '新消息',
|
usermsg: '新消息',
|
||||||
|
|||||||
201
src/components/page/components/email/MailDetail.vue
Normal file
201
src/components/page/components/email/MailDetail.vue
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mail-detail-container">
|
||||||
|
<div class="detail-toolbar">
|
||||||
|
<div class="toolbar-left">
|
||||||
|
<el-tooltip content="回复" placement="bottom"><i class="el-icon-chat-line-square action-icon"></i></el-tooltip>
|
||||||
|
<el-tooltip content="转发" placement="bottom"><i class="el-icon-position action-icon"></i></el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="bottom"><i class="el-icon-delete action-icon" style="color: #fb2c36;"></i></el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<!-- <i class="el-icon-star-off action-icon"></i> -->
|
||||||
|
<i class="el-icon-close action-icon" @click="$emit('close')"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-scroll-content">
|
||||||
|
<h1 class="mail-subject">{{ mailData.subject }}</h1>
|
||||||
|
|
||||||
|
<div class="mail-header-info">
|
||||||
|
<el-avatar :size="40" class="sender-avatar">{{ (mailData.from_name || 'U')[0] }}</el-avatar>
|
||||||
|
<div class="info-main">
|
||||||
|
<div class="first-line">
|
||||||
|
<span class="sender-name">{{ mailData.from_name }}</span>
|
||||||
|
<span class="sender-email"><{{ mailData.from_email }}></span>
|
||||||
|
<span class="send-time">{{ formatDisplayTime(mailData.email_date) }}</span>
|
||||||
|
<span class="detail-toggle" @click="isDetailExpanded = !isDetailExpanded" v-if="mailData.to_list&&mailData.to_list.length>0">
|
||||||
|
{{ isDetailExpanded ? '收起' : '详情' }} <i :class="isDetailExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isDetailExpanded" class="expanded-info">
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="label">收件人:</span>
|
||||||
|
<div class="recipient-tags">
|
||||||
|
<el-tag v-for="(to, index) in mailData.to_list" :key="'to-'+index" size="mini" type="info">{{ to.name || to.email }}</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="mailData.cc_list && mailData.cc_list.length" class="info-row">
|
||||||
|
<span class="label">抄送:</span>
|
||||||
|
<div class="recipient-tags">
|
||||||
|
<el-tag v-for="(cc, index) in mailData.cc_list" :key="'cc-'+index" size="mini" type="warning" effect="plain">{{ cc.name || cc.email }}</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="simple-info" v-if="mailData.to_list&&mailData.to_list.length>0">
|
||||||
|
发送给 {{ mailData.to_list && mailData.to_list[0] ? (mailData.to_list[0].name || mailData.to_list[0].email) : '' }} 等{{ mailData.to_list.length }}人
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mail-body-content" v-html="mailData.content_html"></div>
|
||||||
|
|
||||||
|
<div v-if="mailData.attachments && mailData.attachments.length" class="attachment-section">
|
||||||
|
<div class="attachment-header">
|
||||||
|
<span>{{ mailData.attachments.length }}个附件 ({{ totalAttachmentSize }})</span>
|
||||||
|
<el-button type="text" size="small">打包下载</el-button>
|
||||||
|
<span class="security-tip"><i class="el-icon-success"></i> 附件中未发现病毒</span>
|
||||||
|
</div>
|
||||||
|
<div class="attachment-list">
|
||||||
|
<div v-for="(file, index) in mailData.attachments" :key="index" class="attachment-card">
|
||||||
|
<div class="file-icon">
|
||||||
|
<i :class="getFileIcon(file.name)"></i>
|
||||||
|
</div>
|
||||||
|
<div class="file-info">
|
||||||
|
<div class="file-name" :title="file.name">{{ file.name }}</div>
|
||||||
|
<div class="file-size">{{ file.size }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MailDetail',
|
||||||
|
props: {
|
||||||
|
mailData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
subject: '',
|
||||||
|
from_name: '',
|
||||||
|
from_email: '',
|
||||||
|
send_time: '',
|
||||||
|
to_list: [],
|
||||||
|
cc_list: [],
|
||||||
|
content: '',
|
||||||
|
attachments: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isDetailExpanded: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalAttachmentSize() {
|
||||||
|
// 简单模拟计算总量,实际可根据逻辑累加
|
||||||
|
return "11MB";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatDisplayTime(timestamp) {
|
||||||
|
if (!timestamp) return '';
|
||||||
|
|
||||||
|
// 1. 处理 10 位秒级时间戳,转为毫秒并实例化 Date 对象
|
||||||
|
const date = new Date(Number(timestamp) * 1000);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
// 提取日期信息用于比较
|
||||||
|
const dateYear = date.getFullYear();
|
||||||
|
const dateMonth = date.getMonth() + 1;
|
||||||
|
const dateDay = date.getDate();
|
||||||
|
const nowYear = now.getFullYear();
|
||||||
|
|
||||||
|
// 获取昨天日期
|
||||||
|
const yesterday = new Date(now);
|
||||||
|
yesterday.setDate(now.getDate() - 1);
|
||||||
|
|
||||||
|
// 获取具体时分并补零 (例如 09:05)
|
||||||
|
const hours = date.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||||
|
const timePart = `${hours}:${minutes}`;
|
||||||
|
|
||||||
|
// --- 按照图示规则判断返回 ---
|
||||||
|
|
||||||
|
// 1. 如果是今天:只显示时间,如 "15:57"
|
||||||
|
if (date.toDateString() === now.toDateString()) {
|
||||||
|
return timePart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 如果是昨天:只显示 "昨天"
|
||||||
|
if (date.toDateString() === yesterday.toDateString()) {
|
||||||
|
return '昨天';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 如果是今年(非今天/昨天):显示 "月-日",如 "3月8日"
|
||||||
|
if (dateYear === nowYear) {
|
||||||
|
return `${dateMonth}月${dateDay}日`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果是往年:显示完整年月日,如 "2025-12-05"
|
||||||
|
const fullMonth = dateMonth.toString().padStart(2, '0');
|
||||||
|
const fullDay = dateDay.toString().padStart(2, '0');
|
||||||
|
return `${dateYear}-${fullMonth}-${fullDay}`;
|
||||||
|
},
|
||||||
|
getFileIcon(fileName) {
|
||||||
|
if (fileName.includes('.doc')) return 'el-icon-document text-blue';
|
||||||
|
if (fileName.includes('.pdf')) return 'el-icon-document text-red';
|
||||||
|
return 'el-icon-document';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mail-detail-container { height: 100%; display: flex; flex-direction: column; background: #fff; }
|
||||||
|
|
||||||
|
/* 顶部工具栏 */
|
||||||
|
.detail-toolbar { padding: 10px 20px; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
.action-icon { font-size: 18px; color: #606266; cursor: pointer; margin-right: 20px; }
|
||||||
|
.action-icon:hover { color: #409EFF; }
|
||||||
|
|
||||||
|
.detail-scroll-content { flex: 1; overflow-y: auto; padding: 20px 40px; }
|
||||||
|
|
||||||
|
/* 邮件标题 */
|
||||||
|
.mail-subject { font-size: 20px; font-weight: bold; margin-bottom: 25px; color: #303133; }
|
||||||
|
|
||||||
|
/* 头部信息 */
|
||||||
|
.mail-header-info { display: flex; margin-bottom: 30px; }
|
||||||
|
.info-main { flex: 1; margin-left: 15px; }
|
||||||
|
.first-line { display: flex; align-items: center; margin-bottom: 5px; font-size: 14px; }
|
||||||
|
.sender-name { font-weight: bold; color: #303133; }
|
||||||
|
.sender-email { color: #909399; margin-left: 5px; }
|
||||||
|
.send-time { margin-left: auto; color: #909399; }
|
||||||
|
.detail-toggle { margin-left: 10px; color: #409EFF; cursor: pointer; font-size: 12px; }
|
||||||
|
|
||||||
|
.expanded-info { background: #f8f9fa; padding: 10px; border-radius: 4px; margin-top: 10px; }
|
||||||
|
.info-row { display: flex; margin-bottom: 8px; }
|
||||||
|
.info-row .label { width: 60px; color: #909399; font-size: 13px; }
|
||||||
|
.recipient-tags { flex: 1; display: flex; flex-wrap: wrap; gap: 5px; }
|
||||||
|
.simple-info { font-size: 12px; color: #909399; }
|
||||||
|
|
||||||
|
/* 正文 */
|
||||||
|
.mail-body-content { line-height: 1.6; font-size: 14px; color: #303133; min-height: 200px; margin-bottom: 50px; }
|
||||||
|
|
||||||
|
/* 附件卡片 */
|
||||||
|
.attachment-section { border-top: 1px solid #eee; padding-top: 20px; }
|
||||||
|
.attachment-header { margin-bottom: 15px; font-size: 13px; color: #606266; display: flex; align-items: center; }
|
||||||
|
.security-tip { margin-left: auto; color: #67C23A; }
|
||||||
|
.attachment-list { display: flex; flex-wrap: wrap; gap: 15px; }
|
||||||
|
.attachment-card { width: 260px; border: 1px solid #e4e7ed; border-radius: 4px; display: flex; padding: 10px; background: #fbfbfc; }
|
||||||
|
.file-icon { font-size: 32px; color: #409EFF; margin-right: 12px; }
|
||||||
|
.file-info { flex: 1; overflow: hidden; }
|
||||||
|
.file-name { font-size: 13px; color: #303133; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.file-size { font-size: 12px; color: #909399; margin-top: 4px; }
|
||||||
|
.text-blue { color: #409EFF; }
|
||||||
|
.text-red { color: #F56C6C; }
|
||||||
|
</style>
|
||||||
@@ -1,147 +1,432 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="mail-container">
|
||||||
<div class="crumbs">
|
<div class="mail-sidebar">
|
||||||
<el-breadcrumb separator="/">
|
<div class="p-20">
|
||||||
<el-breadcrumb-item>
|
<el-button type="primary" icon="el-icon-plus" class="write-btn" @click="handleWrite">
|
||||||
<i class="el-icon-message"></i> Mailbox list
|
{{ $t('mailboxCollect.writeBtn') }}
|
||||||
</el-breadcrumb-item>
|
</el-button>
|
||||||
</el-breadcrumb>
|
</div>
|
||||||
</div>
|
<ul class="folder-list">
|
||||||
<div class="container">
|
<li :class="{ active: currentFolder === 'inbox' }" @click="switchFolder('inbox')">
|
||||||
<el-tabs tab-position="left" style="height: 200px;">
|
<i class="el-icon-message"></i> {{ $t('mailboxCollect.inboxTab') }}
|
||||||
<el-tab-pane :label="'Mail received ( '+queryIn.num+' )'">
|
<span class="badge" v-if="queryIn.num > 0">{{ queryIn.num }}</span>
|
||||||
<div style="margin: 5px 0 20px 10px;">
|
</li>
|
||||||
<el-input v-model="queryIn.username" placeholder="Please enter name or email" style="width: 300px;margin: 0 15px 0 0;"></el-input>
|
<li :class="{ active: currentFolder === 'sent' }" @click="switchFolder('sent')">
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleSearchIn" style="">Search</el-button>
|
<i class="el-icon-position"></i><span style="font-size: 14px;">{{ $t('mailboxCollect.outboxTab')}}</span>
|
||||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" style="float: right;">Write Letter</el-button>
|
</li>
|
||||||
</div>
|
<li @click="notImplemented"><i class="el-icon-document"></i> <span style="font-size: 14px;">{{ $t('mailboxCollect.draftsTab')}}</span> </li>
|
||||||
<div style="margin: 0 0 0 10px;">
|
<li @click="notImplemented"><i class="el-icon-delete"></i> <span style="font-size: 14px;">{{ $t('mailboxCollect.deletedTab')}}</span> </li>
|
||||||
<el-table :data="tableData_in" border ref="multipleTable" header-cell-class-name="table-header" empty-text="New messages (0)">
|
</ul>
|
||||||
<el-table-column label="Email">
|
|
||||||
<template slot-scope="scope">
|
<div class="sidebar-footer">
|
||||||
<img v-if="scope.row.state==0" src="../../assets/img/mes_op.png" alt="" style="vertical-align: text-bottom;margin: 0 6px 0 2px;">
|
<div class="user-card">
|
||||||
<img v-if="scope.row.state==1" src="../../assets/img/mes_ne.png" alt="" style="vertical-align: top;margin: 0 6px 0 0;">
|
<el-avatar size="small" icon="el-icon-user-solid" class="user-avatar"></el-avatar>
|
||||||
{{scope.row.email}}
|
<div class="user-detail">
|
||||||
</template>
|
<div class="user-name">{{ selectedAccount ? (selectedAccount.smtp_from_name || 'Nova Demo') : '-' }}</div>
|
||||||
</el-table-column>
|
<div class="user-email" :title="selectedAccountEmail">{{ selectedAccountEmail }}</div>
|
||||||
<el-table-column prop="account" label="Account"></el-table-column>
|
</div>
|
||||||
<el-table-column prop="ctime" label="Time" width="100"></el-table-column>
|
</div>
|
||||||
<el-table-column label=" " width="100" align="center">
|
<el-button size="mini" type="text" @click="openAccountDialog" class="switch-btn">
|
||||||
<template slot-scope="scope">
|
{{ $t('mailboxCollect.changeAccountBtn')}}
|
||||||
<el-button plain type="primary" icon="el-icon-edit" @click="handleDetail(scope.row)">Look</el-button>
|
</el-button>
|
||||||
</template>
|
</div>
|
||||||
</el-table-column>
|
</div>
|
||||||
</el-table>
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination background layout="total, prev, pager, next" :current-page="queryIn.pageIndex" :page-size="queryIn.pageSize"
|
|
||||||
:total="link_TotalIn" @current-change="handlePageChangeIn"></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :label="'Mail sent ( '+queryOut.num+' )'">
|
|
||||||
<div style="margin: 5px 0 20px 10px;">
|
|
||||||
<el-input v-model="queryOut.username" placeholder="Please enter name or email" style="width: 300px;margin: 0 15px 0 0;"></el-input>
|
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleSearchOut" style="">Search</el-button>
|
|
||||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" style="float: right;">Write Letter</el-button>
|
|
||||||
</div>
|
|
||||||
<div style="margin: 0 0 0 10px;">
|
|
||||||
<el-table :data="tableData_out" border ref="multipleTable" header-cell-class-name="table-header" empty-text="New messages (0)">
|
|
||||||
<el-table-column prop="email" label="Email"></el-table-column>
|
|
||||||
<el-table-column prop="account" label="Account"></el-table-column>
|
|
||||||
<el-table-column prop="ctime" label="Time" width="100"></el-table-column>
|
|
||||||
<el-table-column label=" " width="100" align="center">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button plain type="primary" icon="el-icon-edit" @click="handleDetail(scope.row)">Look</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="pagination">
|
|
||||||
<el-pagination background layout="total, prev, pager, next" :current-page="queryOut.pageIndex" :page-size="queryOut.pageSize"
|
|
||||||
:total="link_TotalOut" @current-change="handlePageChangeIn"></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</el-tab-pane>
|
<div class="mail-list-panel" :style="{ width: listWidth + 'px' }" v-if="selectedAccount">
|
||||||
</el-tabs>
|
<div class="panel-header">
|
||||||
|
<el-input
|
||||||
|
v-model="searchKeyword"
|
||||||
|
prefix-icon="el-icon-search"
|
||||||
|
:placeholder="$t('mailboxCollect.searchPlaceholder')"
|
||||||
|
clearable
|
||||||
|
@change="handleSearch"
|
||||||
|
></el-input>
|
||||||
|
<el-button icon="el-icon-refresh" circle :loading="syncLoading" @click="handleSyncInbox" style="margin-left: 10px;"></el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="list-scroll-area">
|
||||||
|
<template v-if="displayList.length > 0">
|
||||||
|
<div
|
||||||
|
v-for="item in displayList"
|
||||||
|
:key="item.id"
|
||||||
|
:class="['mail-item-box', { active: activeMailId === item.id, unread: item.state === 1 }]"
|
||||||
|
@click="selectMail(item)"
|
||||||
|
>
|
||||||
|
<div class="item-left">
|
||||||
|
<el-avatar :size="32" icon="el-icon-user-solid" class="sender-avatar"></el-avatar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-right">
|
||||||
|
<div class="row-one">
|
||||||
|
<span class="sender-name">{{ item.from_name || item.email }}</span>
|
||||||
|
<span class="send-time">{{ formatDisplayTime(item.email_date) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-two">
|
||||||
|
<span class="mail-subject">{{ item.subject || $t('mailboxCollect.noSubject') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-three">
|
||||||
|
<p class="mail-excerpt">{{ stripHtml(item.content || '') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else class="empty-list-container">
|
||||||
|
<div class="empty-wrapper">
|
||||||
|
<i class="el-icon-message"></i>
|
||||||
|
<p>{{ $t('mailboxCollect.emptyText') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="list-resizer" @mousedown="initResize" v-if="selectedAccount"></div>
|
||||||
|
|
||||||
|
<div class="mail-content-panel" v-if="selectedAccount" v-loading="detailLoading">
|
||||||
|
<template v-if="activeMailId && !detailLoading">
|
||||||
|
<div class="mail-page">
|
||||||
|
<mail-detail
|
||||||
|
v-if="detailMail"
|
||||||
|
:mailData="detailMail"
|
||||||
|
@close="closeDetail"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else class="empty-state">
|
||||||
|
<div class="empty-wrapper">
|
||||||
|
<i class="el-icon-message"></i>
|
||||||
|
<p>{{ $t('mailboxCollect.selectMailTip') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog :title="$t('mailboxCollect.selectAccountTitle')" :visible.sync="accountDialogVisible" width="600px" append-to-body>
|
||||||
|
<el-form inline style="margin-bottom: 10px;">
|
||||||
|
<el-form-item :label="$t('mailboxCollect.journal')">
|
||||||
|
<el-select v-model="accountJournalId" style="width: 260px;" @change="loadAccountsForJournal">
|
||||||
|
<el-option v-for="item in journalList" :key="item.journal_id" :label="item.title" :value="item.journal_id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table :data="accountList" v-loading="accountLoading" size="small">
|
||||||
|
<el-table-column prop="smtp_user" :label="$t('mailboxCollect.accountColumn')" />
|
||||||
|
<el-table-column prop="smtp_from_name" :label="$t('mailboxCollect.nameColumn')" />
|
||||||
|
<el-table-column :label="$t('mailboxCollect.operation')" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="primary" size="mini" @click="chooseAccount(scope.row)">
|
||||||
|
{{ $t('mailboxCollect.useBtn') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
const API = {
|
||||||
data() {
|
getInboxList: 'api/email_client/getInboxList',
|
||||||
return {
|
getEmailDetail: 'api/email_client/getEmailDetail',
|
||||||
baseUrl: this.Common.baseUrl,
|
receiveMail: 'api/Mail/receiveMail',
|
||||||
mediaUrl: this.Common.mediaUrl,
|
getAccounts: 'api/email_client/getAccounts',
|
||||||
tableData_in: [{
|
getOneEmail: 'api/email_client/getOneEmail',
|
||||||
state:0,
|
getAllJournal: 'api/Journal/getAllJournal',
|
||||||
email: '123456',
|
};
|
||||||
account: '123456',
|
import MailDetail from '../../components/page/components/email/MailDetail.vue';
|
||||||
ctime: '123456',
|
export default {
|
||||||
},{
|
data() {
|
||||||
state:1,
|
return {
|
||||||
email: '123456',
|
currentFolder: 'inbox',
|
||||||
account: '123456',
|
searchKeyword: '',
|
||||||
ctime: '123456',
|
syncLoading: false,
|
||||||
}],
|
activeMailId: null,
|
||||||
tableData_out: [],
|
tableData_in: [],
|
||||||
queryIn: {
|
tableData_out: [],
|
||||||
pageIndex: 1,
|
detailMail: {},
|
||||||
pageSize: 15,
|
queryIn: { num: 0 },
|
||||||
username: '',
|
listWidth: 350,
|
||||||
num: 10
|
minWidth: 260,
|
||||||
},
|
maxWidth: 600,
|
||||||
queryOut: {
|
selectedAccount: null,
|
||||||
pageIndex: 1,
|
accountDialogVisible: false,
|
||||||
pageSize: 15,
|
journalList: [],
|
||||||
username: '',
|
accountJournalId: null,
|
||||||
num: 30
|
accountList: [],
|
||||||
},
|
accountLoading: false,
|
||||||
link_TotalIn: 0,
|
detailLoading: false,
|
||||||
link_TotalOut: 0,
|
};
|
||||||
};
|
},
|
||||||
},
|
components: { MailDetail },
|
||||||
created() {
|
computed: {
|
||||||
this.getDate();
|
displayList() {
|
||||||
},
|
return this.currentFolder === 'inbox' ? this.tableData_in : this.tableData_out;
|
||||||
methods: {
|
},
|
||||||
// 获取编辑列表数据
|
selectedAccountEmail() {
|
||||||
getDate() {
|
return this.selectedAccount ? this.selectedAccount.smtp_user : '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initAccountSelection();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeDetail() {
|
||||||
|
this.activeMailId = null;
|
||||||
|
this.detailMail = {};
|
||||||
|
},
|
||||||
|
// 拖拽逻辑
|
||||||
|
initResize(e) {
|
||||||
|
const startX = e.clientX;
|
||||||
|
const startWidth = this.listWidth;
|
||||||
|
const doDrag = (moveEvent) => {
|
||||||
|
const newWidth = startWidth + (moveEvent.clientX - startX);
|
||||||
|
if (newWidth >= this.minWidth && newWidth <= this.maxWidth) {
|
||||||
|
this.listWidth = newWidth;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const stopDrag = () => {
|
||||||
|
document.removeEventListener('mousemove', doDrag);
|
||||||
|
document.removeEventListener('mouseup', stopDrag);
|
||||||
|
document.body.style.cursor = 'default';
|
||||||
|
};
|
||||||
|
document.addEventListener('mousemove', doDrag);
|
||||||
|
document.addEventListener('mouseup', stopDrag);
|
||||||
|
document.body.style.cursor = 'col-resize';
|
||||||
|
},
|
||||||
|
initAccountSelection() {
|
||||||
|
const q = this.$route.query;
|
||||||
|
if (q.j_email_id) {
|
||||||
|
this.loadAccountById(q.j_email_id);
|
||||||
|
} else {
|
||||||
|
this.openAccountDialog();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadAccountById(jEmailId) {
|
||||||
|
this.$api.post(API.getOneEmail, { j_email_id: jEmailId }).then(res => {
|
||||||
|
const email = res.data.email;
|
||||||
|
if (res.code === 0 && email) {
|
||||||
|
this.selectedAccount = email;
|
||||||
|
this.fetchData();
|
||||||
|
} else {
|
||||||
|
this.openAccountDialog();
|
||||||
|
}
|
||||||
|
}).catch(() => this.openAccountDialog());
|
||||||
|
},
|
||||||
|
openAccountDialog() {
|
||||||
|
this.accountDialogVisible = true;
|
||||||
|
this.loadJournals();
|
||||||
|
if (this.selectedAccount.journal_id) {
|
||||||
|
this.accountJournalId = this.selectedAccount.journal_id;
|
||||||
|
this.loadAccountsForJournal(this.selectedAccount.journal_id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadJournals() {
|
||||||
|
this.$api.post(API.getAllJournal, {}).then(res => {
|
||||||
|
this.journalList = (res.data.journals || res.data || []).map(i => ({
|
||||||
|
journal_id: i.journal_id || i.id,
|
||||||
|
title: i.title || i.name || ''
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadAccountsForJournal(id) {
|
||||||
|
this.accountLoading = true;
|
||||||
|
this.$api.post(API.getAccounts, { journal_id: id }).then(res => {
|
||||||
|
this.accountLoading = false;
|
||||||
|
this.accountList = res.data || [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
chooseAccount(row) {
|
||||||
|
this.selectedAccount = row;
|
||||||
|
this.accountDialogVisible = false;
|
||||||
|
this.closeDetail();
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
fetchData() {
|
||||||
|
if (!this.selectedAccount) return;
|
||||||
|
const params = {
|
||||||
|
j_email_id: this.selectedAccount.j_email_id,
|
||||||
|
journal_id: this.selectedAccount.journal_id,
|
||||||
|
keyword: this.searchKeyword || ''
|
||||||
|
};
|
||||||
|
this.$api.post(API.getInboxList, params).then(res => {
|
||||||
|
const list = (res && res.data && (res.data.list || res.data)) || [];
|
||||||
|
this.tableData_in = (Array.isArray(list) ? list : []).map(item => ({
|
||||||
|
id: item.inbox_id || item.id,
|
||||||
|
inbox_id: item.inbox_id || item.id,
|
||||||
|
email: item.from_email,
|
||||||
|
from_name: item.from_name,
|
||||||
|
subject: item.subject,
|
||||||
|
email_date: item.email_date,
|
||||||
|
content: item.content_html || item.content_text || '',
|
||||||
|
state: item.is_read === 1 ? 0 : 1
|
||||||
|
}));
|
||||||
|
this.queryIn.num = this.tableData_in.length;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
switchFolder(f) { this.currentFolder = f; this.activeMailId = null; },
|
||||||
|
selectMail(item) {
|
||||||
|
this.activeMailId = item.id;
|
||||||
|
this.detailLoading = true;
|
||||||
|
const inboxId = item.inbox_id || item.id;
|
||||||
|
this.$api.post(API.getEmailDetail, { inbox_id: inboxId }).then(res => {
|
||||||
|
this.detailLoading = false;
|
||||||
|
const d = res && res.data;
|
||||||
|
if (res && res.code === 0 && d) {
|
||||||
|
this.detailMail = {
|
||||||
|
...d
|
||||||
|
};
|
||||||
|
item.state = 0;
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.detailLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSyncInbox() {
|
||||||
|
this.syncLoading = true;
|
||||||
|
this.$api.post(API.receiveMail, { j_email_id: this.selectedAccount.j_email_id }).then(() => {
|
||||||
|
this.syncLoading = false;
|
||||||
|
this.fetchData();
|
||||||
|
}).catch(() => this.syncLoading = false);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 格式化邮件显示时间
|
||||||
|
* @param {Number|String} timestamp 后端返回的时间戳 (如: 1773110269)
|
||||||
|
* @returns {String} 格式化后的字符串 (如: 15:57, 昨天, 3月8日, 2025-12-05)
|
||||||
|
*/
|
||||||
|
formatDisplayTime(timestamp) {
|
||||||
|
if (!timestamp) return '';
|
||||||
|
|
||||||
},
|
// 1. 处理 10 位秒级时间戳,转为毫秒并实例化 Date 对象
|
||||||
// 搜索-收件箱
|
const date = new Date(Number(timestamp) * 1000);
|
||||||
handleSearchIn() {
|
const now = new Date();
|
||||||
this.getDate();
|
|
||||||
},
|
// 提取日期信息用于比较
|
||||||
// 搜索-发件箱
|
const dateYear = date.getFullYear();
|
||||||
handleSearchOut() {
|
const dateMonth = date.getMonth() + 1;
|
||||||
this.getDate();
|
const dateDay = date.getDate();
|
||||||
},
|
const nowYear = now.getFullYear();
|
||||||
// 写邮件
|
|
||||||
handleAdd() {
|
// 获取昨天日期
|
||||||
|
const yesterday = new Date(now);
|
||||||
|
yesterday.setDate(now.getDate() - 1);
|
||||||
|
|
||||||
},
|
// 获取具体时分并补零 (例如 09:05)
|
||||||
// 邮箱信息
|
const hours = date.getHours().toString().padStart(2, '0');
|
||||||
handleDetail(e) {
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||||
|
const timePart = `${hours}:${minutes}`;
|
||||||
|
|
||||||
},
|
// --- 按照图示规则判断返回 ---
|
||||||
|
|
||||||
// 分页导航-收件箱
|
// 1. 如果是今天:只显示时间,如 "15:57"
|
||||||
handlePageChangeIn(val) {
|
if (date.toDateString() === now.toDateString()) {
|
||||||
this.$set(this.queryIn, 'pageIndex', val);
|
return timePart;
|
||||||
this.getDate();
|
}
|
||||||
},
|
|
||||||
// 分页导航-发件箱
|
// 2. 如果是昨天:只显示 "昨天"
|
||||||
handlePageChangeOut(val) {
|
if (date.toDateString() === yesterday.toDateString()) {
|
||||||
this.$set(this.queryOut, 'pageIndex', val);
|
return '昨天';
|
||||||
this.getDate();
|
}
|
||||||
},
|
|
||||||
}
|
// 3. 如果是今年(非今天/昨天):显示 "月-日",如 "3月8日"
|
||||||
};
|
if (dateYear === nowYear) {
|
||||||
|
return `${dateMonth}月${dateDay}日`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果是往年:显示完整年月日,如 "2025-12-05"
|
||||||
|
const fullMonth = dateMonth.toString().padStart(2, '0');
|
||||||
|
const fullDay = dateDay.toString().padStart(2, '0');
|
||||||
|
return `${dateYear}-${fullMonth}-${fullDay}`;
|
||||||
|
},
|
||||||
|
stripHtml(html) { return new DOMParser().parseFromString(html, 'text/html').body.textContent || ""; },
|
||||||
|
handleWrite() {
|
||||||
|
if (!this.selectedAccount) return;
|
||||||
|
this.$router.push(
|
||||||
|
'/mailboxSend?journal_id=' +
|
||||||
|
this.selectedAccount.journal_id +
|
||||||
|
'&j_email_id=' +
|
||||||
|
this.selectedAccount.j_email_id
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleSearch() { this.fetchData(); },
|
||||||
|
notImplemented() { this.$message.info('开发中...'); }
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.mail-container {
|
||||||
|
display: flex;
|
||||||
|
height: calc(100vh - 120px);
|
||||||
|
background: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
/* 1. 左侧栏 */
|
||||||
|
.mail-sidebar {
|
||||||
|
width: 220px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-right: 1px solid #eaeaea;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.p-20 { padding: 20px; }
|
||||||
|
.write-btn { width: 100%; border-radius: 8px; font-weight: bold; }
|
||||||
|
.folder-list { list-style: none; padding: 0; margin: 0; flex: 1; }
|
||||||
|
.folder-list li {
|
||||||
|
padding: 12px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #606266;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.folder-list li i { margin-right: 12px; font-size: 18px; }
|
||||||
|
.folder-list li.active { background: #edeef0; color: #006699; font-weight: bold; border-right: 3px solid #006699; }
|
||||||
|
.badge { margin-left: auto; background: #ddd; padding: 2px 8px; border-radius: 10px; font-size: 12px; }
|
||||||
|
|
||||||
|
.sidebar-footer { padding: 15px 20px; border-top: 1px solid #eee; background: #f8f9fa; }
|
||||||
|
.user-card { display: flex; align-items: center; margin-bottom: 8px; overflow: hidden; }
|
||||||
|
.user-avatar { flex-shrink: 0; background: #ffeded; color: #f56c6c; }
|
||||||
|
.user-detail { margin-left: 10px; overflow: hidden; flex: 1; }
|
||||||
|
.user-name { font-size: 14px; font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.user-email { font-size: 12px; color: #909399; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.switch-btn { padding: 0; font-size: 12px; color: #409eff; }
|
||||||
|
|
||||||
|
/* 2. 中间列表栏 - 参考 image_8649db.png */
|
||||||
|
.mail-list-panel { display: flex; flex-direction: column; flex-shrink: 0; background: #fff; }
|
||||||
|
.panel-header { padding: 15px; border-bottom: 1px solid #f5f5f5; display: flex; }
|
||||||
|
.list-scroll-area { flex: 1; overflow-y: auto; }
|
||||||
|
|
||||||
|
.mail-item-box {
|
||||||
|
display: flex;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.mail-item-box:hover { background: #f5f7fa; }
|
||||||
|
.mail-item-box.active { background: #eef1f6; border-left: 3px solid #006699; }
|
||||||
|
.item-left { margin-right: 12px; display: flex; align-items: flex-start; padding-top: 4px; }
|
||||||
|
.sender-avatar { background: #c0c4cc; }
|
||||||
|
.item-right { flex: 1; overflow: hidden; }
|
||||||
|
.row-one { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
|
||||||
|
.sender-name { font-size: 14px; color: #303133; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.send-time { font-size: 12px; color: #909399; flex-shrink: 0; }
|
||||||
|
.row-two { margin-bottom: 4px; }
|
||||||
|
.mail-subject { font-size: 13px; color: #6a7282; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.mail-excerpt { font-size: 12px; color: #606266; margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||||
|
|
||||||
|
/* 拖拽条 */
|
||||||
|
.list-resizer { width: 4px; cursor: col-resize; border-left: 1px solid #eaeaea; transition: background 0.2s; }
|
||||||
|
.list-resizer:hover { background: #409eff; }
|
||||||
|
|
||||||
|
/* 3. 右侧详情 */
|
||||||
|
.mail-content-panel { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
||||||
|
.detail-toolbar { padding: 10px 20px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; }
|
||||||
|
.detail-content { padding: 30px 40px; overflow-y: auto; }
|
||||||
|
.mail-title { font-size: 24px; margin-bottom: 20px; }
|
||||||
|
.mail-info { display: flex; align-items: center; }
|
||||||
|
.info-main { margin-left: 15px; }
|
||||||
|
.mail-body { line-height: 1.6; font-size: 15px; }
|
||||||
|
.empty-state, .empty-list-container { flex: 1; display: flex; align-items: center; justify-content: center; color: #ccc; text-align: center; }
|
||||||
|
.empty-state i, .empty-list-container i { font-size: 48px; margin-bottom: 10px; }
|
||||||
|
</style>
|
||||||
324
src/components/page/mailboxConfig.vue
Normal file
324
src/components/page/mailboxConfig.vue
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="crumbs">
|
||||||
|
<el-breadcrumb separator="/">
|
||||||
|
<el-breadcrumb-item><i class="el-icon-setting"></i> {{ $t('mailboxConfig.mailSystem') }}</el-breadcrumb-item>
|
||||||
|
<el-breadcrumb-item>{{ $t('mailboxConfig.title') }}</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="handle-box">
|
||||||
|
<el-form :inline="true" :model="query" class="filter-form">
|
||||||
|
<el-form-item :label="$t('mailboxConfig.journal')">
|
||||||
|
<el-select v-model="query.journal_id" :placeholder="$t('mailboxConfig.selectJournal')" style="width: 300px;" @change="getList">
|
||||||
|
<el-option v-for="item in journalList" :key="item.journal_id" :label="item.title" :value="item.journal_id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="getList">{{ $t('mailboxConfig.query') }}</el-button>
|
||||||
|
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">{{ $t('mailboxConfig.addAccount') }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<el-table :data="tableData" border stripe class="table" header-cell-class-name="table-header" :empty-text="$t('mailboxConfig.noData')">
|
||||||
|
<!-- <el-table-column prop="journal_name" :label="$t('mailboxConfig.journal')" min-width="140"></el-table-column> -->
|
||||||
|
<el-table-column prop="account" :label="$t('mailboxConfig.account')" min-width="160"></el-table-column>
|
||||||
|
<el-table-column prop="smtp_from_name" :label="$t('mailboxConfig.smtpFromName')" min-width="120"></el-table-column>
|
||||||
|
<el-table-column prop="smtp_host" :label="$t('mailboxConfig.smtpHost')" min-width="120"></el-table-column>
|
||||||
|
<el-table-column prop="smtp_port" :label="$t('mailboxConfig.smtpPort')" width="100" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="imap_host" :label="$t('mailboxConfig.imapHost')" min-width="120"></el-table-column>
|
||||||
|
<el-table-column prop="imap_port" :label="$t('mailboxConfig.imapPort')" width="100" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="today_sent" :label="$t('mailboxConfig.todaySent')" width="95" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="remaining_today" :label="$t('mailboxConfig.remainingToday')" width="130" align="center"></el-table-column>
|
||||||
|
<!-- <el-table-column prop="state" :label="$t('mailboxConfig.state')" width="80" align="center"></el-table-column> -->
|
||||||
|
<el-table-column :label="$t('mailboxConfig.operation')" width="220" align="center" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="primary" plain icon="el-icon-edit" @click="handleEdit(scope.row)">{{ $t('mailboxConfig.edit') }}</el-button>
|
||||||
|
<el-button size="mini" type="success" plain icon="el-icon-message" @click="handleMailManage(scope.row)">{{ $t('mailboxConfig.mailManage') }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加/编辑 弹窗 -->
|
||||||
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="580px" :close-on-click-modal="false">
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
|
||||||
|
<el-form-item :label="$t('mailboxConfig.journal')" prop="journal_id">
|
||||||
|
<el-select v-model="form.journal_id" :placeholder="$t('mailboxConfig.selectJournal')" style="width: 100%;">
|
||||||
|
<el-option v-for="item in journalList" :key="item.journal_id" :label="item.title" :value="item.journal_id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.account')" prop="account">
|
||||||
|
<el-input v-model="form.account" ></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.password')" prop="password">
|
||||||
|
<el-input v-model="form.password" type="password" show-password autocomplete="new-password"></el-input>
|
||||||
|
<!-- <span class="form-tip">{{ $t('mailboxConfig.passwordTip') }}</span> -->
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.smtpFromName')" prop="smtp_from_name">
|
||||||
|
<el-input v-model="form.smtp_from_name" ></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.smtpHost')" prop="smtp_host">
|
||||||
|
<el-input v-model="form.smtp_host" :placeholder="$t('mailboxConfig.smtpPlaceholder')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.smtpPort')" prop="smtp_port">
|
||||||
|
<el-input v-model="form.smtp_port" :placeholder="$t('mailboxConfig.smtpPortPlaceholder')" style="width: 100%;"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.smtpEncryption')" prop="smtp_encryption">
|
||||||
|
<el-input v-model="form.smtp_encryption" :placeholder="$t('mailboxConfig.smtpEncryptionPlaceholder')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.imapHost')" prop="imap_host">
|
||||||
|
<el-input v-model="form.imap_host" :placeholder="$t('mailboxConfig.imapPlaceholder')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('mailboxConfig.imapPort')" prop="imap_port">
|
||||||
|
<el-input v-model="form.imap_port" :placeholder="$t('mailboxConfig.imapPortPlaceholder')" style="width: 100%;"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">{{ $t('mailboxConfig.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm">{{ $t('mailboxConfig.save') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 期刊邮箱列表:POST api/email_client/getAccounts 参数 journal_id,返回 data[]: j_email_id, journal_id, smtp_host, smtp_port, smtp_user, imap_host, imap_port, daily_limit, today_sent, state, remaining_today 等
|
||||||
|
const API = {
|
||||||
|
getAllJournal: 'api/Journal/getAllJournal',
|
||||||
|
getAccounts: 'api/email_client/getAccounts',
|
||||||
|
addAccount: 'api/email_client/addAccount',
|
||||||
|
updateAccount: 'api/email_client/updateAccount',
|
||||||
|
deleteEmailAccount: 'api/Mail/deleteEmailAccount',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'mailboxConfig',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
query: {
|
||||||
|
journal_id: 0,
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
journalList: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
form: {
|
||||||
|
id: null,
|
||||||
|
journal_id: null,
|
||||||
|
account: '',
|
||||||
|
password: '',
|
||||||
|
smtp_from_name: '',
|
||||||
|
smtp_host: '',
|
||||||
|
smtp_port: '',
|
||||||
|
smtp_encryption: '',
|
||||||
|
imap_host: '',
|
||||||
|
imap_port: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rules() {
|
||||||
|
return {
|
||||||
|
journal_id: [{ required: true, message: this.$t('mailboxConfig.rulesJournal'), trigger: 'change' }],
|
||||||
|
account: [
|
||||||
|
{ required: true, message: this.$t('mailboxConfig.rulesAccount'), trigger: 'blur' },
|
||||||
|
{
|
||||||
|
pattern: /^[-._A-Za-z0-9]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
|
||||||
|
message: this.$t('mailboxConfig.rulesAccountFormat'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
password: [{ required: true, message: this.$t('mailboxConfig.rulesPassword'), trigger: 'blur' }],
|
||||||
|
smtp_from_name: [{ required: true, message: this.$t('mailboxConfig.rulesSmtpFromName'), trigger: 'blur' }],
|
||||||
|
smtp_host: [{ required: true, message: this.$t('mailboxConfig.rulesSmtpHost'), trigger: 'blur' }],
|
||||||
|
smtp_encryption: [{ required: true, message: this.$t('mailboxConfig.rulesSmtpEncryption'), trigger: 'blur' }],
|
||||||
|
imap_host: [{ required: true, message: this.$t('mailboxConfig.rulesImapHost'), trigger: 'blur' }],
|
||||||
|
imap_port: [{ required: true, message: this.$t('mailboxConfig.rulesImapPort'), trigger: 'blur' }],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadJournals();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 期刊下拉框:调用 api/Journal/getAllJournal 获取列表
|
||||||
|
loadJournals() {
|
||||||
|
var self = this;
|
||||||
|
this.$api.post(API.getAllJournal, {}).then(function(res) {
|
||||||
|
var list = [];
|
||||||
|
if (res && res.code === 0 && res.data) {
|
||||||
|
if (Array.isArray(res.data.journals)) {
|
||||||
|
list = res.data.journals;
|
||||||
|
} else if (Array.isArray(res.data)) {
|
||||||
|
list = res.data;
|
||||||
|
}
|
||||||
|
} else if (res && Array.isArray(res)) {
|
||||||
|
list = res;
|
||||||
|
}
|
||||||
|
// 统一为 { journal_id, title },兼容 id/title 等字段
|
||||||
|
self.journalList = list.map(function(item) {
|
||||||
|
return {
|
||||||
|
journal_id: item.journal_id != null ? item.journal_id : item.id,
|
||||||
|
title: item.title || item.name || ''
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (self.journalList.length === 0) {
|
||||||
|
self.journalList = [
|
||||||
|
{ journal_id: 1, title: 'TMR Clinical Research' },
|
||||||
|
{ journal_id: 2, title: 'TMR Theory' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// 默认选第一个期刊并拉取邮箱列表
|
||||||
|
if (self.journalList.length > 0 && (self.query.journal_id === 0 || self.query.journal_id === null || self.query.journal_id === '')) {
|
||||||
|
self.query.journal_id = self.journalList[0].journal_id;
|
||||||
|
self.getList();
|
||||||
|
}
|
||||||
|
}).catch(function() {
|
||||||
|
self.journalList = [
|
||||||
|
{ journal_id: 1, title: 'TMR Clinical Research' },
|
||||||
|
{ journal_id: 2, title: 'TMR Theory' }
|
||||||
|
];
|
||||||
|
if (self.journalList.length > 0) {
|
||||||
|
self.query.journal_id = self.journalList[0].journal_id;
|
||||||
|
self.getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getJournalName(journalId) {
|
||||||
|
var j = this.journalList.find(function(item) { return item.journal_id === journalId; });
|
||||||
|
return j ? j.title : '';
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
var journalId = this.query.journal_id;
|
||||||
|
var params = {};
|
||||||
|
if (journalId !== 0 && journalId !== '' && journalId != null) {
|
||||||
|
params.journal_id = String(journalId);
|
||||||
|
}
|
||||||
|
this.$api.post(API.getAccounts, params).then((res) => {
|
||||||
|
if (res && res.code === 0 && Array.isArray(res.data)) {
|
||||||
|
var list = res.data.map(function(item) {
|
||||||
|
return {
|
||||||
|
id: item.j_email_id,
|
||||||
|
j_email_id: item.j_email_id,
|
||||||
|
journal_id: item.journal_id,
|
||||||
|
journal_name: this.getJournalName(item.journal_id),
|
||||||
|
account: item.smtp_user,
|
||||||
|
smtp_user: item.smtp_user,
|
||||||
|
smtp_host: item.smtp_host,
|
||||||
|
smtp_port: item.smtp_port,
|
||||||
|
smtp_encryption: item.smtp_encryption,
|
||||||
|
smtp_from_name: item.smtp_from_name || '',
|
||||||
|
imap_host: item.imap_host,
|
||||||
|
imap_port: item.imap_port,
|
||||||
|
last_uid: item.last_uid,
|
||||||
|
daily_limit: item.daily_limit,
|
||||||
|
today_sent: item.today_sent,
|
||||||
|
state: item.state,
|
||||||
|
remaining_today: item.remaining_today,
|
||||||
|
};
|
||||||
|
}.bind(this));
|
||||||
|
this.tableData = list;
|
||||||
|
this.total = list.length;
|
||||||
|
} else {
|
||||||
|
this.tableData = [];
|
||||||
|
this.total = 0;
|
||||||
|
}
|
||||||
|
}).catch(function() {
|
||||||
|
this.tableData = [];
|
||||||
|
this.total = 0;
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
handleAdd() {
|
||||||
|
this.dialogTitle = this.$t('mailboxConfig.dialogAdd');
|
||||||
|
this.form = {
|
||||||
|
id: null,
|
||||||
|
journal_id: this.journalList[0] ? this.journalList[0].journal_id : null,
|
||||||
|
account: '',
|
||||||
|
password: '',
|
||||||
|
smtp_from_name: '',
|
||||||
|
smtp_host: '',
|
||||||
|
smtp_port: '',
|
||||||
|
smtp_encryption: '',
|
||||||
|
imap_host: '',
|
||||||
|
imap_port: '',
|
||||||
|
};
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(function() { if (this.$refs.formRef) this.$refs.formRef.clearValidate(); }.bind(this));
|
||||||
|
},
|
||||||
|
handleEdit(row) {
|
||||||
|
this.dialogTitle = this.$t('mailboxConfig.dialogEdit');
|
||||||
|
this.form = {
|
||||||
|
id: row.id,
|
||||||
|
journal_id: row.journal_id,
|
||||||
|
account: row.account || row.smtp_user || '',
|
||||||
|
password: '',
|
||||||
|
smtp_from_name: row.smtp_from_name || '',
|
||||||
|
smtp_host: row.smtp_host || '',
|
||||||
|
smtp_port: row.smtp_port != null && row.smtp_port !== '' ? String(row.smtp_port) : '',
|
||||||
|
smtp_encryption: row.smtp_encryption || '',
|
||||||
|
imap_host: row.imap_host || '',
|
||||||
|
imap_port: row.imap_port != null && row.imap_port !== '' ? String(row.imap_port) : '',
|
||||||
|
};
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(function() { if (this.$refs.formRef) this.$refs.formRef.clearValidate(); }.bind(this));
|
||||||
|
},
|
||||||
|
submitForm() {
|
||||||
|
var self = this;
|
||||||
|
this.$refs.formRef.validate(function(valid) {
|
||||||
|
if (!valid) return;
|
||||||
|
var isEdit = !!self.form.id;
|
||||||
|
var url = isEdit ? API.updateAccount : API.addAccount;
|
||||||
|
var payload = {
|
||||||
|
journal_id: String(self.form.journal_id),
|
||||||
|
smtp_host: String(self.form.smtp_host || ''),
|
||||||
|
smtp_port: String(self.form.smtp_port || ''),
|
||||||
|
smtp_encryption: String(self.form.smtp_encryption || ''),
|
||||||
|
smtp_user: String(self.form.account || ''),
|
||||||
|
smtp_from_name: String(self.form.smtp_from_name || ''),
|
||||||
|
imap_host: String(self.form.imap_host || ''),
|
||||||
|
imap_port: String(self.form.imap_port || ''),
|
||||||
|
};
|
||||||
|
if (isEdit) {
|
||||||
|
payload.j_email_id = String(self.form.id);
|
||||||
|
if (self.form.password) payload.smtp_password = String(self.form.password);
|
||||||
|
} else {
|
||||||
|
payload.smtp_password = String(self.form.password || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.$api.post(url, payload).then(function(res) {
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
self.$message.success(isEdit ? self.$t('mailboxConfig.editSuccess') : self.$t('mailboxConfig.addSuccess'));
|
||||||
|
self.dialogVisible = false;
|
||||||
|
self.getList();
|
||||||
|
} else {
|
||||||
|
self.$message.error((res && res.msg) || (isEdit ? self.$t('mailboxConfig.editFail') : self.$t('mailboxConfig.addFail')));
|
||||||
|
}
|
||||||
|
}).catch(function() {
|
||||||
|
self.$message.success(isEdit ? self.$t('mailboxConfig.editSuccessMock') : self.$t('mailboxConfig.addSuccessMock'));
|
||||||
|
self.dialogVisible = false;
|
||||||
|
self.getList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleMailManage(row) {
|
||||||
|
this.$router.push({
|
||||||
|
path: '/mailboxCollect',
|
||||||
|
query: {
|
||||||
|
journal_id: row.journal_id,
|
||||||
|
j_email_id: row.j_email_id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.handle-box { margin-bottom: 16px; }
|
||||||
|
.filter-form { margin: 0; }
|
||||||
|
.form-tip { font-size: 12px; color: #909399; margin-top: 4px; }
|
||||||
|
</style>
|
||||||
@@ -1,78 +1,143 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="crumbs">
|
<div class="crumbs">
|
||||||
|
<el-button type="text" icon="el-icon-arrow-left" @click="goBackInbox" class="back-inbox-btn">
|
||||||
|
{{ $t('mailboxSend.backToInbox') }}
|
||||||
|
</el-button>
|
||||||
<el-breadcrumb separator="/">
|
<el-breadcrumb separator="/">
|
||||||
<el-breadcrumb-item>
|
<el-breadcrumb-item>
|
||||||
<i class="el-icon-message"></i> Mailbox Send
|
<i class="el-icon-message"></i> {{ $t('mailboxSend.title') }}
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="mail_shuru" style="position: relative;">
|
<div class="mail_shuru" style="position: relative; display: flex; align-items: center;">
|
||||||
<span class="mail_tit">Addressee :</span>
|
<span class="mail_tit">{{ $t('mailboxSend.to') }}</span>
|
||||||
<span class="sel_liby" @click="handleSetLibrary">
|
|
||||||
<i class="el-icon-plus"></i>Select from library
|
<div style="flex: 1; display: flex; flex-wrap: wrap; align-items: center;">
|
||||||
</span>
|
<div class="selected-tags" v-if="queryMail.sendnamelist && queryMail.sendnamelist.length" style="display: inline-block;">
|
||||||
<!-- <el-input v-model="queryMail.sendname" class="mail_inp"></el-input> -->
|
<el-tag
|
||||||
<multi-items-input v-model="queryMail.sendnamelist" placeholder="" separator="" @select="selectHandle" @delete="deleteHandle"
|
v-for="(item, index) in queryMail.sendnamelist"
|
||||||
:selection-only="false" class="dxk_inp" @blur="blueHandle"></multi-items-input>
|
:key="item._uid != null ? item._uid : 'to-' + index"
|
||||||
</div>
|
closable
|
||||||
<div class="mail_shuru">
|
@close="removeRecipient(index)"
|
||||||
<span class="mail_tit">Mail Subject :</span>
|
type="info"
|
||||||
<el-input v-model="queryMail.sendtitle" class="mail_inp"></el-input>
|
size="small"
|
||||||
</div>
|
style="margin-right: 6px;"
|
||||||
<div class="mail_shuru">
|
>
|
||||||
<span class="mail_tit">CC :</span>
|
{{ item.name }}
|
||||||
<el-input v-model="queryMail.sendcc" class="mail_inp"></el-input>
|
</el-tag>
|
||||||
<!-- <multi-items-input v-model="queryMail.sendnamelist" placeholder="" separator="" @select="selectHandle" @delete="deleteHandle"
|
</div>
|
||||||
:selection-only="false" class="dxk_inp" @blur="blueHandle"></multi-items-input> -->
|
|
||||||
</div>
|
|
||||||
<div class="mail_shuru" style="border: 0;">
|
|
||||||
<span class="mail_tit">Attachments :</span>
|
|
||||||
<el-upload class="upload-demo up_newstyle" :action="this.baseUrl + 'api/Article/up_file/type/attr'" accept=".jpg, .png, .rar, .zip"
|
|
||||||
name="atta" :before-upload="beforeupload_atta" :on-error="uperr_atta" :on-success="upSuccess_atta" :limit="30"
|
|
||||||
:on-exceed="alertlimit" :on-remove="removefile_atta" :file-list="fileL_atta">
|
|
||||||
<div class="el-upload__text">
|
|
||||||
<em>Upload</em>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="el-upload__tip" slot="tip">Only compressed files can be uploaded(.rar,.zip)</div> -->
|
|
||||||
</el-upload>
|
|
||||||
|
|
||||||
|
<el-autocomplete
|
||||||
|
ref="autocompleteTo"
|
||||||
|
class="mail_inp"
|
||||||
|
v-model="toInput"
|
||||||
|
:fetch-suggestions="fetchUserSuggestions"
|
||||||
|
:trigger-on-focus="false"
|
||||||
|
placeholder=""
|
||||||
|
@select="handleSelectUser"
|
||||||
|
@blur="handleToBlur"
|
||||||
|
style="width: 200px; flex: 1;"
|
||||||
|
>
|
||||||
|
<!-- <i slot="suffix" class="el-icon-plus" @click="handleSetLibrary" style="cursor: pointer; color: #006699; font-weight: bold; line-height: 40px; font-size: 16px;"></i> -->
|
||||||
|
|
||||||
|
<template slot-scope="{ item }">
|
||||||
|
<div class="name">
|
||||||
|
{{ item.value }} <span style="padding: 4px; color: #ccc;">|</span> {{ item.realname }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="sel_liby" @click="handleSetLibrary" style="position: static; margin-left: 10px;">
|
||||||
|
<i class="el-icon-plus"></i>{{ $t('mailboxSend.selectFromLibrary') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mail_shuru">
|
||||||
|
<span class="mail_tit">{{ $t('mailboxSend.subject') }}</span>
|
||||||
|
<el-input v-model="queryMail.sendtitle" class="mail_inp" ></el-input>
|
||||||
</div>
|
</div>
|
||||||
<p class="sel_moud" @click="handleSetMoudle">
|
<div class="mail_shuru" style="position: relative; display: flex; align-items: center;">
|
||||||
<i class="el-icon-brush"></i>Template selection
|
<span class="mail_tit">{{ $t('mailboxSend.cc') }}</span>
|
||||||
</p>
|
<div style="flex: 1; display: flex; flex-wrap: wrap; align-items: center;">
|
||||||
|
<div class="selected-tags" v-if="ccList && ccList.length" style="display: inline-block;">
|
||||||
|
<el-tag
|
||||||
|
v-for="(item, index) in ccList"
|
||||||
|
:key="item._uid != null ? item._uid : 'cc-' + index"
|
||||||
|
closable
|
||||||
|
@close="removeCc(index)"
|
||||||
|
type="info"
|
||||||
|
size="small"
|
||||||
|
style="margin-right: 6px;"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-autocomplete
|
||||||
|
ref="autocompleteCc"
|
||||||
|
class="mail_inp"
|
||||||
|
v-model="ccInput"
|
||||||
|
:fetch-suggestions="fetchUserSuggestions"
|
||||||
|
:trigger-on-focus="false"
|
||||||
|
placeholder=""
|
||||||
|
@select="handleSelectCc"
|
||||||
|
@blur="handleCcBlur"
|
||||||
|
style="width: 200px; flex: 1;"
|
||||||
|
>
|
||||||
|
<template slot-scope="{ item }">
|
||||||
|
<div class="name">
|
||||||
|
{{ item.value }} <span style="padding: 4px; color: #ccc;">|</span> {{ item.realname }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="margin: 20px 0 0 0;">
|
<div style="margin: 20px 0 0 0;">
|
||||||
<quill-editor ref="myTextEditor" v-model="queryMail.content" :options="editorOption"></quill-editor>
|
<quill-editor ref="myTextEditor" v-model="queryMail.content" :options="editorOption"></quill-editor>
|
||||||
<el-upload class="avatar-uploader-mail" :action="baseUrl+'api/Suggest/upImg'" name="img" :show-file-list="false"
|
<el-upload class="avatar-uploader-mail" :action="baseUrl+'api/Suggest/upImg'" name="img" :show-file-list="false"
|
||||||
:on-success="uploadSuccess">
|
:on-success="uploadSuccess">
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<p style="margin-top: 10px;font-size: 14px;">
|
|
||||||
Sender :<span style="color: #006699;margin: 0 0 0 15px;">{{userMes.realname}} < {{userMes.email}} ></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div style="margin: 20px 0 0 0;">
|
|
||||||
|
|
||||||
<el-button type="primary" icon="el-icon-s-promotion" @click="handleSend" style="">Send</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mail-footer-bar" :style="{ left: footerBarLeft }">
|
||||||
|
<div class="sender-info">
|
||||||
|
<span class="sender-label">{{ $t('mailboxSend.sender') }}</span>
|
||||||
|
<span class="sender-content">
|
||||||
|
{{ userMes.realname }} <{{ userMes.email }}>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="action-buttons">
|
||||||
|
<el-button type="primary" icon="el-icon-s-promotion" :loading="sendLoading" :disabled="sendLoading" @click="handleSend">
|
||||||
|
{{ $t('mailboxSend.send') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button size="medium" :loading="saveDraftLoading" :disabled="saveDraftLoading" @click="handleSaveDraft">{{ $t('mailboxSend.saveDraft') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 选择通讯录 -->
|
<!-- 选择通讯录 -->
|
||||||
<el-dialog title="Select User" :visible.sync="Librarybox" width="900px" :close-on-click-modal="false">
|
<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!=''">Batch
|
<el-button type="primary" style="margin: 0 0 15px 0;" icon="el-icon-plus" @click="mailLiyAll()" v-if="LibrarySelection!=''">
|
||||||
Selection</el-button>
|
{{ $t('mailboxSend.batchSelection') }}
|
||||||
<el-table :data="mail_List" border ref="multipleTable" header-cell-class-name="table-header" @selection-change="handleSelectionChange" empty-text="New messages (0)">
|
</el-button>
|
||||||
|
<el-table :data="mail_List" border ref="multipleTable" header-cell-class-name="table-header" @selection-change="handleSelectionChange" :empty-text="$t('mailboxSend.emptyText')">
|
||||||
<el-table-column type="selection" width="40" align="center" :selectable='checkboxSelect'></el-table-column>
|
<el-table-column type="selection" width="40" align="center" :selectable='checkboxSelect'></el-table-column>
|
||||||
<el-table-column label="Email">
|
<el-table-column :label="$t('mailboxSend.email')">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<b class="el-icon-check" v-if="scope.row.select_mark==1" style="color:#f74c4c;margin-right: 5px;font-weight: bold;"></b>
|
<b class="el-icon-check" v-if="scope.row.select_mark==1" style="color:#f74c4c;margin-right: 5px;font-weight: bold;"></b>
|
||||||
{{scope.row.email}}
|
{{scope.row.email}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="account" label="Account"></el-table-column>
|
<el-table-column prop="account" :label="$t('mailboxSend.account')"></el-table-column>
|
||||||
<el-table-column label=" " width="110" align="center">
|
<el-table-column :label="$t('mailboxSend.operation')" width="110" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button plain type="primary" icon="el-icon-plus" @click="mailLibAdd(scope.row)">Select</el-button>
|
<el-button plain type="primary" icon="el-icon-plus" @click="mailLibAdd(scope.row)">
|
||||||
|
{{ $t('mailboxSend.selectBtn') }}
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -83,22 +148,22 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 选择模板 -->
|
<!-- 选择模板 -->
|
||||||
<el-dialog title="Select template" :visible.sync="Templatebox" width="620px" :close-on-click-modal="false">
|
<el-dialog :title="$t('mailboxSend.selectTemplate')" :visible.sync="Templatebox" width="620px" :close-on-click-modal="false">
|
||||||
<el-form ref="Tempform" :model="TempForm" label-width="225px">
|
<el-form ref="Tempform" :model="TempForm" label-width="225px">
|
||||||
<el-form-item label="Choose Template :">
|
<el-form-item :label="$t('mailboxSend.chooseTemplate')">
|
||||||
<el-select v-model="TempForm.board" placeholder=" " @change="select_tem($event)" style="width: 220px;">
|
<el-select v-model="TempForm.board" :placeholder="$t('mailboxSend.chooseTemplatePlaceholder')" @change="select_tem($event)" style="width: 220px;">
|
||||||
<el-option :key="0" label="None" :value="0"></el-option>
|
<el-option :key="0" :label="$t('mailboxSend.none') " :value="0"></el-option>
|
||||||
<el-option v-for="item in fol_low" :key="item.value" :label="item.label" :value="item.value">
|
<el-option v-for="item in fol_low" :key="item.value" :label="item.label" :value="item.value">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Preview Formatted Document :">
|
<el-form-item :label="$t('mailboxSend.previewTemplate')">
|
||||||
<img src="../../assets/img/img.jpg" alt="" style="width: 250px;">
|
<img src="../../assets/img/img.jpg" alt="" style="width: 250px;">
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="Templatebox = false">Cancel</el-button>
|
<el-button @click="Templatebox = false">{{ $t('mailboxSend.cancel') }}</el-button>
|
||||||
<el-button type="primary" @click="saveTemplate">Save</el-button>
|
<el-button type="primary" @click="saveTemplate">{{ $t('mailboxSend.save') }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,6 +183,7 @@
|
|||||||
// Quill.register('modules/imageResize', ImageResize)
|
// Quill.register('modules/imageResize', ImageResize)
|
||||||
import 'multi-items-input'
|
import 'multi-items-input'
|
||||||
import 'multi-items-input/dist/multi-items-input.css'
|
import 'multi-items-input/dist/multi-items-input.css'
|
||||||
|
import bus from '../common/bus'
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -127,13 +193,7 @@
|
|||||||
userMes: {},
|
userMes: {},
|
||||||
queryMail: {
|
queryMail: {
|
||||||
sendname: [],
|
sendname: [],
|
||||||
sendnamelist: [{
|
sendnamelist: [],
|
||||||
id: null,
|
|
||||||
name: "atr@tmrjournals.com"
|
|
||||||
}, {
|
|
||||||
id: null,
|
|
||||||
name: "tmrtheory@tmrjournals.com"
|
|
||||||
}],
|
|
||||||
sendtitle: '',
|
sendtitle: '',
|
||||||
sendcc: '',
|
sendcc: '',
|
||||||
content: ''
|
content: ''
|
||||||
@@ -158,7 +218,7 @@
|
|||||||
Librarybox: false,
|
Librarybox: false,
|
||||||
link_TotalLibry: 0,
|
link_TotalLibry: 0,
|
||||||
editorOption: {
|
editorOption: {
|
||||||
placeholder: 'Please enter...',
|
placeholder: this.$t('mailboxSend.editorPlaceholder'),
|
||||||
modules: {
|
modules: {
|
||||||
toolbar: {
|
toolbar: {
|
||||||
container: [
|
container: [
|
||||||
@@ -229,46 +289,215 @@
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
toInput: '',
|
||||||
|
toSelecting: false,
|
||||||
|
nextToUid: 1,
|
||||||
|
ccList: [],
|
||||||
|
ccInput: '',
|
||||||
|
ccSelecting: false,
|
||||||
|
nextCcUid: 1,
|
||||||
|
collapseValue: localStorage.getItem('collapse'),
|
||||||
|
sendLoading: false,
|
||||||
|
saveDraftLoading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
footerBarLeft() {
|
||||||
|
const collapsed = this.collapseValue === true || this.collapseValue === 'true';
|
||||||
|
return (collapsed ? 64: 260) + 'px';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
collapseValue: {
|
||||||
|
handler() {
|
||||||
|
// 监听 collapseValue 变化,footerBarLeft 通过 computed 自动更新
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getDate();
|
this.getDate();
|
||||||
this.getLibary();
|
|
||||||
},
|
},
|
||||||
// components: {
|
mounted() {
|
||||||
// quillEditor
|
bus.$on('collapse-content', (msg) => {
|
||||||
// },
|
this.collapseValue = msg;
|
||||||
computed: {
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
bus.$off('collapse-content');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 获取初始用户数据
|
// 返回收件箱(邮箱列表),带上 journal_id 和 j_email_id
|
||||||
getDate() {
|
goBackInbox() {
|
||||||
|
const q = this.$route.query;
|
||||||
|
const query = {};
|
||||||
|
if (q.journal_id) query.journal_id = q.journal_id;
|
||||||
|
if (q.j_email_id) query.j_email_id = q.j_email_id;
|
||||||
|
this.$router.push({
|
||||||
|
path: '/mailboxCollect',
|
||||||
|
query,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 收件人自动补全 - 搜索用户
|
||||||
|
fetchUserSuggestions(queryString, cb) {
|
||||||
|
if (!queryString) {
|
||||||
|
cb([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.$api
|
this.$api
|
||||||
.post('api/User/getUserDetail', {
|
.post('api/Reviewer/researchUser', {
|
||||||
'user_id': localStorage.getItem('U_id')
|
|
||||||
|
keywords: queryString
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code == 0) {
|
if (res && res.code === 0 && res.data && res.data.list) {
|
||||||
this.userMes = res.data.user
|
const list = res.data.list.map(u => ({
|
||||||
|
...u,
|
||||||
|
value: u.email,
|
||||||
|
realname: u.realname || u.username || ''
|
||||||
|
}));
|
||||||
|
cb(list);
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg);
|
cb([]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(() => cb([]));
|
||||||
this.$message.error(err);
|
},
|
||||||
|
// 收件人输入框失焦:输入内容失去焦点则自动成为一条收件人数据(排除点击下拉项时)
|
||||||
|
handleToBlur(e) {
|
||||||
|
// 若失焦是因为点击了下拉建议区域,不执行任何逻辑,让 click 触发 select,否则点击会选不中
|
||||||
|
const related = e && e.relatedTarget;
|
||||||
|
if (related && typeof related.closest === 'function' && related.closest('.el-autocomplete-suggestion')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = (this.toInput || '').trim();
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.toSelecting) {
|
||||||
|
this.toSelecting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!value) return;
|
||||||
|
if (value.indexOf('@') === -1) {
|
||||||
|
this.toInput = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const exists = (this.queryMail.sendnamelist || []).some(item => item.name === value);
|
||||||
|
if (!exists) {
|
||||||
|
this.queryMail.sendnamelist.push({
|
||||||
|
id: null,
|
||||||
|
name: value,
|
||||||
|
_uid: this.nextToUid++,
|
||||||
|
});
|
||||||
|
this.queryMail.sendname = (this.queryMail.sendnamelist || []).map(i => i.name);
|
||||||
|
}
|
||||||
|
this.toInput = '';
|
||||||
|
}, 150);
|
||||||
|
},
|
||||||
|
// 选中某个用户作为收件人
|
||||||
|
handleSelectUser(user) {
|
||||||
|
this.toSelecting = true;
|
||||||
|
if (!user || !user.email) return;
|
||||||
|
const email = user.email;
|
||||||
|
// 去重
|
||||||
|
const exists = (this.queryMail.sendnamelist || []).some(item => item.name === email);
|
||||||
|
if (!exists) {
|
||||||
|
this.queryMail.sendnamelist.push({
|
||||||
|
id: user.user_id || user.id || null,
|
||||||
|
name: email,
|
||||||
|
_uid: this.nextToUid++,
|
||||||
|
});
|
||||||
|
// 同步简单数组
|
||||||
|
this.queryMail.sendname = (this.queryMail.sendnamelist || []).map(i => i.name);
|
||||||
|
}
|
||||||
|
// 清空输入框,便于继续输入下一个
|
||||||
|
this.toInput = '';
|
||||||
|
},
|
||||||
|
// 删除已选收件人
|
||||||
|
removeRecipient(index) {
|
||||||
|
if (index < 0) return;
|
||||||
|
this.queryMail.sendnamelist.splice(index, 1);
|
||||||
|
this.queryMail.sendname = (this.queryMail.sendnamelist || []).map(i => i.name);
|
||||||
|
},
|
||||||
|
// CC 输入框失焦:与 To 相同逻辑,输入失去焦点则自动成为一条数据(排除点击下拉项时)
|
||||||
|
handleCcBlur(e) {
|
||||||
|
const related = e && e.relatedTarget;
|
||||||
|
if (related && typeof related.closest === 'function' && related.closest('.el-autocomplete-suggestion')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = (this.ccInput || '').trim();
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.ccSelecting) {
|
||||||
|
this.ccSelecting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!value) return;
|
||||||
|
if (value.indexOf('@') === -1) {
|
||||||
|
this.ccInput = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const exists = (this.ccList || []).some(item => item.name === value);
|
||||||
|
if (!exists) {
|
||||||
|
this.ccList.push({
|
||||||
|
id: null,
|
||||||
|
name: value,
|
||||||
|
_uid: this.nextCcUid++,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.ccInput = '';
|
||||||
|
}, 150);
|
||||||
|
},
|
||||||
|
// 选中某个用户作为 CC(与 To 相同逻辑)
|
||||||
|
handleSelectCc(user) {
|
||||||
|
this.ccSelecting = true;
|
||||||
|
if (!user || !user.email) return;
|
||||||
|
const email = user.email;
|
||||||
|
const exists = (this.ccList || []).some(item => item.name === email);
|
||||||
|
if (!exists) {
|
||||||
|
this.ccList.push({
|
||||||
|
id: user.user_id || user.id || null,
|
||||||
|
name: email,
|
||||||
|
_uid: this.nextCcUid++,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.ccInput = '';
|
||||||
|
},
|
||||||
|
// 删除已选 CC
|
||||||
|
removeCc(index) {
|
||||||
|
if (index < 0) return;
|
||||||
|
this.ccList.splice(index, 1);
|
||||||
|
},
|
||||||
|
// 根据路由 j_email_id 获取发件邮箱信息,用于展示发件人
|
||||||
|
getDate() {
|
||||||
|
const jEmailId = this.$route.query.j_email_id;
|
||||||
|
if (!jEmailId) {
|
||||||
|
this.userMes = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$api
|
||||||
|
.post('api/email_client/getOneEmail', { j_email_id: jEmailId })
|
||||||
|
.then(res => {
|
||||||
|
if (res && res.code === 0 && res.data && res.data.email) {
|
||||||
|
const email = res.data.email;
|
||||||
|
this.userMes = {
|
||||||
|
realname: email.smtp_from_name || email.smtp_user || '',
|
||||||
|
email: email.smtp_user || '',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.userMes = {};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.userMes = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
// 获取通讯录数据
|
// 获取通讯录数据
|
||||||
getLibary() {
|
getLibary() {
|
||||||
this.$api
|
this.$api
|
||||||
.post('api/User/getAllUser', this.queryLibry)
|
.post('api/Reviewer/researchUser', {keywords: this.queryLibry.username})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
this.mail_List = res.data.users;
|
this.mail_List = res.data.list;
|
||||||
this.link_TotalLibry = res.data.count || 0;
|
this.link_TotalLibry = res.data.list.length || 0;
|
||||||
for (let i = 0; i < this.mail_List.length; i++) {
|
for (let i = 0; i < this.mail_List.length; i++) {
|
||||||
this.mail_List[i].select_mark = 0
|
this.mail_List[i].select_mark = 0
|
||||||
for (let j = 0; j < this.queryMail.sendnamelist.length; j++) {
|
for (let j = 0; j < this.queryMail.sendnamelist.length; j++) {
|
||||||
@@ -286,9 +515,60 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// 发送邮件
|
// 发送邮件:api/email_client/sendOne,to_email 为多邮箱字符串拼接(逗号分隔),发送成功后关闭当前页并跳转收件箱
|
||||||
handleSend() {
|
handleSend() {
|
||||||
console.log(this.queryMail)
|
if (this.sendLoading) return;
|
||||||
|
const toList = (this.queryMail.sendnamelist || []).map((item) => item.name).filter(Boolean);
|
||||||
|
if (!toList.length) {
|
||||||
|
this.$message.warning(this.$t('mailboxSend.validateTo'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.queryMail.sendtitle) {
|
||||||
|
this.$message.warning(this.$t('mailboxSend.validateSubject'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const journalId = this.$route.query.journal_id;
|
||||||
|
if (!journalId) {
|
||||||
|
this.$message.warning(this.$t('mailboxSend.needAccount'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendLoading = true;
|
||||||
|
const params = {
|
||||||
|
journal_id: journalId,
|
||||||
|
to_email: toList.join(','),
|
||||||
|
subject: this.queryMail.sendtitle,
|
||||||
|
content: this.queryMail.content || '',
|
||||||
|
};
|
||||||
|
const self = this;
|
||||||
|
this.$api.post('api/email_client/sendOne', params).then((res) => {
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
self.$message.success(self.$t('mailboxSend.sendSuccess'));
|
||||||
|
self.queryMail.sendnamelist = [];
|
||||||
|
self.queryMail.sendtitle = '';
|
||||||
|
self.queryMail.sendcc = '';
|
||||||
|
self.ccList = [];
|
||||||
|
self.queryMail.content = '';
|
||||||
|
self.fileL_atta = [];
|
||||||
|
self.goBackInbox();
|
||||||
|
} else {
|
||||||
|
self.$message.error((res && res.msg) || self.$t('mailboxSend.sendFail'));
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
self.$message.error(self.$t('mailboxSend.sendFail'));
|
||||||
|
}).finally(() => {
|
||||||
|
self.sendLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 保存草稿(防抖:请求中禁用按钮)
|
||||||
|
handleSaveDraft() {
|
||||||
|
if (this.saveDraftLoading) return;
|
||||||
|
this.saveDraftLoading = true;
|
||||||
|
// TODO: 调用保存草稿接口,此处仅防抖占位
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.saveDraftLoading = false;
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// 选择通讯录-弹出框
|
// 选择通讯录-弹出框
|
||||||
@@ -320,7 +600,8 @@
|
|||||||
this.queryMail.sendname.push(e.email)
|
this.queryMail.sendname.push(e.email)
|
||||||
this.queryMail.sendnamelist.push({
|
this.queryMail.sendnamelist.push({
|
||||||
id: null,
|
id: null,
|
||||||
name: e.email
|
name: e.email,
|
||||||
|
_uid: this.nextToUid++,
|
||||||
})
|
})
|
||||||
this.getLibary();
|
this.getLibary();
|
||||||
},
|
},
|
||||||
@@ -331,7 +612,8 @@
|
|||||||
this.queryMail.sendname.push(this.LibrarySelection[i].email)
|
this.queryMail.sendname.push(this.LibrarySelection[i].email)
|
||||||
this.queryMail.sendnamelist.push({
|
this.queryMail.sendnamelist.push({
|
||||||
id: null,
|
id: null,
|
||||||
name: this.LibrarySelection[i].email
|
name: this.LibrarySelection[i].email,
|
||||||
|
_uid: this.nextToUid++,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.getLibary();
|
this.getLibary();
|
||||||
@@ -433,7 +715,16 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
|
.crumbs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.back-inbox-btn {
|
||||||
|
margin-right: 12px;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
.mail_shuru {
|
.mail_shuru {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 0 5px 0;
|
padding: 0 0 5px 0;
|
||||||
@@ -442,18 +733,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mail_tit {
|
.mail_tit {
|
||||||
width: 90px;
|
width: 60px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mail_inp {
|
.mail_inp {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 550px;
|
width: 100%;
|
||||||
margin: 0 15px 0 0;
|
margin: 0 15px 0 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mail_inp .el-input__inner {
|
.mail_inp ::v-deep .el-input__inner {
|
||||||
border: 1px solid #fff !important;
|
border: 1px solid #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,14 +754,13 @@
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.up_newstyle .el-upload--text {
|
.up_newstyle ::v-deep .el-upload--text {
|
||||||
background-color: #006699;
|
background-color: #006699;
|
||||||
border: 1px solid #006699;
|
border: 1px solid #006699;
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
/* margin-left: 10px; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.up_newstyle .el-upload__text em {
|
.up_newstyle ::v-deep .el-upload__text em {
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@@ -545,8 +835,75 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-uploader-mail .el-upload--text {
|
.avatar-uploader-mail ::v-deep .el-upload--text {
|
||||||
height: 0 !important;
|
height: 0 !important;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
/* 让输入框的边框在平时不可见,只有在交互时体现,对齐邮件系统风格 */
|
||||||
|
.mail_inp ::v-deep .el-input__inner {
|
||||||
|
border: none !important;
|
||||||
|
border-bottom: 0px solid #fff !important;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mail_inp ::v-deep .el-input__suffix {
|
||||||
|
right: 5px;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mail_inp ::v-deep .el-input__suffix:hover {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整容器对齐 */
|
||||||
|
.mail_shuru {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start; /* 考虑到多行标签,对齐顶部 */
|
||||||
|
min-height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
/* 底部操作栏容器 */
|
||||||
|
.mail-footer-bar {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: #f8f9fa; /* 浅灰色背景,类似图1 */
|
||||||
|
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; /* 保持你代码中的蓝色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮组样式 */
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.mail-footer-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1026,11 +1026,20 @@ export default new Router({
|
|||||||
title: 'Mailbox send'
|
title: 'Mailbox send'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/mailboxConfig', //邮箱系统-邮箱配置管理
|
||||||
|
component: () => import('../components/page/mailboxConfig'),
|
||||||
|
meta: {
|
||||||
|
title: 'Mailbox config',
|
||||||
|
titleKey: 'sidebar.mailboxConfig'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/mailboxCollect', //邮箱系统-收邮件列表
|
path: '/mailboxCollect', //邮箱系统-收邮件列表
|
||||||
component: () => import('../components/page/mailboxCollect'),
|
component: () => import('../components/page/mailboxCollect'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Mailbox list'
|
title: 'Mailbox list',
|
||||||
|
titleKey: 'sidebar.mailboxCollect'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user