新增注册码、草稿箱、权限拦截邮件、发件菜单隐藏
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="account-box">
|
||||
<div class="head-opt" >
|
||||
<Icon v-perm="'account:add'" class="icon" icon="ion:add-outline" width="23" height="23" @click="add" />
|
||||
<Icon class="icon" icon="ion:reload" width="18" height="18" @click="refresh" />
|
||||
<Icon v-perm="'account:add'" class="icon add" icon="ion:add-outline" width="23" height="23" @click="add" />
|
||||
<Icon class="icon refresh" icon="ion:reload" width="18" height="18" @click="refresh" />
|
||||
</div>
|
||||
<el-scrollbar class="scrollbar">
|
||||
<div v-infinite-scroll="getAccountList" :infinite-scroll-distance="600" :infinite-scroll-immediate="false">
|
||||
@@ -16,11 +16,12 @@
|
||||
</div>
|
||||
<div class="settings" @click.stop>
|
||||
<Icon icon="streamline-ultimate-color:copy-paste-1" width="19" height="19" @click.stop="copyAccount(item.email)"/>
|
||||
<el-dropdown>
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" />
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" v-if="showNullSetting(item)" />
|
||||
<el-dropdown v-else>
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" />
|
||||
<template #dropdown >
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openSetName(item)">改名</el-dropdown-item>
|
||||
<el-dropdown-menu >
|
||||
<el-dropdown-item v-if="hasPerm('email:send')" @click="openSetName(item)">改名</el-dropdown-item>
|
||||
<el-dropdown-item v-if="item.accountId !== userStore.user.accountId && hasPerm('account:delete')" @click="remove(item)">删除</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@@ -217,6 +218,10 @@ function openSetName (accountItem) {
|
||||
setNameShow.value = true
|
||||
}
|
||||
|
||||
function showNullSetting(item) {
|
||||
return !hasPerm('email:send') && !(item.accountId !== userStore.user.accountId && hasPerm('account:delete'))
|
||||
}
|
||||
|
||||
function itemBg(accountId) {
|
||||
return accountStore.currentAccountId === accountId ? 'item-choose' : ''
|
||||
}
|
||||
@@ -388,8 +393,16 @@ path[fill="#ffdda1"] {
|
||||
.icon{
|
||||
cursor: pointer;
|
||||
}
|
||||
.icon:nth-child(2) {
|
||||
margin-left: 15px;
|
||||
.refresh {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.add {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.head-opt:not(.add) .refresh {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
.scrollbar {
|
||||
|
||||
@@ -11,11 +11,16 @@
|
||||
<Icon icon="hugeicons:mailbox-01" width="20" height="20" />
|
||||
<span class="menu-name" style="margin-left: 21px">收件箱</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'send'})" index="send"
|
||||
<el-menu-item @click="router.push({name: 'send'})" index="send" v-perm="'email:send'"
|
||||
:class="route.meta.name === 'send' ? 'choose-item' : ''">
|
||||
<Icon icon="cil:send" width="20" height="20" />
|
||||
<span class="menu-name" style="margin-left: 21px">已发送</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'draft'})" index="draft" v-perm="'email:send'"
|
||||
:class="route.meta.name === 'draft' ? 'choose-item' : ''">
|
||||
<Icon icon="ep:document" width="19" height="19" />
|
||||
<span class="menu-name" style="margin-left: 22px">草稿箱</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'star'})" index="star"
|
||||
:class="route.meta.name === 'star' ? 'choose-item' : ''">
|
||||
<Icon icon="solar:star-line-duotone" width="20" height="20" />
|
||||
@@ -46,9 +51,14 @@
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'role'})" index="setting" v-perm="'role:query'"
|
||||
:class="route.meta.name === 'role' ? 'choose-item' : ''">
|
||||
<Icon icon="hugeicons:key-02" width="22" height="22" />
|
||||
<Icon icon="fluent:lock-closed-16-regular" width="22" height="22" />
|
||||
<span class="menu-name" style="margin-left: 20px">权限控制</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'reg-key'})" index="reg-key" v-perm="'reg-key:query'"
|
||||
:class="route.meta.name === 'reg-key' ? 'choose-item' : ''">
|
||||
<Icon icon="fluent:fingerprint-20-filled" width="22" height="22" />
|
||||
<span class="menu-name" style="margin-left: 20px">注册密钥</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item @click="router.push({name: 'sys-setting'})" index="sys-setting" v-perm="'setting:query'"
|
||||
:class="route.meta.name === 'sys-setting' ? 'choose-item' : ''">
|
||||
<Icon icon="eos-icons:system-ok-outlined" width="18" height="18" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="header" :class="!hasPerm('email:send') ? 'not-send' : ''">
|
||||
<div class="header-btn">
|
||||
<hanburger @click="changeAside"></hanburger>
|
||||
<span class="breadcrumb-item">{{ route.meta.title }}</span>
|
||||
</div>
|
||||
<div class="writer-box" @click="openSend">
|
||||
<div v-perm="'email:send'" class="writer-box" @click="openSend">
|
||||
<div class="writer" >
|
||||
<Icon icon="material-symbols:edit-outline-sharp" width="22" height="22" />
|
||||
</div>
|
||||
@@ -95,10 +95,14 @@ const sendType = computed(() => {
|
||||
return '无权限'
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendCount === 0) {
|
||||
if (!userStore.user.role.sendCount) {
|
||||
return '无限制'
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendCount < 0) {
|
||||
return '无次数'
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendType === 'day') {
|
||||
return '每天'
|
||||
}
|
||||
@@ -116,6 +120,11 @@ const sendCount = computed(() => {
|
||||
if (!userStore.user.role.sendCount) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendCount < 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return userStore.user.sendCount + '/' + userStore.user.role.sendCount
|
||||
})
|
||||
|
||||
@@ -248,6 +257,10 @@ function full() {
|
||||
grid-template-columns: auto auto 1fr;
|
||||
}
|
||||
|
||||
.header.not-send {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.writer-box {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div :class="accountShow && hasPerm('account:query') ? 'block-show' : 'block-hide'" @click="uiStore.accountShow = false"></div>
|
||||
<account :class="accountShow && hasPerm('account:query') ? 'show' : 'hide'" />
|
||||
<router-view class="main-view" v-slot="{ Component,route }">
|
||||
<keep-alive :include="['email','sys-email','send','sys-setting','star','user','role','analysis']">
|
||||
<keep-alive :include="['email','sys-email','send','sys-setting','star','user','role','analysis','reg-key','draft']">
|
||||
<component :is="Component" :key="route.name"/>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="send" v-show="show" @click="close">
|
||||
<div class="send" v-show="show">
|
||||
<div class="write-box" @click.stop>
|
||||
<div class="title">
|
||||
<div class="title-left">
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<el-input-tag @add-tag="addTagChange" tag-type="primary" size="default" v-model="form.receiveEmail" placeholder="多邮个箱用, 分开 example1.com,example2.com" >
|
||||
<el-input-tag @add-tag="addTagChange" tag-type="primary" size="default" v-model="form.receiveEmail" placeholder="多个邮箱用, 分开 example1.com,example2.com" >
|
||||
<template #prefix>
|
||||
<div class="item-title">收件人 </div>
|
||||
</template>
|
||||
@@ -56,7 +56,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import tinyEditor from '@/components/tiny-editor/index.vue'
|
||||
import {h, onMounted, onUnmounted, reactive, ref} from "vue";
|
||||
import {h, nextTick, onMounted, onUnmounted, reactive, ref, toRaw} from "vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import {emailSend} from "@/request/email.js";
|
||||
@@ -66,14 +66,19 @@ import {useEmailStore} from "@/store/email.js";
|
||||
import {fileToBase64, formatBytes} from "@/utils/file-utils.js";
|
||||
import {getIconByName} from "@/utils/icon-utils.js";
|
||||
import sendPercent from "@/components/send-percent/index.vue"
|
||||
import {formatDetailDate} from "@/utils/day.js";
|
||||
import {formatDetailDate, fromNow} from "@/utils/day.js";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import {userDraftStore} from "@/store/draft.js";
|
||||
import db from "@/db/db.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
openReply
|
||||
openReply,
|
||||
openDraft
|
||||
})
|
||||
|
||||
const draftStore = userDraftStore()
|
||||
const settingStore = useSettingStore()
|
||||
const emailStore = useEmailStore();
|
||||
const accountStore = useAccountStore()
|
||||
@@ -84,6 +89,12 @@ const percent = ref(0)
|
||||
let percentMessage = null
|
||||
let sending = false
|
||||
const defValue = ref('')
|
||||
const backReply = reactive({
|
||||
receiveEmail: [],
|
||||
subject: '',
|
||||
content: '',
|
||||
sendType: ''
|
||||
})
|
||||
const form = reactive({
|
||||
sendEmail: '',
|
||||
receiveEmail: [],
|
||||
@@ -95,7 +106,8 @@ const form = reactive({
|
||||
sendType: '',
|
||||
text: '',
|
||||
emailId: 0,
|
||||
attachments: []
|
||||
attachments: [],
|
||||
draftId: null,
|
||||
})
|
||||
|
||||
function addTagChange(val) {
|
||||
@@ -110,10 +122,8 @@ function addTagChange(val) {
|
||||
if (isEmail(email) && !form.receiveEmail.includes(email)) {
|
||||
form.receiveEmail.push(email)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
function checkDistribute() {
|
||||
@@ -155,7 +165,6 @@ function chooseFile() {
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const content = await fileToBase64(file)
|
||||
form.attachments.push({content, filename, size, contentType})
|
||||
}
|
||||
@@ -217,7 +226,9 @@ async function sendEmail() {
|
||||
})
|
||||
|
||||
sending = true
|
||||
close()
|
||||
|
||||
show.value = false
|
||||
|
||||
emailSend(form, (e) => {
|
||||
percent.value = Math.round((e.loaded * 98) / e.total)
|
||||
}).then(emailList => {
|
||||
@@ -225,15 +236,25 @@ async function sendEmail() {
|
||||
emailList.forEach(item => {
|
||||
emailStore.sendScroll?.addItem(item)
|
||||
})
|
||||
resetForm()
|
||||
show.value = false
|
||||
|
||||
ElNotification({
|
||||
title: '邮件已发送',
|
||||
type: "success",
|
||||
message: h('span', { style: 'color: teal' }, email.subject),
|
||||
position: 'bottom-right'
|
||||
})
|
||||
|
||||
userStore.refreshUserInfo();
|
||||
|
||||
if (form.draftId) {
|
||||
form.subject = ''
|
||||
form.content = ''
|
||||
form.receiveEmail = []
|
||||
draftStore.setDraft = {...toRaw(form)}
|
||||
}
|
||||
|
||||
resetForm()
|
||||
show.value = false
|
||||
}).catch((e) => {
|
||||
ElNotification({
|
||||
title: '发送失败',
|
||||
@@ -241,6 +262,7 @@ async function sendEmail() {
|
||||
message: h('span', { style: 'color: teal' }, e.message),
|
||||
position: 'bottom-right'
|
||||
})
|
||||
show.value = true
|
||||
}).finally(() => {
|
||||
percentMessage.close()
|
||||
percent.value = 0
|
||||
@@ -255,8 +277,13 @@ function resetForm() {
|
||||
form.content = ''
|
||||
form.manyType = null
|
||||
form.attachments = []
|
||||
form.sendType = null
|
||||
form.sendType = ''
|
||||
form.emailId = 0
|
||||
form.draftId = null
|
||||
backReply.content = ''
|
||||
backReply.subject = ''
|
||||
backReply.receiveEmail = []
|
||||
backReply.sendType = ''
|
||||
editor.value.clearEditor()
|
||||
}
|
||||
|
||||
@@ -291,7 +318,13 @@ function openReply(email) {
|
||||
</article>
|
||||
</blockquote>`
|
||||
open()
|
||||
console.log(defValue.value)
|
||||
|
||||
nextTick(() => {
|
||||
backReply.content = editor.value.getContent()
|
||||
backReply.subject = form.subject
|
||||
backReply.receiveEmail = form.receiveEmail
|
||||
backReply.sendType = form.sendType
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
@@ -299,7 +332,6 @@ function openReply(email) {
|
||||
function formatImage(content) {
|
||||
content = content || '';
|
||||
const domain = settingStore.settings.r2Domain;
|
||||
console.log(content)
|
||||
return content.replace(/{{domain}}/g, domain + '/');
|
||||
}
|
||||
|
||||
@@ -317,6 +349,14 @@ function open() {
|
||||
editor.value.focus()
|
||||
}
|
||||
|
||||
function openDraft(draft) {
|
||||
Object.assign(form,{...draft})
|
||||
defValue.value = ''
|
||||
setTimeout(() => defValue.value = form.content)
|
||||
show.value = true;
|
||||
editor.value.focus()
|
||||
}
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
close()
|
||||
@@ -332,7 +372,52 @@ onUnmounted(() => {
|
||||
});
|
||||
|
||||
function close() {
|
||||
show.value = false;
|
||||
|
||||
if (form.draftId) {
|
||||
draftStore.setDraft = {...toRaw(form)}
|
||||
show.value = false
|
||||
resetForm()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(form.content || form.subject || form.receiveEmail.length > 0)) {
|
||||
show.value = false
|
||||
resetForm()
|
||||
return;
|
||||
}
|
||||
|
||||
if (backReply.sendType === 'reply') {
|
||||
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]
|
||||
if (subjectFlag && contentFlag && receiveFlag) {
|
||||
resetForm();
|
||||
close()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ElMessageBox.confirm('是否保存草稿?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true
|
||||
}).then( async () => {
|
||||
const formData = {...toRaw(form)}
|
||||
delete formData.draftId
|
||||
delete formData.attachments
|
||||
formData.createTime = dayjs().utc().format('YYYY-MM-DD HH:mm:ss');
|
||||
const draftId = await db.value.draft.add({...formData})
|
||||
db.value.att.add({draftId,attachments: toRaw(form.attachments)})
|
||||
draftStore.refreshList ++
|
||||
show.value = false
|
||||
}).catch((action) => {
|
||||
if (action === 'cancel') {
|
||||
show.value = false
|
||||
resetForm()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user