mirror of
https://github.com/eoao/cloud-mail.git
synced 2026-05-06 21:51:48 +08:00
新增邮件转发
This commit is contained in:
@@ -949,6 +949,11 @@ function loadData() {
|
||||
@media (max-width: 1366px) {
|
||||
height: 83px;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
/* 触屏 */
|
||||
user-select: none;
|
||||
}
|
||||
&.all-email {
|
||||
height: 65px;
|
||||
@media (max-width: 1366px) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<script setup>
|
||||
import {ref, onMounted, onBeforeUnmount, watch, nextTick, shallowRef, defineEmits, computed} from 'vue';
|
||||
import loading from "@/components/loading/index.vue";
|
||||
import {compressImage} from "@/utils/file-utils.js";
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {useUiStore} from '@/store/ui.js'
|
||||
import {useSettingStore} from '@/store/setting.js'
|
||||
@@ -140,7 +139,6 @@ function initEditor() {
|
||||
|
||||
input.addEventListener('change', async (e) => {
|
||||
let file = e.target.files[0];
|
||||
file = await compressImage(file);
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const id = 'blobid' + (new Date()).getTime();
|
||||
|
||||
@@ -184,6 +184,7 @@ const en = {
|
||||
changeUserName: 'Change Username',
|
||||
send: 'Send',
|
||||
reply: 'Reply',
|
||||
forward: 'Forward',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel',
|
||||
delEmailConfirm: 'Confirm deleting this email?',
|
||||
@@ -228,7 +229,6 @@ const en = {
|
||||
banRestore: 'Confirm banning {msg}?',
|
||||
logOut: 'Sign out',
|
||||
clearContentConfirm: 'Are you sure to clear all content?',
|
||||
attLimitMsg: 'Attachment size limit: 28MB',
|
||||
emptyRecipientMsg: 'Recipient email cannot be empty',
|
||||
emptySubjectMsg: 'Subject cannot be empty',
|
||||
emptyContentMsg: 'Content cannot be empty',
|
||||
|
||||
@@ -184,6 +184,7 @@ const zh = {
|
||||
changeUserName: '修改用户名',
|
||||
send: '发送',
|
||||
reply: '回复',
|
||||
forward: '转发',
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
delEmailConfirm: '确认删除该邮件吗?',
|
||||
@@ -228,7 +229,6 @@ const zh = {
|
||||
banRestore: '确认禁用 {msg} 吗?',
|
||||
logOut: '退出',
|
||||
clearContentConfirm: '确定要清空所有内容吗?',
|
||||
attLimitMsg: '附件不能超过28MB',
|
||||
emptyRecipientMsg: '收件人邮箱地址不能为空',
|
||||
emptySubjectMsg: '主题不能为空',
|
||||
emptyContentMsg: '邮件正文不能为空',
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="sendEmail" v-if="form.sendType === 'reply'">{{ $t('reply') }}</el-button>
|
||||
<el-button type="primary" @click="sendEmail" v-else-if="form.sendType === 'forward'">{{ $t('forward') }}</el-button>
|
||||
<el-button type="primary" @click="sendEmail" v-else>{{ $t('send') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,10 +115,11 @@ import router from "@/router/index.js";
|
||||
defineExpose({
|
||||
open,
|
||||
openReply,
|
||||
openForward,
|
||||
openDraft
|
||||
})
|
||||
|
||||
const {t} = useI18n()
|
||||
const {t, locale} = useI18n()
|
||||
const writerStore = useWriterStore();
|
||||
const draftStore = userDraftStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -207,7 +209,6 @@ function selectChange(value) {
|
||||
|
||||
function selectStatusChange(status) {
|
||||
selectStatus = status
|
||||
ruleEmailsInputDesc.value = status ? '' : ruleEmailsInputDesc.value = t('ruleEmailsInputDesc')
|
||||
}
|
||||
|
||||
const openSelect = () => {
|
||||
@@ -264,25 +265,23 @@ function delAtt(index) {
|
||||
function chooseFile() {
|
||||
const doc = document.createElement("input")
|
||||
doc.setAttribute("type", "file")
|
||||
doc.multiple = true;
|
||||
doc.click()
|
||||
doc.onchange = async (e) => {
|
||||
|
||||
const file = e.target.files[0]
|
||||
const size = file.size
|
||||
const filename = file.name
|
||||
const contentType = file.type
|
||||
const fileList = e.target.files;
|
||||
|
||||
for (const file of fileList) {
|
||||
|
||||
const size = file.size
|
||||
const filename = file.name
|
||||
const contentType = file.type
|
||||
|
||||
const content = await fileToBase64(file)
|
||||
form.attachments.push({content, filename, size, contentType})
|
||||
|
||||
const TotalSize = form.attachments.reduce((acc, item) => acc + item.size, 0);
|
||||
if ((TotalSize + size) > 29360128) {
|
||||
ElMessage({
|
||||
message: t('attLimitMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
const content = await fileToBase64(file)
|
||||
form.attachments.push({content, filename, size, contentType})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,6 +426,35 @@ function focusChange() {
|
||||
if (selectStatus) openSelect()
|
||||
}
|
||||
|
||||
function openForward(email) {
|
||||
resetForm();
|
||||
|
||||
email.subject = email.subject || ''
|
||||
|
||||
form.subject = email.subject
|
||||
form.sendType = 'forward'
|
||||
form.emailId = email.emailId
|
||||
|
||||
defValue.value = ''
|
||||
|
||||
setTimeout(() => {
|
||||
defValue.value = `
|
||||
<articl class="mceNonEditable" >
|
||||
${formatImage(email.content) || `<pre style="font-family: inherit;word-break: break-word;white-space: pre-wrap;margin: 0">${email.text}</pre>`}
|
||||
</article>
|
||||
`
|
||||
open()
|
||||
|
||||
nextTick(() => {
|
||||
backReply.content = editor.value.getContent()
|
||||
backReply.subject = form.subject
|
||||
backReply.receiveEmail = form.receiveEmail
|
||||
backReply.sendType = form.sendType
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function openReply(email) {
|
||||
|
||||
resetForm();
|
||||
@@ -527,7 +555,7 @@ function close() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backReply.sendType === 'reply') {
|
||||
if (backReply.sendType === 'reply' || backReply.sendType === 'forward') {
|
||||
let subjectFlag = form.subject === backReply.subject
|
||||
let contentFlag = editor.value.getContent() === backReply.content
|
||||
let receiveFlag = form.receiveEmail.length === 1 && form.receiveEmail[0] === backReply.receiveEmail[0]
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
<Icon class="icon" @click="changeStar" v-if="email.isStar" icon="fluent-color:star-16" width="20" height="20"/>
|
||||
<Icon class="icon" @click="changeStar" v-else icon="solar:star-line-duotone" width="18" height="18"/>
|
||||
</span>
|
||||
<Icon class="icon" v-if="emailStore.contentData.showReply" v-perm="'email:send'" @click="openReply" icon="la:reply" width="20" height="20" />
|
||||
<Icon class="icon" v-if="emailStore.contentData.showReply" v-perm="'email:send'" @click="openReply" icon="la:reply" width="21" height="21" />
|
||||
<Icon class="icon" v-if="emailStore.contentData.showReply" v-perm="'email:send'" @click="openForward" icon="tabler:location-share" width="19" height="19" />
|
||||
</div>
|
||||
<div></div>
|
||||
<el-scrollbar class="scrollbar">
|
||||
@@ -121,6 +122,10 @@ function openReply() {
|
||||
uiStore.writerRef.openReply(email)
|
||||
}
|
||||
|
||||
function openForward() {
|
||||
uiStore.writerRef.openForward(email)
|
||||
}
|
||||
|
||||
function toMessage(message) {
|
||||
return message ? JSON.parse(message).message : '';
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty" v-if="regKeyData.length === 0">
|
||||
<el-empty v-if="!regKeyFirst" :image-size="isMobile ? 120 : 0" :description="$t('noCodeFound')"/>
|
||||
<el-empty v-if="!regKeyFirst" :image-size="isMobile ? 120 : null" :description="$t('noCodeFound')"/>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<el-dialog v-model="showAdd" :title="$t('addRegKey')">
|
||||
|
||||
@@ -1273,6 +1273,13 @@ function adjustWidth() {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
@media (pointer: coarse) {
|
||||
/* 触屏 */
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table th.el-table__cell>.cell.highlight) {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ const en = {
|
||||
noResendToken: 'Resend API token not configured',
|
||||
sendEmailNotCurUser: 'Sender email does not belong to current user',
|
||||
notExistEmailReply: 'Mail does not exist and cannot be replied to',
|
||||
imageAttLimit: 'The maximum number of image attachments is 10',
|
||||
attLimit: 'The maximum number of attachments is 10.',
|
||||
pwdLengthLimit: 'Password length exceeds the limit',
|
||||
emailLengthLimit: 'Email length exceeds the limit',
|
||||
minEmailPrefix: 'Email must be at least {{msg}} characters',
|
||||
|
||||
@@ -23,6 +23,8 @@ const zh = {
|
||||
noResendToken: 'resend密钥未配置',
|
||||
sendEmailNotCurUser: '发件人邮箱非当前用户所有',
|
||||
notExistEmailReply: '邮件不存在无法回复',
|
||||
imageAttLimit: '图片不能超过10个',
|
||||
attLimit: '附件不能超过10个',
|
||||
pwdLengthLimit: '密码长度超出限制',
|
||||
emailLengthLimit: '邮箱长度超出限制',
|
||||
minEmailPrefix: '邮箱名至少{{msg}}位',
|
||||
|
||||
@@ -179,6 +179,7 @@ const attService = {
|
||||
cacheControl: `max-age=259200`,
|
||||
contentDisposition: `inline;filename=${attData.filename}`
|
||||
});
|
||||
delete attData.buff;
|
||||
}
|
||||
|
||||
await orm(c).insert(att).values(attDataList).run();
|
||||
|
||||
@@ -331,11 +331,17 @@ const emailService = {
|
||||
|
||||
//保存内嵌附件
|
||||
if (imageDataList.length > 0) {
|
||||
if (imageDataList.length > 10) {
|
||||
throw new BizError(t('imageAttLimit'));
|
||||
}
|
||||
await attService.saveArticleAtt(c, imageDataList, userId, accountId, emailResult.emailId);
|
||||
}
|
||||
|
||||
//保存普通附件
|
||||
if (attachments?.length > 0) {
|
||||
if (attachments.length > 10) {
|
||||
throw new BizError(t('attLimit'));
|
||||
}
|
||||
await attService.saveSendAtt(c, attachments, userId, accountId, emailResult.emailId);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,10 @@ const settingService = {
|
||||
|
||||
|
||||
if (!showSiteKey) {
|
||||
settingRow.siteKey = settingRow.siteKey ? `${settingRow.siteKey.slice(0, 12)}******` : null;
|
||||
settingRow.siteKey = settingRow.siteKey ? `${settingRow.siteKey.slice(0, 6)}******` : null;
|
||||
}
|
||||
|
||||
settingRow.secretKey = settingRow.secretKey ? `${settingRow.secretKey.slice(0, 12)}******` : null;
|
||||
settingRow.secretKey = settingRow.secretKey ? `${settingRow.secretKey.slice(0, 6)}******` : null;
|
||||
|
||||
Object.keys(settingRow.resendTokens).forEach(key => {
|
||||
settingRow.resendTokens[key] = `${settingRow.resendTokens[key].slice(0, 12)}******`;
|
||||
|
||||
Reference in New Issue
Block a user