新增深色模式
This commit is contained in:
@@ -144,7 +144,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading" :class="loading ? 'loading-show' : 'loading-hide'">
|
||||
<div class="loading" :class="loading ? 'loading-show' : 'loading-hide'" :style="firstLoad ? 'background: transparent' : ''">
|
||||
<Loading/>
|
||||
</div>
|
||||
<div class="follow-loading" v-if="followLoading">
|
||||
@@ -535,12 +535,11 @@ function loadData() {
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.email-container {
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
color: #2e2e2e;
|
||||
color: var(--el-text-color-primary);
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -582,7 +581,7 @@ function loadData() {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background: var(--loadding-background);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
@@ -607,7 +606,7 @@ function loadData() {
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
justify-content: space-between;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
box-shadow: var(--header-actions-border);
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
@@ -621,7 +620,7 @@ function loadData() {
|
||||
column-gap: 10px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
color: rgba(25, 41, 59, 0.4);
|
||||
color: var(--email-scroll-content-color);
|
||||
|
||||
.user, .account {
|
||||
overflow: hidden;
|
||||
@@ -683,8 +682,8 @@ function loadData() {
|
||||
}
|
||||
|
||||
.email-sender {
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
font-weight: bold;;
|
||||
color: var(--el-text-color-primary);
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
|
||||
@@ -714,7 +713,6 @@ function loadData() {
|
||||
.phone-time {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #333 !important;
|
||||
@media (min-width: 1200px) {
|
||||
display: none;
|
||||
}
|
||||
@@ -722,7 +720,6 @@ function loadData() {
|
||||
}
|
||||
|
||||
.email-text {
|
||||
color: #333;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
@media (max-width: 1199px) {
|
||||
@@ -743,7 +740,7 @@ function loadData() {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
padding-left: 10px;
|
||||
color: rgba(25, 41, 59, 0.4);
|
||||
color: var(--email-scroll-content-color);
|
||||
@media (max-width: 1199px) {
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
@@ -760,14 +757,13 @@ function loadData() {
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
align-items: center;
|
||||
color: #333;
|
||||
@media (max-width: 1199px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #F2F6FC;
|
||||
background-color: var(--email-hover-background);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@@ -815,9 +811,7 @@ function loadData() {
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
padding: 3px 15px;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
|
||||
|
||||
box-shadow: var(--header-actions-border);
|
||||
.header-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -825,6 +819,7 @@ function loadData() {
|
||||
column-gap: 18px;
|
||||
row-gap: 8px;
|
||||
padding-left: 2px;
|
||||
color: var(--el-text-color-primary);;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
@@ -832,7 +827,7 @@ function loadData() {
|
||||
grid-template-columns: auto auto;
|
||||
align-items: start;
|
||||
height: 100%;
|
||||
|
||||
color: var(--el-text-color-primary);;
|
||||
.email-count {
|
||||
white-space: nowrap;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -57,6 +57,7 @@ function updateContent() {
|
||||
}
|
||||
|
||||
.shadow-content {
|
||||
background: #FFFFFF;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
min-width: 100%;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<template>
|
||||
<div class="editor-box" :class="showLoading ? 'editor-box-loading' : ''">
|
||||
<loading class="loading" v-if="showLoading" />
|
||||
<loading class="loading" v-if="showLoading"/>
|
||||
<textarea v-else style="outline: none" :id="editorId" ref="editorRef"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted, onBeforeUnmount, watch, nextTick, shallowRef, defineEmits} from 'vue';
|
||||
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 {useI18n} from 'vue-i18n'
|
||||
import {useUiStore} from '@/store/ui.js'
|
||||
import {useSettingStore} from '@/store/setting.js'
|
||||
|
||||
defineExpose({
|
||||
clearEditor,
|
||||
focus,
|
||||
@@ -28,12 +31,14 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
|
||||
const { locale } = useI18n()
|
||||
const {locale} = useI18n()
|
||||
const emit = defineEmits(['change']);
|
||||
const editor = shallowRef(null);
|
||||
const isInitialized = ref(false);
|
||||
const editorRef = ref(null);
|
||||
const showLoading = ref(false);
|
||||
const uiStore = useUiStore();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
onMounted(() => {
|
||||
initTinyMCE();
|
||||
@@ -49,6 +54,23 @@ watch(() => props.defValue, (newValue) => {
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => [uiStore.dark, settingStore.lang], () => {
|
||||
destroyEditor();
|
||||
initEditor();
|
||||
});
|
||||
|
||||
const language = computed(() => {
|
||||
if (locale.value === 'zh') {
|
||||
return 'zh_CN'
|
||||
}
|
||||
|
||||
if (locale.value === 'zhTW') {
|
||||
return 'zh_TW'
|
||||
}
|
||||
|
||||
return 'en'
|
||||
})
|
||||
|
||||
function clearEditor() {
|
||||
if (editor.value) {
|
||||
editor.value.setContent('');
|
||||
@@ -75,6 +97,12 @@ function initEditor() {
|
||||
height: "100%",
|
||||
auto_focus: true,
|
||||
forced_root_block: 'div',
|
||||
skin: `${uiStore.dark ? 'oxide-dark' : 'oxide'}`,
|
||||
content_css: `/tinymce/css/index.css,${uiStore.dark ? 'dark' : 'default'}`,
|
||||
content_style: `:root {
|
||||
--scrollbar-track-color: ${uiStore.dark ? '#141414' : '#FFFFFF'};
|
||||
--scrollbar-thumb-color: ${uiStore.dark ? '#8D9095' : '#A8ABB2'};
|
||||
}`,
|
||||
plugins: 'link image advlist lists emoticons fullscreen table preview code',
|
||||
toolbar: 'bold emoticons forecolor backcolor italic fontsize | alignleft aligncenter alignright alignjustify | outdent indent | bullist numlist | link image | table code preview fullscreen',
|
||||
toolbar_mode: 'scrolling',
|
||||
@@ -83,37 +111,11 @@ function initEditor() {
|
||||
},
|
||||
font_size_formats: '8px 10px 12px 14px 16px 18px 24px 36px',
|
||||
emoticons_search: false,
|
||||
language: locale.value === 'zh' ? 'zh_CN' : 'en',
|
||||
language_url: '/tinymce/langs/zh_CN.js',
|
||||
language: language.value,
|
||||
language_load: true,
|
||||
menubar: false,
|
||||
license_key: 'gpl',
|
||||
noneditable_class: 'mceNonEditable',
|
||||
content_style: ` .tox-dialog__body-content { margin: 0 !important; }
|
||||
img { max-width: 100% !important; height: auto !important; }
|
||||
body {margin: 10px 8px 0 5px !important; font-family: 'HarmonyOS'; font-size: 14px;}
|
||||
@media (pointer: fine) and (hover: hover) {
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.mce-item-table:not([border]), .mce-item-table:not([border]) caption, .mce-item-table:not([border]) td, .mce-item-table:not([border]) th, .mce-item-table[border="0"], .mce-item-table[border="0"] caption, .mce-item-table[border="0"] td, .mce-item-table[border="0"] th, table[style*="border-width: 0px"], table[style*="border-width: 0px"] caption, table[style*="border-width: 0px"] td, table[style*="border-width: 0px"] th {
|
||||
border: none;
|
||||
}
|
||||
`,
|
||||
setup: (ed) => {
|
||||
editor.value = ed;
|
||||
ed.on('init', () => {
|
||||
@@ -122,7 +124,7 @@ function initEditor() {
|
||||
});
|
||||
ed.on('input change', () => {
|
||||
const content = ed.getContent();
|
||||
const text = ed.getContent({ format: 'text' });
|
||||
const text = ed.getContent({format: 'text'});
|
||||
emit('change', content, text);
|
||||
});
|
||||
},
|
||||
@@ -133,7 +135,7 @@ function initEditor() {
|
||||
image_description: false,
|
||||
link_title: false,
|
||||
dialog_type: 'none',
|
||||
file_picker_callback: (callback, value, meta) => {
|
||||
file_picker_callback: (callback, value, meta) => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'file');
|
||||
input.setAttribute('accept', 'image/*');
|
||||
@@ -144,12 +146,12 @@ function initEditor() {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const id = 'blobid' + (new Date()).getTime();
|
||||
const blobCache = tinymce.activeEditor.editorUpload.blobCache;
|
||||
const blobCache = tinymce.activeEditor.editorUpload.blobCache;
|
||||
const base64 = reader.result.split(',')[1];
|
||||
const blobInfo = blobCache.create(id, file, base64);
|
||||
blobCache.add(blobInfo);
|
||||
|
||||
callback(blobInfo.blobUri(), { title: file.name });
|
||||
callback(blobInfo.blobUri(), {title: file.name});
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
@@ -202,7 +204,7 @@ function destroyEditor() {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
padding-bottom: 15px;
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
@media (max-width: 767px) {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
@@ -228,4 +230,4 @@ function destroyEditor() {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import {useAccountStore} from "@/store/account.js";
|
||||
import {useUiStore} from "@/store/ui.js";
|
||||
import {loginUserInfo} from "@/request/my.js";
|
||||
import {permsToRouter} from "@/perm/perm.js";
|
||||
import router from "@/router";
|
||||
@@ -24,6 +25,10 @@ export async function init() {
|
||||
|
||||
i18n.global.locale.value = settingStore.lang
|
||||
|
||||
const uiStore = useUiStore();
|
||||
let doc = document.querySelector("html");
|
||||
doc.setAttribute('class', uiStore.dark ? 'dark' : '');
|
||||
|
||||
let setting = null;
|
||||
|
||||
if (token) {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<el-skeleton v-for="i in 3" :key="i" animated>
|
||||
<template #template>
|
||||
<el-card class="item">
|
||||
<el-skeleton-item variant="p" style="width: 70%; height: 20px; margin-bottom: 20px"/>
|
||||
<el-skeleton-item variant="p" style="width: 70%; height: 20px; margin-bottom: 25px"/>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
@@ -92,7 +92,7 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<div>
|
||||
<span>{{ addForm.suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
@@ -428,7 +428,7 @@ path[fill="#ffdda1"] {
|
||||
.account-box {
|
||||
|
||||
border-right: 1px solid var(--el-border-color) !important;
|
||||
background-color: #FFF;
|
||||
background-color: var(--el-bg-color);
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -436,7 +436,7 @@ path[fill="#ffdda1"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 38px;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
box-shadow: var(--header-actions-border);
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
@@ -487,7 +487,7 @@ path[fill="#ffdda1"] {
|
||||
}
|
||||
|
||||
.item {
|
||||
background-color: #fff;
|
||||
background-color: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
padding: 12px 10px;
|
||||
margin-bottom: 10px;
|
||||
@@ -532,7 +532,7 @@ path[fill="#ffdda1"] {
|
||||
}
|
||||
|
||||
.item-choose {
|
||||
background: var(--el-color-primary-light-8);
|
||||
background: var(--choose-account-background);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,7 +545,7 @@ path[fill="#ffdda1"] {
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0 !important;
|
||||
padding-left: 8px !important;
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
:deep(.el-dialog) {
|
||||
@@ -567,7 +567,7 @@ path[fill="#ffdda1"] {
|
||||
|
||||
:deep(.el-pagination .el-select) {
|
||||
width: 100px;
|
||||
background: #FFF;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.add-email-turnstile {
|
||||
|
||||
@@ -143,15 +143,15 @@ const route = useRoute();
|
||||
|
||||
|
||||
:deep(.el-scrollbar__wrap--hidden-default ) {
|
||||
background: #001529 !important;
|
||||
background: var(--aside-backgound) !important;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item) {
|
||||
background: #001529;
|
||||
background: var(--aside-backgound);
|
||||
}
|
||||
|
||||
:deep(.el-menu) {
|
||||
background: #001529;
|
||||
background: var(--aside-backgound);
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
@@ -163,22 +163,11 @@ const route = useRoute();
|
||||
}
|
||||
|
||||
:deep(.el-divider__text) {
|
||||
background: #001529;
|
||||
background: var(--aside-backgound);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.scroll {
|
||||
|
||||
}
|
||||
|
||||
.github {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
a{
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<span class="breadcrumb-item">{{ $t(route.meta.title) }}</span>
|
||||
</div>
|
||||
<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 class="writer">
|
||||
<Icon icon="material-symbols:edit-outline-sharp" width="22" height="22"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-dropdown>
|
||||
<div class="translate icon-item">
|
||||
<Icon icon="carbon:ibm-watson-language-translator" />
|
||||
<Icon icon="carbon:ibm-watson-language-translator"/>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
@@ -21,15 +21,21 @@
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<div class="notice icon-item" @click="openNotice">
|
||||
<Icon icon="streamline-plump:announcement-megaphone" />
|
||||
<div v-if="uiStore.dark" class="sun-icon icon-item" @click="openDark($event)">
|
||||
<Icon icon="mingcute:sun-fill"/>
|
||||
</div>
|
||||
<el-dropdown :teleported="false" popper-class="detail-dropdown" >
|
||||
<div v-else class="dark-icon icon-item" @click="openDark($event)">
|
||||
<Icon icon="solar:moon-linear"/>
|
||||
</div>
|
||||
<div class="notice icon-item" @click="openNotice">
|
||||
<Icon icon="streamline-plump:announcement-megaphone"/>
|
||||
</div>
|
||||
<el-dropdown :teleported="false" popper-class="detail-dropdown">
|
||||
<div class="avatar">
|
||||
<div class="avatar-text">
|
||||
<div>{{ formatName(userStore.user.email) }}</div>
|
||||
</div>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="24" height="24" />
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="24" height="24"/>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<div class="user-details">
|
||||
@@ -37,35 +43,38 @@
|
||||
{{ formatName(userStore.user.email) }}
|
||||
</div>
|
||||
<div class="user-name">
|
||||
{{userStore.user.name}}
|
||||
{{ userStore.user.name }}
|
||||
</div>
|
||||
<div class="detail-email" @click="copyEmail(userStore.user.email)">
|
||||
{{ userStore.user.email }}
|
||||
</div>
|
||||
<div class="detail-user-type">
|
||||
<el-tag >{{$t(userStore.user.role.name)}}</el-tag>
|
||||
<el-tag>{{ $t(userStore.user.role.name) }}</el-tag>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div>
|
||||
<span style="margin-right: 10px">{{$t('sendCount')}}</span>
|
||||
<span style="margin-right: 10px">{{$t('accountCount')}}</span>
|
||||
<span style="margin-right: 10px">{{ $t('sendCount') }}</span>
|
||||
<span style="margin-right: 10px">{{ $t('accountCount') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span v-if="sendCount" style="margin-right: 5px" >{{ sendCount }}</span>
|
||||
<el-tag v-if="!hasPerm('email:send')" >{{sendType}}</el-tag>
|
||||
<el-tag v-else >{{sendType}}</el-tag>
|
||||
<span v-if="sendCount" style="margin-right: 5px">{{ sendCount }}</span>
|
||||
<el-tag v-if="!hasPerm('email:send')">{{ sendType }}</el-tag>
|
||||
<el-tag v-else>{{ sendType }}</el-tag>
|
||||
</div>
|
||||
<div>
|
||||
<el-tag v-if="settingStore.settings.manyEmail || settingStore.settings.addEmail" >{{$t('disabled')}}</el-tag>
|
||||
<span v-else-if="accountCount && hasPerm('account:add')" style="margin-right: 5px">{{ $t('totalUserAccount',{msg: accountCount}) }}</span>
|
||||
<el-tag v-else-if="!accountCount && hasPerm('account:add')" >{{$t('unlimited')}}</el-tag>
|
||||
<el-tag v-else-if="!hasPerm('account:add')" >{{$t('unauthorized')}}</el-tag>
|
||||
<el-tag v-if="settingStore.settings.manyEmail || settingStore.settings.addEmail">
|
||||
{{ $t('disabled') }}
|
||||
</el-tag>
|
||||
<span v-else-if="accountCount && hasPerm('account:add')"
|
||||
style="margin-right: 5px">{{ $t('totalUserAccount', {msg: accountCount}) }}</span>
|
||||
<el-tag v-else-if="!accountCount && hasPerm('account:add')">{{ $t('unlimited') }}</el-tag>
|
||||
<el-tag v-else-if="!hasPerm('account:add')">{{ $t('unauthorized') }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="logout">
|
||||
<el-button type="primary" :loading="logoutLoading" @click="clickLogout">{{$t('logOut')}}</el-button>
|
||||
<el-button type="primary" :loading="logoutLoading" @click="clickLogout">{{ $t('logOut') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -77,17 +86,18 @@
|
||||
<script setup>
|
||||
import router from "@/router";
|
||||
import hanburger from '@/components/hamburger/index.vue'
|
||||
import { logout} from "@/request/login.js";
|
||||
import {logout} from "@/request/login.js";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {useUiStore} from "@/store/ui.js";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import { useRoute } from "vue-router";
|
||||
import {useRoute} from "vue-router";
|
||||
import {computed, ref} from "vue";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import { hasPerm } from "@/perm/perm.js"
|
||||
import {hasPerm} from "@/perm/perm.js"
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {setExtend} from "@/utils/day.js"
|
||||
|
||||
const { t } = useI18n();
|
||||
const {t} = useI18n();
|
||||
const route = useRoute();
|
||||
const settingStore = useSettingStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -174,6 +184,44 @@ function openNotice() {
|
||||
uiStore.showNotice()
|
||||
}
|
||||
|
||||
function openDark(e) {
|
||||
|
||||
const nextIsDark = !uiStore.dark
|
||||
const root = document.documentElement
|
||||
|
||||
if (!document.startViewTransition) {
|
||||
switchDark(nextIsDark, root);
|
||||
return
|
||||
}
|
||||
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
|
||||
const maxX = Math.max(x, window.innerWidth - x)
|
||||
const maxY = Math.max(y, window.innerHeight - y)
|
||||
const endRadius = Math.hypot(maxX, maxY)
|
||||
|
||||
// 标记切换目标,供 CSS 选择器使用
|
||||
root.setAttribute('data-theme-to', nextIsDark ? 'dark' : 'light')
|
||||
root.style.setProperty('--vt-x', `${x}px`)
|
||||
root.style.setProperty('--vt-y', `${y}px`)
|
||||
root.style.setProperty('--vt-end-radius', `${endRadius + 10}px`)
|
||||
|
||||
const transition = document.startViewTransition(() => {
|
||||
switchDark(nextIsDark, root);
|
||||
})
|
||||
|
||||
transition.finished.finally(() => {
|
||||
// 清理标记
|
||||
root.removeAttribute('data-theme-to')
|
||||
})
|
||||
}
|
||||
|
||||
function switchDark(nextIsDark, root) {
|
||||
root.setAttribute('class', nextIsDark ? 'dark' : '')
|
||||
uiStore.dark = nextIsDark
|
||||
}
|
||||
|
||||
function openSend() {
|
||||
uiStore.writerRef.open()
|
||||
}
|
||||
@@ -197,7 +245,11 @@ function formatName(email) {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.detail-dropdown {
|
||||
color: var(--el-text-color-primary) !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.breadcrumb-item {
|
||||
@@ -213,10 +265,10 @@ function formatName(email) {
|
||||
.user-details {
|
||||
width: 250px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
justify-items: center;
|
||||
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
@@ -228,6 +280,7 @@ function formatName(email) {
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.detail-user-type {
|
||||
margin-top: 10px;
|
||||
}
|
||||
@@ -237,16 +290,19 @@ function formatName(email) {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
margin-top: 10px;
|
||||
>div:first-child {
|
||||
|
||||
> div:first-child {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
>div:last-child {
|
||||
|
||||
> div:last-child {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
text-align: center;
|
||||
>div {
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -261,26 +317,31 @@ function formatName(email) {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
color: #5c5958;
|
||||
color: var(--regular-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logout {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.el-button {
|
||||
border-radius: 6px;
|
||||
height: 28px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.details-avatar {
|
||||
margin-top: 20px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border: 1px solid #ccc;
|
||||
background: var(--el-bg-color);
|
||||
color: var(--el-text-color-primary);
|
||||
border: 1px solid var(--dark-border);
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -290,7 +351,6 @@ function formatName(email) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header {
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
@@ -310,8 +370,9 @@ function formatName(email) {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 5px;
|
||||
|
||||
.writer {
|
||||
width: 34px;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
color: #ffffff;
|
||||
@@ -320,6 +381,7 @@ function formatName(email) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.writer-text {
|
||||
margin-left: 15px;
|
||||
font-size: 14px;
|
||||
@@ -334,8 +396,6 @@ function formatName(email) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
@@ -343,6 +403,7 @@ function formatName(email) {
|
||||
@media (max-width: 767px) {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
align-self: center;
|
||||
width: 30px;
|
||||
@@ -355,7 +416,7 @@ function formatName(email) {
|
||||
}
|
||||
|
||||
.icon-item:hover {
|
||||
background: #F0F2F5;
|
||||
background: var(--base-fill);
|
||||
}
|
||||
|
||||
.notice {
|
||||
@@ -363,6 +424,14 @@ function formatName(email) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.dark-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.sun-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.translate {
|
||||
padding-top: 2px;
|
||||
font-size: 21px;
|
||||
@@ -372,14 +441,17 @@ function formatName(email) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
.avatar-text {
|
||||
background: var(--el-bg-color);
|
||||
color: var(--el-text-color-primary);
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--dark-border);
|
||||
}
|
||||
|
||||
.setting-icon {
|
||||
@@ -391,6 +463,7 @@ function formatName(email) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.el-tooltip__trigger:first-child:focus-visible {
|
||||
outline: unset;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.aside-show {
|
||||
-webkit-box-shadow: 3px 0 5px rgba(0, 21, 41, .35);
|
||||
box-shadow: 3px 0 5px rgba(0, 21, 41, 0.35);
|
||||
-webkit-box-shadow: var(--aside-right-border);
|
||||
box-shadow: var(--aside-right-border);
|
||||
transform: translateX(0);
|
||||
transition: all 100ms ease;
|
||||
z-index: 101;
|
||||
@@ -71,7 +71,7 @@ onBeforeUnmount(() => {
|
||||
left: 0;
|
||||
z-index: 101;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
@@ -101,8 +101,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.el-header {
|
||||
background: #FFFFFF;
|
||||
border-bottom: solid 1px var(--el-menu-border-color);
|
||||
background: var(--el-bg-color);
|
||||
border-bottom: solid 1px var(--el-border-color);
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ const handleResize = () => {
|
||||
|
||||
|
||||
.main-view {
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ const handleResize = () => {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
.tag {
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ function close() {
|
||||
justify-content: center;
|
||||
|
||||
.write-box {
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
width: min(1200px,calc(100% - 80px));
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
|
||||
@@ -5,6 +5,7 @@ import './style.css';
|
||||
import { init } from '@/init/init.js';
|
||||
import { createPinia } from 'pinia';
|
||||
import piniaPersistedState from 'pinia-plugin-persistedstate';
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
import perm from "@/perm/perm.js";
|
||||
const pinia = createPinia().use(piniaPersistedState)
|
||||
import i18n from "@/i18n/index.js";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {createRouter, createWebHistory} from 'vue-router'
|
||||
import {useUiStore} from "@/store/ui.js";
|
||||
import {replace} from "lodash-es";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -91,7 +90,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
|
||||
if (token && to.name === 'login') {
|
||||
next(from.path)
|
||||
return next(from.path)
|
||||
}
|
||||
|
||||
next()
|
||||
|
||||
@@ -10,6 +10,7 @@ export const useUiStore = defineStore('ui', {
|
||||
changePreview: 0,
|
||||
previewData: {},
|
||||
key: 0,
|
||||
dark: false,
|
||||
asideCount: {
|
||||
email: 0,
|
||||
send: 0,
|
||||
@@ -26,6 +27,6 @@ export const useUiStore = defineStore('ui', {
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
pick: ['accountShow'],
|
||||
pick: ['accountShow','dark'],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -15,26 +14,20 @@ html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'HarmonyOS';
|
||||
src: url('@/assets/fonts/HarmonyOS_Sans_SC_Regular.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
:deep(.el-input__inner:focus) {
|
||||
background-color: transparent !important;
|
||||
border-color: #dcdfe6 !important;
|
||||
}
|
||||
|
||||
.el-table thead th {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'HarmonyOS', -apple-system, BlinkMacSystemFont,
|
||||
'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
||||
'Noto Sans', sans-serif;
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
color: var(--el-text-color-primary);
|
||||
background-color: var(--el-bg-color);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -64,6 +57,27 @@ button, input, select, textarea {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.message-bottom {
|
||||
top: auto !important;
|
||||
bottom: 20px !important;
|
||||
|
||||
.el-icon {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-input-group__append, .el-input-group__prepend {
|
||||
color: var(--el-text-color-primary) !important;
|
||||
}
|
||||
|
||||
.tox .tox-dialog__iframe.tox-dialog__iframe--opaque {
|
||||
background-color: var(--el-bg-color) !important;
|
||||
}
|
||||
|
||||
.tox .tox-dialog--width-lg {
|
||||
height: 850px !important;
|
||||
@media (max-width: 1024px) {
|
||||
@@ -89,10 +103,6 @@ button, input, select, textarea {
|
||||
max-height: 220px !important;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--el-color-primary: #1890ff;
|
||||
--el-color-primary-dark-2: #1064c0;
|
||||
@@ -100,17 +110,65 @@ button, input, select, textarea {
|
||||
--el-color-primary-light-5: #69c0ff;
|
||||
--el-color-primary-light-7: #91d5ff;
|
||||
--el-color-primary-light-9: #e6f7ff;
|
||||
--el-text-color-regular: #333;
|
||||
|
||||
--extra-light-fill: #FAFCFF;
|
||||
--light-ill: #F5F7FA;
|
||||
--light-border: #E4E7ED;
|
||||
--header-actions-border: inset 0 -1px 0 0 var(--el-border-color-lighter);
|
||||
--aside-backgound: #001529;
|
||||
--loadding-background: rgba(255, 255, 255, 0.8);
|
||||
--dark-border: #CDD0D6;
|
||||
--base-fill: #F0F2F5;
|
||||
--regular-text-color: #585d69;
|
||||
--light-border-color: #e7e9ec;
|
||||
--aside-right-border: 3px 0 5px rgba(0, 21, 41, .35);
|
||||
--choose-account-background: var(--el-color-primary-light-8);
|
||||
--el-text-color-regular: var(--el-text-color-primary);
|
||||
--email-scroll-content-color: rgba(25, 41, 59, 0.4);
|
||||
--email-hover-background: #F2F6FC;
|
||||
--login-border: none;
|
||||
--form-desc-color: #71717a;
|
||||
--login-switch-color: #006be6;
|
||||
--scrollbar-track-color: #A8ABB2;
|
||||
--base-border-color: #DCDFE6;
|
||||
--secondary-text-color: #909399;
|
||||
--message-block-color: rgba(0, 0, 0, 0);
|
||||
--vt-x: 50%;
|
||||
--vt-y: 50%;
|
||||
--vt-duration: 520ms;
|
||||
--vt-easing: ease-out;
|
||||
}
|
||||
|
||||
.message-bottom {
|
||||
top: auto !important;
|
||||
bottom: 20px !important;
|
||||
.el-icon {
|
||||
display: none !important;
|
||||
}
|
||||
.dark {
|
||||
--extra-light-fill: #191919;
|
||||
--light-ill: #262727;
|
||||
--light-border: #414243;
|
||||
--aside-backgound: #141414;
|
||||
--header-actions-border: inset 0 -1px 0 0 var(--el-border-color-lighter);
|
||||
--loadding-background: rgba(0, 0, 0, 0.3);
|
||||
--dark-border: #636466;
|
||||
--base-fill: #303030;
|
||||
--regular-text-color: #bfbdbc;
|
||||
--light-border-color: #414243;
|
||||
--aside-right-border: 3px 0 5px #0A0A0A;
|
||||
--choose-account-background: #39393A;
|
||||
--email-scroll-content-color: rgba(255, 255, 255, 0.3);
|
||||
--email-hover-background: #1D1E1F;
|
||||
--login-border: none;
|
||||
--form-desc-color: #8D9095;
|
||||
--login-switch-color: rgb(102, 177, 255);
|
||||
--scrollbar-track-color: #8D9095;
|
||||
--base-border-color: #4C4D4F;
|
||||
--secondary-text-color: #A3A6AD;
|
||||
--message-block-color: rgba(30, 30, 30, 0.2);
|
||||
--el-border-color: #414243 !important;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
--el-input-text-color: var(--el-text-color-primary) !important;
|
||||
}
|
||||
|
||||
|
||||
@media (pointer: fine) and (hover: hover) {
|
||||
/* 整个滚动条 */
|
||||
::-webkit-scrollbar {
|
||||
@@ -120,14 +178,54 @@ button, input, select, textarea {
|
||||
|
||||
/* 滚动条轨道 */
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* 滚动条滑块 */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
background: var(--scrollbar-track-color);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 视图过渡,基于径向剪裁 */
|
||||
html.dark,
|
||||
html:not(.dark) {
|
||||
view-transition-name: root;
|
||||
}
|
||||
|
||||
::view-transition-old(root),
|
||||
::view-transition-new(root) {
|
||||
animation: none;
|
||||
mix-blend-mode: normal;
|
||||
}
|
||||
|
||||
/* 层级控制,确保对应方向动画在上层可见 */
|
||||
html[data-theme-to="dark"]::view-transition-new(root) { z-index: 2; }
|
||||
html[data-theme-to="dark"]::view-transition-old(root) { z-index: 1; }
|
||||
html[data-theme-to="light"]::view-transition-old(root) { z-index: 2; }
|
||||
html[data-theme-to="light"]::view-transition-new(root) { z-index: 1; }
|
||||
|
||||
/* 切到暗色:新视图从点击点向外扩散 */
|
||||
html[data-theme-to="dark"]::view-transition-new(root) {
|
||||
clip-path: circle(0px at var(--vt-x) var(--vt-y));
|
||||
animation: vt-radial-in var(--vt-duration) var(--vt-easing) forwards;
|
||||
}
|
||||
|
||||
/* 切到浅色:旧视图向点击点收缩 */
|
||||
html[data-theme-to="light"]::view-transition-old(root) {
|
||||
clip-path: circle(var(--vt-end-radius, 0px) at var(--vt-x) var(--vt-y));
|
||||
animation: vt-radial-out var(--vt-duration) var(--vt-easing) forwards;
|
||||
}
|
||||
|
||||
@keyframes vt-radial-in {
|
||||
from { clip-path: circle(0px at var(--vt-x) var(--vt-y)); }
|
||||
to { clip-path: circle(var(--vt-end-radius, 0px) at var(--vt-x) var(--vt-y)); }
|
||||
}
|
||||
|
||||
@keyframes vt-radial-out {
|
||||
from { clip-path: circle(var(--vt-end-radius, 0px) at var(--vt-x) var(--vt-y)); }
|
||||
to { clip-path: circle(0px at var(--vt-x) var(--vt-y)); }
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-option key="1" :label="$t('user')" :value="'user'"/>
|
||||
<el-option key="2" :label="$t('selectEmail')" :value="'account'"/>
|
||||
</el-select>
|
||||
<div style="color: #333;display: flex;">
|
||||
<div class="search-type">
|
||||
<span>{{ selectTitle }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
@@ -194,6 +194,11 @@ function getEmailList(emailId, size) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-type {
|
||||
display: flex;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
:deep(.header-actions) {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<script setup>
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {useTransition} from "@vueuse/core";
|
||||
import {defineOptions, onActivated, onDeactivated, onMounted, reactive, ref, watch} from "vue";
|
||||
import {defineOptions, onActivated, onDeactivated, onMounted, reactive, ref, watch, computed} from "vue";
|
||||
import echarts from "@/echarts/index.js";
|
||||
import dayjs from "dayjs";
|
||||
import {analysisEcharts} from "@/request/analysis.js";
|
||||
@@ -185,6 +185,17 @@ const emailColumnData = {
|
||||
daysData: []
|
||||
}
|
||||
|
||||
const topic = computed(() => ({
|
||||
color: uiStore.dark ? '#E5EAF3' : '#303133',
|
||||
background: uiStore.dark ? '#141414' : '#FFFFFF',
|
||||
borderColor: uiStore.dark ? '#141414' : '#FFFFFF',
|
||||
scaleLineColor: uiStore.dark ? '#636466' : '#CDD0D6',
|
||||
crossColor: uiStore.dark ? '#8D9095' : '#A8ABB2',
|
||||
axisColor: uiStore.dark ? '#A3A6AD' : '#909399',
|
||||
splitLineColor: uiStore.dark ? '#58585B' : '#D4D7DE',
|
||||
gaugeSplitLine: uiStore.dark ? '#CFD3DC' : '#606266',
|
||||
containerBackground: uiStore.dark ? '#6C6E72' : '#E6EBF8'
|
||||
}))
|
||||
let daySendTotal = 0
|
||||
let leaveWidth = 0
|
||||
let senderPie = null
|
||||
@@ -194,6 +205,7 @@ let sendGauge = null
|
||||
let first = true
|
||||
let boxKey = ref(0)
|
||||
let senderPieLeft = window.innerWidth < 500 ? `${window.innerWidth - 110}` : '72%'
|
||||
let analysisDark = uiStore.dark
|
||||
|
||||
onMounted(() => {
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
@@ -232,17 +244,6 @@ onMounted(() => {
|
||||
|
||||
})
|
||||
|
||||
function initPicture() {
|
||||
if (route.name !== 'analysis') return
|
||||
boxKey.value++
|
||||
setTimeout(() => {
|
||||
createSenderPie()
|
||||
createIncreaseLine()
|
||||
createEmailColumnChart();
|
||||
createSendGauge();
|
||||
})
|
||||
}
|
||||
|
||||
const widthChange = debounce(initPicture, 500, {
|
||||
leading: false,
|
||||
trailing: true
|
||||
@@ -261,6 +262,9 @@ onActivated(() => {
|
||||
widthChange()
|
||||
} else if (!senderPie) {
|
||||
widthChange()
|
||||
} else if (analysisDark !== uiStore.dark) {
|
||||
initPicture()
|
||||
analysisDark = uiStore.dark
|
||||
}
|
||||
})
|
||||
|
||||
@@ -273,6 +277,23 @@ window.onresize = () => {
|
||||
widthChange()
|
||||
}
|
||||
|
||||
watch(() => uiStore.dark, () => {
|
||||
if (route.name !== 'analysis') return
|
||||
analysisDark = uiStore.dark
|
||||
initPicture()
|
||||
})
|
||||
|
||||
function initPicture() {
|
||||
if (route.name !== 'analysis') return
|
||||
boxKey.value++
|
||||
setTimeout(() => {
|
||||
createSenderPie()
|
||||
createIncreaseLine()
|
||||
createEmailColumnChart();
|
||||
createSendGauge();
|
||||
})
|
||||
}
|
||||
|
||||
function setStyle() {
|
||||
senderPieLeft = window.innerWidth < 500 ? `${window.innerWidth - 110}` : '72%'
|
||||
emailColumnData.barWidth = window.innerWidth > 767 ? '40%' : '60%'
|
||||
@@ -301,11 +322,14 @@ function createSenderPie() {
|
||||
if (senderPie) {
|
||||
senderPie.dispose()
|
||||
}
|
||||
|
||||
senderPie = echarts.init(document.querySelector(".sender-pie"))
|
||||
let option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
textStyle: {
|
||||
color: topic.value.color
|
||||
},
|
||||
backgroundColor: topic.value.background,
|
||||
formatter: params => {
|
||||
return `${params.marker} ${params.name}: ${params.value} (${params.percent}%)`;
|
||||
}
|
||||
@@ -315,6 +339,9 @@ function createSenderPie() {
|
||||
orient: 'vertical',
|
||||
left: '10',
|
||||
top: '20',
|
||||
textStyle: {
|
||||
color: topic.value.color
|
||||
},
|
||||
formatter: function (name) {
|
||||
return truncateTextByWidth(name)
|
||||
}
|
||||
@@ -329,7 +356,7 @@ function createSenderPie() {
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 4,
|
||||
borderColor: '#fff',
|
||||
borderColor: topic.value.borderColor,
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
@@ -370,7 +397,10 @@ function createIncreaseLine() {
|
||||
axisPointer: {
|
||||
type: 'cross', // 指示器的类型为交叉型,适用于折线图等
|
||||
crossStyle: {
|
||||
color: '#999' // 设置指示器线的颜色
|
||||
color: topic.value.crossColor// 设置指示器线的颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: topic.value.crossColor // ← 竖线颜色
|
||||
},
|
||||
axis: 'x',
|
||||
},
|
||||
@@ -381,12 +411,12 @@ function createIncreaseLine() {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
backgroundColor: '#fff', // 设置背景颜色
|
||||
borderColor: '#ccc', // 设置边框颜色
|
||||
backgroundColor: topic.value.background, // 设置背景颜色
|
||||
borderColor: topic.value.splitLineColor, // 设置边框颜色
|
||||
borderWidth: 1, // 设置边框宽度
|
||||
padding: 10, // 设置内边距
|
||||
textStyle: {
|
||||
color: '#333', // 设置文字颜色
|
||||
color: topic.value.color, // 设置文字颜色
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
@@ -402,7 +432,7 @@ function createIncreaseLine() {
|
||||
show: false,
|
||||
alignWithLabel: false, // 刻度线与标签对齐,
|
||||
lineStyle: {
|
||||
color: 'red',
|
||||
color: topic.value.axisColor,
|
||||
}
|
||||
},
|
||||
axisPointer: {
|
||||
@@ -412,7 +442,7 @@ function createIncreaseLine() {
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#909399',
|
||||
color: topic.value.axisColor,
|
||||
width: 1,
|
||||
type: 'solid'
|
||||
}
|
||||
@@ -427,6 +457,7 @@ function createIncreaseLine() {
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
},
|
||||
boundaryGap: false,
|
||||
},
|
||||
@@ -444,7 +475,7 @@ function createIncreaseLine() {
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#909399',
|
||||
color: topic.value.axisColor,
|
||||
width: 1,
|
||||
}
|
||||
},
|
||||
@@ -460,7 +491,7 @@ function createIncreaseLine() {
|
||||
show: true, // 显示网格线
|
||||
lineStyle: {
|
||||
type: 'dashed', // 设置网格线为虚线
|
||||
color: '#ccc' // 设置虚线的颜色
|
||||
color: topic.value.scaleLineColor // 设置虚线的颜色
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -519,6 +550,10 @@ function createEmailColumnChart() {
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
textStyle: {
|
||||
color: topic.value.color
|
||||
},
|
||||
backgroundColor: topic.value.background,
|
||||
formatter: function (params) {
|
||||
params.marker
|
||||
return `${params.marker} ${params.seriesName}: ${params.value}`
|
||||
@@ -526,7 +561,10 @@ function createEmailColumnChart() {
|
||||
},
|
||||
legend: {
|
||||
data: [t('emailReceived'), t('emailSent')],
|
||||
top: '0'
|
||||
top: '0',
|
||||
textStyle: {
|
||||
color: topic.value.color, // 图例文字颜色
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '18',
|
||||
@@ -539,12 +577,12 @@ function createEmailColumnChart() {
|
||||
type: 'category',
|
||||
data: emailColumnData.daysData,
|
||||
axisTick: {
|
||||
show: false
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#909399',
|
||||
color: topic.value.axisColor,
|
||||
width: 1,
|
||||
}
|
||||
},
|
||||
@@ -555,6 +593,21 @@ function createEmailColumnChart() {
|
||||
return 10
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: topic.value.splitLineColor, // ← 横线颜色
|
||||
type: 'solid', // dashed=虚线,solid=实线
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: topic.value.axisColor,
|
||||
width: 0,
|
||||
}
|
||||
},
|
||||
type: 'value',
|
||||
boundaryGap: [0, 0.1],
|
||||
},
|
||||
@@ -603,7 +656,12 @@ function createSendGauge() {
|
||||
}
|
||||
sendGauge = echarts.init(document.querySelector(".send-count"));
|
||||
let option = {
|
||||
tooltip: {},
|
||||
tooltip: {
|
||||
textStyle: {
|
||||
color: topic.value.color
|
||||
},
|
||||
backgroundColor: topic.value.background
|
||||
},
|
||||
series: [{
|
||||
name: t('sentToday'),
|
||||
type: 'gauge',
|
||||
@@ -622,31 +680,39 @@ function createSendGauge() {
|
||||
color: '#3CB2FF'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: topic.value.gaugeSplitLine,
|
||||
},
|
||||
// 轴线背景色(新增)
|
||||
axisLine: {
|
||||
roundCap: true,
|
||||
lineStyle: {
|
||||
color: [[1, '#E6EBF8']]
|
||||
color: [[1, topic.value.containerBackground]]
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: topic.value.gaugeSplitLine, // 大刻度线颜色
|
||||
}
|
||||
},
|
||||
// 刻度颜色(新增)
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: '#999'
|
||||
color: topic.value.axisColor
|
||||
}
|
||||
},
|
||||
// 中心文字颜色(新增)
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
formatter: '{value}',
|
||||
color: '#333' // 黑色文字
|
||||
color: topic.value.color // 黑色文字
|
||||
},
|
||||
data: [{
|
||||
value: daySendTotal,
|
||||
name: t('total'),
|
||||
// 名称标签颜色(新增)
|
||||
title: {
|
||||
color: '#333' // 灰色标签
|
||||
color: topic.value.color // 灰色标签
|
||||
}
|
||||
}]
|
||||
}],
|
||||
@@ -683,7 +749,7 @@ function createSendGauge() {
|
||||
height: 100%;
|
||||
padding: 20px 20px 30px;
|
||||
gap: 20px;
|
||||
background: #FAFCFF;
|
||||
background: var(--extra-light-fill);
|
||||
display: grid;
|
||||
grid-auto-rows: min-content;
|
||||
@media (max-width: 1024px) {
|
||||
@@ -727,6 +793,10 @@ function createSendGauge() {
|
||||
gap: 5px;
|
||||
grid-auto-rows: min-content;
|
||||
|
||||
> div:first-child {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
> div:last-child {
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -761,18 +831,19 @@ function createSendGauge() {
|
||||
justify-content: start;
|
||||
gap: 20px;
|
||||
padding-top: 5px;
|
||||
font-size: 14px;
|
||||
|
||||
.normal {
|
||||
width: fit-content;
|
||||
color: var(--el-color-success);
|
||||
font-weight: bold;
|
||||
font-weight: bold;;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.deleted {
|
||||
width: fit-content;
|
||||
color: var(--el-color-danger);
|
||||
font-weight: bold;
|
||||
font-weight: bold;;
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
@@ -792,7 +863,7 @@ function createSendGauge() {
|
||||
}
|
||||
|
||||
.picture-item {
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
|
||||
@@ -832,7 +903,7 @@ function createSendGauge() {
|
||||
}
|
||||
|
||||
.picture-cs-item {
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-alert v-if="email.status === 5" :closable="false" :title="$t('delayed')" class="email-msg" type="warning" show-icon />
|
||||
</div>
|
||||
<el-scrollbar class="htm-scrollbar" :class="email.attList.length === 0 ? 'bottom-distance' : ''">
|
||||
<ShadowHtml :html="formatImage(email.content)" v-if="email.content" />
|
||||
<ShadowHtml class="shadow-html" :html="formatImage(email.content)" v-if="email.content" />
|
||||
<pre v-else class="email-text" >{{email.text}}</pre>
|
||||
</el-scrollbar>
|
||||
<div class="att" v-if="email.attList.length > 0">
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="att-name" @click="showImage(att.key)">
|
||||
{{ att.filename }}
|
||||
</div>
|
||||
<div style="color: rgba(24, 36, 48, 0.6);">{{ formatBytes(att.size) }}</div>
|
||||
<div class="att-size">{{ formatBytes(att.size) }}</div>
|
||||
<div class="opt-icon att-icon">
|
||||
<Icon v-if="isImage(att.filename)" icon="hugeicons:view" width="22" height="22" @click="showImage(att.key)"/>
|
||||
<a :href="cvtR2Url(att.key)" download>
|
||||
@@ -208,7 +208,7 @@ const handleDelete = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
box-shadow: var(--header-actions-border);
|
||||
font-size: 18px;
|
||||
.star {
|
||||
display: flex;
|
||||
@@ -281,7 +281,7 @@ const handleDelete = () => {
|
||||
padding: 5px 8px;
|
||||
border-radius: 4px;
|
||||
align-self: start;
|
||||
border: 1px solid #e7e9ec;
|
||||
border: 1px solid var(--base-border-color);
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
gap: 10px;
|
||||
@@ -290,6 +290,10 @@ const handleDelete = () => {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.att-size {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.att-name {
|
||||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
@@ -305,13 +309,13 @@ const handleDelete = () => {
|
||||
}
|
||||
|
||||
.opt-icon {
|
||||
color: rgba(24, 36, 48, 0.6);
|
||||
color: var(--secondary-text-color);
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
a {
|
||||
color: rgba(24, 36, 48, 0.6);
|
||||
color: var(--secondary-text-color);
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
@@ -321,14 +325,14 @@ const handleDelete = () => {
|
||||
|
||||
.email-info {
|
||||
|
||||
border-bottom: 1px solid #e7e9ec;
|
||||
border-bottom: 1px solid var(--light-border-color);
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 8px;
|
||||
@media (max-width: 1024px) {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.date {
|
||||
color: #585d69;
|
||||
color: var(--regular-text-color);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
@@ -343,7 +347,7 @@ const handleDelete = () => {
|
||||
margin-bottom: 6px;
|
||||
|
||||
.send-name {
|
||||
color: #585d69;
|
||||
color: var(--regular-text-color);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -361,7 +365,7 @@ const handleDelete = () => {
|
||||
word-break: break-word;
|
||||
}
|
||||
span:nth-child(2) {
|
||||
color: #585d69;
|
||||
color: var(--regular-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +384,17 @@ const handleDelete = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.shadow-html::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--message-block-color); /* 半透明黑色蒙层 */
|
||||
pointer-events: none; /* 不影响点击 */
|
||||
}
|
||||
|
||||
.email-text {
|
||||
font-family: inherit;
|
||||
white-space: pre-wrap;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<div style="color: var(--el-text-color-primary)">
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<div>
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
@@ -178,7 +178,8 @@ window.loadBefore = (e) => {
|
||||
}
|
||||
|
||||
const loginOpacity = computed(() => {
|
||||
return `rgba(255, 255, 255, ${settingStore.settings.loginOpacity})`
|
||||
const opacity = settingStore.settings.loginOpacity
|
||||
return uiStore.dark ? `rgba(0, 0, 0, ${opacity})` : `rgba(255, 255, 255, ${opacity})`
|
||||
})
|
||||
|
||||
const background = computed(() => {
|
||||
@@ -415,7 +416,7 @@ function submitRegister() {
|
||||
justify-content: center;
|
||||
width: 450px;
|
||||
height: 100%;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-left: 1px solid var(--login-border);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
@media (max-width: 1024px) {
|
||||
padding: 20px 18px;
|
||||
@@ -423,6 +424,7 @@ function submitRegister() {
|
||||
margin-left: 18px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
border: 1px solid var(--login-border);
|
||||
padding: 20px 18px;
|
||||
border-radius: 6px;
|
||||
height: fit-content;
|
||||
@@ -440,7 +442,7 @@ function submitRegister() {
|
||||
.form-desc {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 18px;
|
||||
color: #71717a;
|
||||
color: var(--form-desc-color);
|
||||
}
|
||||
|
||||
.form-title {
|
||||
@@ -453,17 +455,19 @@ function submitRegister() {
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
color: #006be6;
|
||||
color: var(--login-switch-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 6px;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.email-input :deep(.el-input__wrapper) {
|
||||
border-radius: 6px 0 0 6px;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.el-input {
|
||||
@@ -490,7 +494,7 @@ function submitRegister() {
|
||||
padding: 0 !important;
|
||||
padding-left: 8px !important;
|
||||
padding-right: 4px !important;
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
@@ -518,7 +522,6 @@ function submitRegister() {
|
||||
|
||||
#login-box {
|
||||
background: linear-gradient(to bottom, #2980b9, #6dd5fa, #fff);
|
||||
color: #333;
|
||||
font: 100% Arial, sans-serif;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
@@ -15,40 +15,40 @@
|
||||
<Icon class="icon" icon="fluent:broom-sparkle-16-regular" width="22" height="22" @click="clearNotUse"/>
|
||||
</div>
|
||||
|
||||
<el-scrollbar class="scrollbar" :style="`background: ${regKeyData.length > 0 ? '#FAFCFF;' : '#FFF'}`">
|
||||
<div class="loading" :class="regKeyLoading ? 'loading-show' : 'loading-hide'">
|
||||
<loading />
|
||||
<el-scrollbar class="scrollbar">
|
||||
<div class="loading" :class="regKeyLoading ? 'loading-show' : 'loading-hide'" :style="regKeyFirst ? 'background: transparent' : ''">
|
||||
<loading/>
|
||||
</div>
|
||||
<div class="code-box">
|
||||
<div class="code-item" v-for="item in regKeyData">
|
||||
<div class="code-info">
|
||||
<div class="info-left">
|
||||
<div class="info-left-item">
|
||||
<span class="code" @click="copyCode(item.code)">{{item.code}}</span>
|
||||
<span class="code" @click="copyCode(item.code)">{{ item.code }}</span>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>{{$t('remainingUses')}}:</div>
|
||||
<div v-if="item.count">{{item.count}}</div>
|
||||
<el-tag v-else type="danger">{{$t('exhausted')}}</el-tag>
|
||||
<div>{{ $t('remainingUses') }}:</div>
|
||||
<div v-if="item.count">{{ item.count }}</div>
|
||||
<el-tag v-else type="danger">{{ $t('exhausted') }}</el-tag>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>{{$t('roleDesc')}}:</div>
|
||||
<el-tag>{{item.roleName}}</el-tag>
|
||||
<div>{{ $t('roleDesc') }}:</div>
|
||||
<el-tag>{{ item.roleName }}</el-tag>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>{{$t('validUntil')}}:</div>
|
||||
<div v-if="item.expireTime">{{ formatExpireTime(item.expireTime)}}</div>
|
||||
<el-tag v-else type="danger">{{$t('expired')}}</el-tag>
|
||||
<div>{{ $t('validUntil') }}:</div>
|
||||
<div v-if="item.expireTime">{{ formatExpireTime(item.expireTime) }}</div>
|
||||
<el-tag v-else type="danger">{{ $t('expired') }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-right">
|
||||
<el-dropdown class="setting">
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" />
|
||||
<template #dropdown >
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399"/>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="copyCode(item.code)">{{$t('copy')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="openHistory(item)">{{$t('history')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="deleteRegKey(item)">{{$t('delete')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="copyCode(item.code)">{{ $t('copy') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="openHistory(item)">{{ $t('history') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="deleteRegKey(item)">{{ $t('delete') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -64,7 +64,7 @@
|
||||
<div class="container">
|
||||
<el-input v-model="addForm.code" :placeholder="$t('regKey')">
|
||||
<template #suffix>
|
||||
<Icon @click.stop="genCode" class="gen-code" icon="bitcoin-icons:refresh-filled" width="24" height="24" />
|
||||
<Icon @click.stop="genCode" class="gen-code" icon="bitcoin-icons:refresh-filled" width="24" height="24"/>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select v-model="addForm.roleId" :placeholder="$t('roleDesc')">
|
||||
@@ -77,31 +77,33 @@
|
||||
/>
|
||||
<el-input-number v-model="addForm.count" :min="1" :max="99999"/>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="addLoading"
|
||||
>{{$t('add')}}
|
||||
>{{ $t('add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog class="history-list" v-model="showRegKeyHistory" :title="$t('useHistory')">
|
||||
<div class="loading" :class="historyLoading ? 'loading-show' : 'loading-hide'">
|
||||
<loading />
|
||||
<loading/>
|
||||
</div>
|
||||
<el-table v-if="!historyLoading" :data="historyList" :fit="true" style="height: 100%" >
|
||||
<el-table-column :min-width="emailColumnWidth" property="email" :label="$t('user')" :show-overflow-tooltip="true" />
|
||||
<el-table-column :width="createTimeColumnWidth" :formatter="formatUserCreateTime" property="createTime" :label="$t('date')" fixed="right" :show-overflow-tooltip="true" />
|
||||
<el-table v-if="!historyLoading" :data="historyList" :fit="true" style="height: 100%">
|
||||
<el-table-column :min-width="emailColumnWidth" property="email" :label="$t('user')"
|
||||
:show-overflow-tooltip="true"/>
|
||||
<el-table-column :width="createTimeColumnWidth" :formatter="formatUserCreateTime" property="createTime"
|
||||
:label="$t('date')" fixed="right" :show-overflow-tooltip="true"/>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {defineOptions, reactive, ref, watch} from "vue"
|
||||
import {defineOptions, nextTick, reactive, ref, watch} from "vue"
|
||||
import {Icon} from "@iconify/vue";
|
||||
import loading from "@/components/loading/index.vue";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import {roleSelectUse} from "@/request/role.js";
|
||||
import {useRoleStore} from "@/store/role.js";
|
||||
import {regKeyAdd, regKeyList, regKeyClearNotUse, regKeyDelete, regKeyHistory} from "@/request/reg-key.js";
|
||||
import { getTextWidth } from "@/utils/text.js";
|
||||
import {getTextWidth} from "@/utils/text.js";
|
||||
import dayjs from "dayjs";
|
||||
import {tzDayjs} from "@/utils/day.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
@@ -116,7 +118,7 @@ const params = reactive({
|
||||
code: '',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const {t} = useI18n()
|
||||
const roleList = reactive([])
|
||||
const addLoading = ref(false)
|
||||
const showAdd = ref(false)
|
||||
@@ -193,15 +195,7 @@ function formatUserCreateTime(regKey) {
|
||||
const currentYear = dayjs().year();
|
||||
const expireYear = createTime.year();
|
||||
|
||||
if(settingStore.lang === 'zh') {
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return createTime.format('M月D日 HH:mm');
|
||||
} else {
|
||||
return createTime.format('YYYY年M月D日 HH:mm');
|
||||
}
|
||||
|
||||
} else {
|
||||
if (settingStore.lang === 'en') {
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return createTime.format('MMM D, HH:mm');
|
||||
@@ -209,6 +203,14 @@ function formatUserCreateTime(regKey) {
|
||||
return createTime.format('MMM D, YYYY HH:mm');
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return createTime.format('M月D日 HH:mm');
|
||||
} else {
|
||||
return createTime.format('YYYY年M月D日 HH:mm');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -218,16 +220,18 @@ function formatExpireTime(expireTime) {
|
||||
const currentYear = dayjs().year();
|
||||
const expireYear = expireDate.year();
|
||||
|
||||
if (settingStore.lang === 'zh') {
|
||||
|
||||
return expireYear === currentYear
|
||||
? expireDate.format('M月D日')
|
||||
: expireDate.format('YYYY年M月D日');
|
||||
} else {
|
||||
if (settingStore.lang === 'en') {
|
||||
|
||||
return expireYear === currentYear
|
||||
? expireDate.format('MMM D')
|
||||
: expireDate.format('MMM D, YYYY');
|
||||
|
||||
} else {
|
||||
|
||||
return expireYear === currentYear
|
||||
? expireDate.format('M月D日')
|
||||
: expireDate.format('YYYY年M月D日');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +252,9 @@ function getList(showLoading = false) {
|
||||
regKeyData.length = 0
|
||||
regKeyData.push(...list)
|
||||
regKeyLoading.value = false
|
||||
regKeyFirst.value = false
|
||||
setTimeout(() => {
|
||||
regKeyFirst.value = false
|
||||
},200)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -353,8 +359,8 @@ function submit() {
|
||||
})
|
||||
}
|
||||
|
||||
function deleteRegKey(regKey){
|
||||
ElMessageBox.confirm(t('delConfirm',{msg: regKey.code}), {
|
||||
function deleteRegKey(regKey) {
|
||||
ElMessageBox.confirm(t('delConfirm', {msg: regKey.code}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
@@ -370,7 +376,7 @@ function deleteRegKey(regKey){
|
||||
});
|
||||
}
|
||||
|
||||
function resetForm(){
|
||||
function resetForm() {
|
||||
addForm.code = ''
|
||||
}
|
||||
|
||||
@@ -390,30 +396,37 @@ function openAdd() {
|
||||
.scrollbar {
|
||||
height: calc(100% - 48px);
|
||||
position: relative;
|
||||
background: var(--extra-light-fill);
|
||||
@media (max-width: 372px) {
|
||||
height: calc(100% - 85px);
|
||||
}
|
||||
|
||||
.code-box {
|
||||
padding: 15px 15px 25px 15px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 15px;
|
||||
|
||||
.code-item {
|
||||
background-color: #fff;
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
transition: all 300ms;
|
||||
transition: all 200ms;
|
||||
padding: 15px;
|
||||
|
||||
.code-info {
|
||||
display: flex;
|
||||
|
||||
.info-left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.info-left-item {
|
||||
display: flex;
|
||||
padding-top: 5px;
|
||||
|
||||
.code {
|
||||
font-weight: bold;
|
||||
font-weight: bold;;
|
||||
font-size: 16px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -479,7 +492,7 @@ function openAdd() {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background: var(--loadding-background);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@@ -529,6 +542,7 @@ function openAdd() {
|
||||
@media (max-width: 767px) {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: min(200px, calc(100vw - 140px));
|
||||
}
|
||||
@@ -549,7 +563,7 @@ function openAdd() {
|
||||
}
|
||||
|
||||
:deep(.el-table__inner-wrapper:before) {
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,78 +1,82 @@
|
||||
<template>
|
||||
<div class="perm-box">
|
||||
<div class="header-actions">
|
||||
<Icon class="icon" icon="ion:add-outline" width="23" height="23" @click="openAddRole" />
|
||||
<Icon class="icon" icon="ion:reload" width="18" height="18" @click="refresh" />
|
||||
<Icon class="icon" icon="ion:add-outline" width="23" height="23" @click="openAddRole"/>
|
||||
<Icon class="icon" icon="ion:reload" width="18" height="18" @click="refresh"/>
|
||||
</div>
|
||||
<div class="loading" v-if="tableLoading">
|
||||
<loading/>
|
||||
</div>
|
||||
<el-scrollbar v-else class="perm-scrollbar">
|
||||
<div>
|
||||
<el-table
|
||||
:data="roles"
|
||||
style="width: 100%;"
|
||||
>
|
||||
<el-table-column width="10" />
|
||||
<el-table-column :label="$t('role')" prop="name" :min-width="roleWidth">
|
||||
<template #default="props">
|
||||
<div class="role-name">
|
||||
<span >{{props.row.name}}</span>
|
||||
<span v-if="props.row.isDefault"><el-tag class="def-tag" >{{$t('default')}}</el-tag></span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('order')" :width="sortWidth" prop="sort"/>
|
||||
<el-table-column v-if="desShow" :label="$t('description')" min-width="200" prop="description" >
|
||||
<template #default="props">
|
||||
<div class="description">
|
||||
<span >{{props.row.description}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('tabSetting')" :width="settingWidth">
|
||||
<template #default="props">
|
||||
<el-dropdown trigger="click">
|
||||
<el-button size="small" type="primary">{{$t('action')}}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openRoleSet(props.row)">{{$t('change')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setDef(props.row)">{{$t('default')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="delRole(props.row)">{{$t('delete')}}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-scrollbar class="perm-scrollbar">
|
||||
<div class="loading" :class="tableLoading ? 'loading-show' : 'loading-hide'"
|
||||
:style="first ? 'background: transparent' : ''">
|
||||
<loading/>
|
||||
</div>
|
||||
<el-table
|
||||
:data="roles"
|
||||
style="height: 100%;"
|
||||
:empty-text="''"
|
||||
>
|
||||
<el-table-column width="10"/>
|
||||
<el-table-column :label="$t('role')" prop="name" :min-width="roleWidth">
|
||||
<template #default="props">
|
||||
<div class="role-name">
|
||||
<span>{{ props.row.name }}</span>
|
||||
<span v-if="props.row.isDefault"><el-tag class="def-tag">{{ $t('default') }}</el-tag></span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('order')" :width="sortWidth" prop="sort"/>
|
||||
<el-table-column v-if="desShow" :label="$t('description')" min-width="200" prop="description">
|
||||
<template #default="props">
|
||||
<div class="description">
|
||||
<span>{{ props.row.description }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('tabSetting')" :width="settingWidth">
|
||||
<template #default="props">
|
||||
<el-dropdown trigger="click">
|
||||
<el-button size="small" type="primary">{{ $t('action') }}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openRoleSet(props.row)">{{ $t('change') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setDef(props.row)">{{ $t('default') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="delRole(props.row)">{{ $t('delete') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-scrollbar>
|
||||
<el-dialog top="5vh" class="dialog" v-model="roleFormShow" @closed="resetForm">
|
||||
<template #header>
|
||||
<span style="font-size: 18px">{{dialogType.title}}</span>
|
||||
<span style="font-size: 18px">{{ dialogType.title }}</span>
|
||||
<el-popover
|
||||
width ="340"
|
||||
width="340"
|
||||
:title="t('featDesc')"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #reference>
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</template>
|
||||
<div style="font-weight: bold;margin-bottom: 2px;">{{t('emailInterception')}}</div>
|
||||
<div>{{t('emailInterceptionDesc')}}</div>
|
||||
<div style="font-weight: bold;margin-top: 10px;margin-bottom: 2px;">{{t('availableDomains')}}</div>
|
||||
<div style="font-weight: bold;;margin-bottom: 2px;">{{ t('emailInterception') }}</div>
|
||||
<div>{{ t('emailInterceptionDesc') }}</div>
|
||||
<div style="font-weight: bold;;margin-top: 10px;margin-bottom: 2px;">{{ t('availableDomains') }}</div>
|
||||
<div>
|
||||
{{t('availableDomainsDesc')}}
|
||||
{{ t('availableDomainsDesc') }}
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
<div class="dialog-box">
|
||||
<el-input class="dialog-input" v-model="form.name" type="text" :maxlength="12" :placeholder="$t('roleName')" autocomplete="off" />
|
||||
<el-input class="dialog-input" v-model="form.description" :maxlength="30" type="text" :placeholder="$t('description')" autocomplete="off" />
|
||||
<el-input-tag class="dialog-input-tag" tag-type="warning" :class="form.banEmail.length === 0 ? 'dialog-input' : '' " v-model="form.banEmail" @add-tag="banEmailAddTag" type="text" :placeholder="$t('emailInterception')" autocomplete="off" />
|
||||
<el-input class="dialog-input" v-model="form.name" type="text" :maxlength="12" :placeholder="$t('roleName')"
|
||||
autocomplete="off"/>
|
||||
<el-input class="dialog-input" v-model="form.description" :maxlength="30" type="text"
|
||||
:placeholder="$t('description')" autocomplete="off"/>
|
||||
<el-input-tag class="dialog-input-tag" tag-type="warning"
|
||||
:class="form.banEmail.length === 0 ? 'dialog-input' : '' " v-model="form.banEmail"
|
||||
@add-tag="banEmailAddTag" type="text" :placeholder="$t('emailInterception')" autocomplete="off"/>
|
||||
<el-radio-group class="dialog-radio" v-model="form.banEmailType" v-if="form.banEmail.length > 0">
|
||||
<el-radio :label="$t('removeAll')" :value="0" />
|
||||
<el-radio :label="$t('removeContent')" :value="1" />
|
||||
<el-radio :label="$t('removeAll')" :value="0"/>
|
||||
<el-radio :label="$t('removeContent')" :value="1"/>
|
||||
</el-radio-group>
|
||||
<el-select
|
||||
class="dialog-input"
|
||||
@@ -94,11 +98,12 @@
|
||||
/>
|
||||
</el-select>
|
||||
<div class="dialog-input">
|
||||
<el-input-number :placeholder="$t('order')" :min="0" :max="9999" v-model.number="form.sort" controls-position="right" autocomplete="off" />
|
||||
<el-input-number :placeholder="$t('order')" :min="0" :max="9999" v-model.number="form.sort"
|
||||
controls-position="right" autocomplete="off"/>
|
||||
</div>
|
||||
<el-radio-group v-model="expand" size="small" @change="expandChange" class="perm-expand">
|
||||
<el-radio-button :label="$t('expand')" :value="true" />
|
||||
<el-radio-button :label="$t('collapse')" :value="false" />
|
||||
<el-radio-button :label="$t('expand')" :value="true"/>
|
||||
<el-radio-button :label="$t('collapse')" :value="false"/>
|
||||
</el-radio-group>
|
||||
<el-tree
|
||||
:expand-on-click-node="false"
|
||||
@@ -114,25 +119,28 @@
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div>
|
||||
<span>{{node.label}}</span>
|
||||
<span>{{ node.label }}</span>
|
||||
<span class="send-num" v-if="data.permKey === 'email:send'" @click.stop>
|
||||
<el-input-number v-model="form.sendCount" controls-position="right" :min="0" :max="99999" size="small" :placeholder="$t('total')" >
|
||||
<el-input-number v-model="form.sendCount" controls-position="right" :min="0" :max="99999" size="small"
|
||||
:placeholder="$t('total')">
|
||||
</el-input-number>
|
||||
<el-select v-model="form.sendType" placeholder="Select" size="small" style="width: 65px;margin-left: 5px;">
|
||||
<el-option :label="$t('total')" value="count" />
|
||||
<el-option :label="$t('daily')" value="day" />
|
||||
<el-option :label="$t('btnBan')" value="ban" />
|
||||
<el-select v-model="form.sendType" placeholder="Select" size="small"
|
||||
style="width: 65px;margin-left: 5px;">
|
||||
<el-option :label="$t('total')" value="count"/>
|
||||
<el-option :label="$t('daily')" value="day"/>
|
||||
<el-option :label="$t('btnBan')" value="ban"/>
|
||||
</el-select>
|
||||
</span>
|
||||
<span class="send-num" v-if="data.permKey === 'account:add'" @click.stop>
|
||||
<el-input-number v-model="form.accountCount" controls-position="right" :min="0" :max="99999" size="small" :placeholder="$t('total')" >
|
||||
<el-input-number v-model="form.accountCount" controls-position="right" :min="0" :max="99999"
|
||||
size="small" :placeholder="$t('total')">
|
||||
</el-input-number>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
<el-button class="btn" type="primary" :loading="permLoading" @click="roleFormClick"
|
||||
>{{$t('save')}}
|
||||
>{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -153,8 +161,8 @@ defineOptions({
|
||||
name: 'role'
|
||||
})
|
||||
|
||||
const { domainList } = useSettingStore();
|
||||
const { t, locale } = useI18n();
|
||||
const {domainList} = useSettingStore();
|
||||
const {t, locale} = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const roleStore = useRoleStore();
|
||||
const roleFormShow = ref(false)
|
||||
@@ -167,6 +175,7 @@ const desShow = ref(true)
|
||||
const settingWidth = ref(null)
|
||||
const sortWidth = ref(null)
|
||||
const roleWidth = ref(200)
|
||||
const first = ref(true)
|
||||
|
||||
const dialogType = reactive({
|
||||
title: '',
|
||||
@@ -200,7 +209,7 @@ rolePermTree().then(tree => {
|
||||
|
||||
domainOptions = domainList.map(domain => {
|
||||
const cleanDomain = domain.replace(/^@/, '');
|
||||
return { label: cleanDomain, value: cleanDomain };
|
||||
return {label: cleanDomain, value: cleanDomain};
|
||||
});
|
||||
|
||||
|
||||
@@ -209,7 +218,7 @@ function availDomainChange() {
|
||||
return !domainOptions.map(option => option.value).includes(domain)
|
||||
})
|
||||
if (index > -1) {
|
||||
form.availDomain.splice(index,1)
|
||||
form.availDomain.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +301,7 @@ function setRole() {
|
||||
return
|
||||
}
|
||||
|
||||
const params = {...form,roleId: chooseRole.roleId}
|
||||
const params = {...form, roleId: chooseRole.roleId}
|
||||
const checkedId = tree.value.getCheckedKeys()
|
||||
const halfId = tree.value.getHalfCheckedKeys()
|
||||
params.permIds = [...checkedId, ...halfId]
|
||||
@@ -390,6 +399,9 @@ function getRoleList() {
|
||||
roles.value = list
|
||||
}).finally(() => {
|
||||
tableLoading.value = false
|
||||
setTimeout(() => {
|
||||
first.value = false
|
||||
}, 200)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -414,6 +426,7 @@ window.onresize = () => {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
.perm-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -421,6 +434,7 @@ window.onresize = () => {
|
||||
|
||||
.send-num {
|
||||
margin-left: 10px;
|
||||
|
||||
.el-input-number {
|
||||
width: 95px;
|
||||
}
|
||||
@@ -436,16 +450,19 @@ window.onresize = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
box-shadow: var(--header-actions-border);
|
||||
font-size: 18px;
|
||||
|
||||
.search {
|
||||
:deep(.el-input-group) {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -466,10 +483,25 @@ window.onresize = () => {
|
||||
}
|
||||
|
||||
.loading {
|
||||
height: 100%;
|
||||
height: calc(100% - 41px);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
background: var(--loadding-background);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.loading-show {
|
||||
transition: all 200ms ease 200ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.loading-hide {
|
||||
pointer-events: none;
|
||||
transition: all 200ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.role-name {
|
||||
@@ -494,15 +526,17 @@ window.onresize = () => {
|
||||
.dialog-input {
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.dialog-radio {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dialog-input-tag {
|
||||
}
|
||||
}
|
||||
|
||||
.perm-expand {
|
||||
.perm-expand {
|
||||
margin-bottom: 5px;
|
||||
--el-border-radius-base: 4px;
|
||||
position: relative;
|
||||
@@ -520,8 +554,13 @@ window.onresize = () => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-scrollbar__view) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
<div class="del-email" v-perm="'my:delete'">
|
||||
<div class="title">{{$t('deleteUser')}}</div>
|
||||
<div style="color: #585d69;">
|
||||
<div style="color: var(--regular-text-color);">
|
||||
{{$t('delAccountMsg')}}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
<template>
|
||||
<div class="settings-container">
|
||||
<div v-if="firstLoading" class="loading">
|
||||
<loading />
|
||||
<loading/>
|
||||
</div>
|
||||
<el-scrollbar class="scroll" v-else >
|
||||
<el-scrollbar class="scroll" v-else>
|
||||
<div class="scroll-body">
|
||||
<div class="card-grid">
|
||||
<!-- Website Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('websiteSetting')}}</div>
|
||||
<div class="card-title">{{ $t('websiteSetting') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('websiteReg')}}</span></div>
|
||||
<div><span>{{ $t('websiteReg') }}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.register"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('loginDomain')}}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.loginDomain"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('regKey')}}</span></div>
|
||||
<div><span>{{ $t('loginDomain') }}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.loginDomain"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{ $t('regKey') }}</span></div>
|
||||
<div>
|
||||
<el-select
|
||||
@change="change"
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('addAccount')}}</span></div>
|
||||
<div><span>{{ $t('addAccount') }}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.addEmail"/>
|
||||
@@ -51,7 +51,7 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>{{$t('multipleEmail')}}</span>
|
||||
<span>{{ $t('multipleEmail') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('multipleEmailDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>{{$t('physicallyWipeData')}}</span>
|
||||
<span>{{ $t('physicallyWipeData') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('physicallyWipeDataDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
@@ -80,10 +80,10 @@
|
||||
|
||||
<!-- Personalization Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('customization')}}</div>
|
||||
<div class="card-title">{{ $t('customization') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div class="title-item"><span>{{$t('websiteTitle')}}</span></div>
|
||||
<div class="title-item"><span>{{ $t('websiteTitle') }}</span></div>
|
||||
<div class="email-title">
|
||||
<span>{{ setting.title }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="editTitleShow = true">
|
||||
@@ -92,13 +92,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title-item"><span>{{$t('loginBoxOpacity')}}</span></div>
|
||||
<div class="title-item"><span>{{ $t('loginBoxOpacity') }}</span></div>
|
||||
<div>
|
||||
<el-input-number size="small" v-model="loginOpacity" @change="opacityChange" :precision="2" :step="0.01" :max="1" :min="0" />
|
||||
<el-input-number size="small" v-model="loginOpacity" @change="opacityChange" :precision="2"
|
||||
:step="0.01" :max="1" :min="0"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item personalized">
|
||||
<div><span>{{$t('loginBackground')}}</span></div>
|
||||
<div><span>{{ $t('loginBackground') }}</span></div>
|
||||
<div>
|
||||
<el-image
|
||||
class="background"
|
||||
@@ -128,10 +129,10 @@
|
||||
|
||||
<!-- Email Sending Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('emailSetting')}}</div>
|
||||
<div class="card-title">{{ $t('emailSetting') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('receiveEmail')}}</span></div>
|
||||
<div><span>{{ $t('receiveEmail') }}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.receive"/>
|
||||
@@ -139,7 +140,7 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>{{$t('autoRefresh')}}</span>
|
||||
<span>{{ $t('autoRefresh') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('autoRefreshDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
@@ -161,7 +162,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('sendEmail')}}</span></div>
|
||||
<div><span>{{ $t('sendEmail') }}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.send"/>
|
||||
@@ -169,7 +170,7 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>{{$t('noRecipientTitle')}}</span>
|
||||
<span>{{ $t('noRecipientTitle') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('noRecipientDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
@@ -180,12 +181,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('resendToken')}}</span></div>
|
||||
<div><span>{{ $t('resendToken') }}</span></div>
|
||||
<div>
|
||||
<el-button class="opt-button" style="margin-top: 0" @click="openResendList" size="small" type="primary">
|
||||
<el-button class="opt-button" style="margin-top: 0" @click="openResendList" size="small"
|
||||
type="primary">
|
||||
<Icon icon="ic:round-list" width="18" height="18"/>
|
||||
</el-button>
|
||||
<el-button class="opt-button" style="margin-top: 0" @click="openResendForm" size="small" type="primary">
|
||||
<el-button class="opt-button" style="margin-top: 0" @click="openResendForm" size="small"
|
||||
type="primary">
|
||||
<Icon icon="material-symbols:add-rounded" width="16" height="16"/>
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -195,10 +198,10 @@
|
||||
|
||||
<!-- R2 Object Storage Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('R2OS')}}</div>
|
||||
<div class="card-title">{{ $t('R2OS') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('osDomain')}}</span></div>
|
||||
<div><span>{{ $t('osDomain') }}</span></div>
|
||||
<div class="r2domain">
|
||||
<span>{{ setting.r2Domain || '' }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="r2DomainShow = true">
|
||||
@@ -210,10 +213,10 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('emailPush')}}</div>
|
||||
<div class="card-title">{{ $t('emailPush') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('tgBot')}}</span></div>
|
||||
<div><span>{{ $t('tgBot') }}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.tgBotStatus === 0 ? $t('enabled') : $t('disabled') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openTgSetting">
|
||||
@@ -222,7 +225,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('otherEmail')}}</span></div>
|
||||
<div><span>{{ $t('otherEmail') }}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.forwardStatus === 0 ? $t('enabled') : $t('disabled') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openThirdEmailSetting">
|
||||
@@ -231,7 +234,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('forwardingRules')}}</span></div>
|
||||
<div><span>{{ $t('forwardingRules') }}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.ruleType === 0 ? $t('forwardAll') : $t('rules') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openForwardRules">
|
||||
@@ -244,10 +247,10 @@
|
||||
|
||||
<!-- Turnstile Verification Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('turnstileSetting')}}</div>
|
||||
<div class="card-title">{{ $t('turnstileSetting') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('signUpVerification')}}</span></div>
|
||||
<div><span>{{ $t('signUpVerification') }}</span></div>
|
||||
<div>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openRegVerifyCount">
|
||||
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||
@@ -259,14 +262,14 @@
|
||||
placeholder="Select"
|
||||
class="bot-verify-select"
|
||||
>
|
||||
<el-option key="1" :value="0" :label="$t('enable')" />
|
||||
<el-option key="1" :value="1" :label="$t('disable')" />
|
||||
<el-option key="1" :value="2" :label="$t('rulesVerify')" />
|
||||
<el-option key="1" :value="0" :label="$t('enable')"/>
|
||||
<el-option key="1" :value="1" :label="$t('disable')"/>
|
||||
<el-option key="1" :value="2" :label="$t('rulesVerify')"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('addEmailVerification')}}</span></div>
|
||||
<div><span>{{ $t('addEmailVerification') }}</span></div>
|
||||
<div>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openAddVerifyCount">
|
||||
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||
@@ -278,9 +281,9 @@
|
||||
placeholder="Select"
|
||||
class="bot-verify-select"
|
||||
>
|
||||
<el-option key="1" :value="0" :label="$t('enable')" />
|
||||
<el-option key="1" :value="1" :label="$t('disable')" />
|
||||
<el-option key="1" :value="2" :label="$t('rulesVerify')" />
|
||||
<el-option key="1" :value="0" :label="$t('enable')"/>
|
||||
<el-option key="1" :value="1" :label="$t('disable')"/>
|
||||
<el-option key="1" :value="2" :label="$t('rulesVerify')"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -306,10 +309,10 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<div class="card-title">{{$t('noticeTitle')}}</div>
|
||||
<div class="card-title">{{ $t('noticeTitle') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('noticePopup')}}</span></div>
|
||||
<div><span>{{ $t('noticePopup') }}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.notice === 0 ? $t('enabled') : $t('disabled') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openNoticePopupSetting">
|
||||
@@ -318,7 +321,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>{{$t('popUp')}}</span></div>
|
||||
<div><span>{{ $t('popUp') }}</span></div>
|
||||
<div class="forward">
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openNoticePopup">
|
||||
<Icon icon="mynaui:click-solid" width="18" height="18"/>
|
||||
@@ -329,18 +332,25 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-card about">
|
||||
<div class="card-title">{{$t('about')}}</div>
|
||||
<div class="card-title">{{ $t('about') }}</div>
|
||||
<div class="card-content">
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('version')}} :</span>
|
||||
<span>v1.7.0</span>
|
||||
<span>{{ $t('version') }} :</span>
|
||||
<el-badge is-dot :hidden="!hasUpdate">
|
||||
<el-button @click="jump('https://github.com/eoao/cloud-mail/releases')">
|
||||
{{ currentVersion }}
|
||||
<template #icon>
|
||||
<Icon icon="qlementine-icons:version-control-16" style="font-size: 20px" color="#1890FF"/>
|
||||
</template>
|
||||
</el-button>
|
||||
</el-badge>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('community')}} : </span>
|
||||
<span>{{ $t('community') }} : </span>
|
||||
<el-button @click="jump('https://github.com/eoao/cloud-mail')">
|
||||
Github
|
||||
<template #icon>
|
||||
<Icon icon="codicon:github-inverted" width="22" height="22" />
|
||||
<Icon icon="codicon:github-inverted" width="22" height="22"/>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button @click="jump('https://t.me/cloud_mail_tg')">
|
||||
@@ -351,23 +361,23 @@
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('support')}} : </span>
|
||||
<el-button @click="jump('https://doc.skymail.ink/support.html')" >
|
||||
{{t('supportDesc')}}
|
||||
<span>{{ $t('support') }} : </span>
|
||||
<el-button @click="jump('https://doc.skymail.ink/support.html')">
|
||||
{{ t('supportDesc') }}
|
||||
<template #icon>
|
||||
<Icon color="#79D6B5" icon="simple-icons:buymeacoffee" width="20" height="20" />
|
||||
<Icon color="#79D6B5" icon="simple-icons:buymeacoffee" width="20" height="20"/>
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{ $t('help') }} : </span>
|
||||
<el-button @click="jump('https://doc.skymail.ink')">
|
||||
{{ t('document') }}
|
||||
<template #icon>
|
||||
<Icon color="#79D6B5" icon="fluent-color:document-32" width="18" height="18"/>
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('help')}} : </span>
|
||||
<el-button @click="jump('https://doc.skymail.ink')" >
|
||||
{{t('document')}}
|
||||
<template #icon>
|
||||
<Icon color="#79D6B5" icon="fluent-color:document-32" width="18" height="18" />
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,7 +387,7 @@
|
||||
<el-dialog v-model="editTitleShow" :title="$t('changeTitle')" width="340" @closed="editTitle = setting.title">
|
||||
<form>
|
||||
<el-input type="text" :placeholder="$t('websiteTitle')" v-model="editTitle"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTitle">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTitle">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="resendTokenFormShow" :title="$t('resendToken')" width="340" @closed="cleanResendTokenForm">
|
||||
@@ -391,13 +401,14 @@
|
||||
/>
|
||||
</el-select>
|
||||
<el-input type="text" :placeholder="$t('addResendTokenDesc')" v-model="resendTokenForm.token"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveResendToken">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveResendToken">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="r2DomainShow" :title="$t('addOsDomain')" width="340" @closed="r2DomainInput = setting.r2Domain">
|
||||
<el-dialog v-model="r2DomainShow" :title="$t('addOsDomain')" width="340"
|
||||
@closed="r2DomainInput = setting.r2Domain">
|
||||
<form>
|
||||
<el-input type="text" :placeholder="$t('domainDesc')" v-model="r2DomainInput"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveR2domain">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveR2domain">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="turnstileShow" :title="$t('addTurnstileSecret')" width="340"
|
||||
@@ -405,7 +416,7 @@
|
||||
<form>
|
||||
<el-input type="text" placeholder="Site Key" v-model="turnstileForm.siteKey"/>
|
||||
<el-input type="text" style="margin-top: 15px" placeholder="Secret Key" v-model="turnstileForm.secretKey"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTurnstileKey">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTurnstileKey">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
@@ -415,16 +426,17 @@
|
||||
>
|
||||
<template #header>
|
||||
<span style="font-size: 18px">
|
||||
{{$t('backgroundTitle')}}
|
||||
{{ $t('backgroundTitle') }}
|
||||
<el-tooltip>
|
||||
<template #content>
|
||||
<span>{{$t('backgroundWarning')}}</span>
|
||||
<span>{{ $t('backgroundWarning') }}</span>
|
||||
</template>
|
||||
<Icon class="title-icon warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-input :placeholder="$t('backgroundUrlDesc')" v-model="backgroundUrl" v-if="!localUpShow" class="background-url" />
|
||||
<el-input :placeholder="$t('backgroundUrlDesc')" v-model="backgroundUrl" v-if="!localUpShow"
|
||||
class="background-url"/>
|
||||
<el-image
|
||||
v-if="localUpShow"
|
||||
:preview-src-list="[backgroundImage]"
|
||||
@@ -435,12 +447,12 @@
|
||||
></el-image>
|
||||
<div class="cut-button">
|
||||
<el-button type="primary" link @click="openCut" v-if="!localUpShow">
|
||||
{{$t('localUpload')}}
|
||||
{{ $t('localUpload') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="localUpShow = false" v-if="localUpShow">
|
||||
{{$t('imageLink')}}
|
||||
{{ $t('imageLink') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveBackground">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveBackground">{{ $t('save') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
@@ -449,7 +461,7 @@
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">{{$t('tgBot')}}</span>
|
||||
<span class="forward-set-title">{{ $t('tgBot') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('tgBotDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
@@ -457,13 +469,15 @@
|
||||
</template>
|
||||
<div class="forward-set-body">
|
||||
<el-input :placeholder="$t('tgBotToken')" v-model="tgBotToken"></el-input>
|
||||
<el-input-tag tag-type="warning" :placeholder="$t('toBotTokenDesc')" v-model="tgChatId" @add-tag="addChatTag" ></el-input-tag>
|
||||
<el-input-tag tag-type="warning" :placeholder="$t('toBotTokenDesc')" v-model="tgChatId"
|
||||
@add-tag="addChatTag"></el-input-tag>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-switch v-model="tgBotStatus" :active-value="0" :inactive-value="1" :active-text="$t('enable')" :inactive-text="$t('disable')" />
|
||||
<el-switch v-model="tgBotStatus" :active-value="0" :inactive-value="1" :active-text="$t('enable')"
|
||||
:inactive-text="$t('disable')"/>
|
||||
<el-button :loading="settingLoading" type="primary" @click="tgBotSave">
|
||||
{{$t('save')}}
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -474,20 +488,22 @@
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">{{$t('otherEmail')}}</span>
|
||||
<span class="forward-set-title">{{ $t('otherEmail') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('otherEmailDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<div class="forward-set-body">
|
||||
<el-input-tag tag-type="warning" :placeholder="$t('otherEmailInputDesc')" v-model="forwardEmail" @add-tag="emailAddTag"></el-input-tag>
|
||||
<el-input-tag tag-type="warning" :placeholder="$t('otherEmailInputDesc')" v-model="forwardEmail"
|
||||
@add-tag="emailAddTag"></el-input-tag>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-switch v-model="forwardStatus" :active-value="0" :inactive-value="1" :active-text="$t('enable')" :inactive-text="$t('disable')" />
|
||||
<el-switch v-model="forwardStatus" :active-value="0" :inactive-value="1" :active-text="$t('enable')"
|
||||
:inactive-text="$t('disable')"/>
|
||||
<el-button :loading="settingLoading" type="primary" @click="forwardEmailSave">
|
||||
{{$t('save')}}
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -497,91 +513,97 @@
|
||||
class="forward-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">{{$t('forwardingRules')}}</span>
|
||||
<el-tooltip effect="dark" :content="$t('forwardingRulesDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">{{ $t('forwardingRules') }}</span>
|
||||
<el-tooltip effect="dark" :content="$t('forwardingRulesDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<div class="forward-set-body">
|
||||
<el-input-tag :placeholder="$t('ruleEmailsInputDesc')" tag-type="success" v-model="ruleEmail" @add-tag="ruleEmailAddTag" />
|
||||
<el-input-tag :placeholder="$t('ruleEmailsInputDesc')" tag-type="success" v-model="ruleEmail"
|
||||
@add-tag="ruleEmailAddTag"/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-radio-group v-model="ruleType">
|
||||
<el-radio :value="0" >{{$t('forwardAll')}}</el-radio>
|
||||
<el-radio :value="1" >{{$t('rules')}}</el-radio>
|
||||
<el-radio :value="0">{{ $t('forwardAll') }}</el-radio>
|
||||
<el-radio :value="1">{{ $t('rules') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button :loading="settingLoading" type="primary" @click="ruleEmailSave">
|
||||
{{$t('save')}}
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog class="resend-table" v-model="showResendList" :title="$t('resendTokenList')">
|
||||
<el-table :data="resendList" >
|
||||
<el-table-column :min-width="emailColumnWidth" property="key" :label="$t('domain')" :show-overflow-tooltip="true" />
|
||||
<el-table-column :width="tokenColumnWidth" property="value" label="Token" fixed="right" :show-overflow-tooltip="true" />
|
||||
<el-table :data="resendList">
|
||||
<el-table-column :min-width="emailColumnWidth" property="key" :label="$t('domain')"
|
||||
:show-overflow-tooltip="true"/>
|
||||
<el-table-column :width="tokenColumnWidth" property="value" label="Token" fixed="right"
|
||||
:show-overflow-tooltip="true"/>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="regVerifyCountShow" :title="$t('rulesVerifyTitle',{count: regVerifyCount})" @closed="regVerifyCount = setting.regVerifyCount" >
|
||||
<el-dialog v-model="regVerifyCountShow" :title="$t('rulesVerifyTitle',{count: regVerifyCount})"
|
||||
@closed="regVerifyCount = setting.regVerifyCount">
|
||||
<form>
|
||||
<el-input-number type="text" v-model="regVerifyCount" :min="1" >
|
||||
<el-input-number type="text" v-model="regVerifyCount" :min="1">
|
||||
</el-input-number>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveRegVerifyCount">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveRegVerifyCount">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="addVerifyCountShow" :title="$t('rulesVerifyTitle',{count: addVerifyCount})" @closed="addVerifyCount = setting.addVerifyCount">
|
||||
<el-dialog v-model="addVerifyCountShow" :title="$t('rulesVerifyTitle',{count: addVerifyCount})"
|
||||
@closed="addVerifyCount = setting.addVerifyCount">
|
||||
<form>
|
||||
<el-input-number type="text" v-model="addVerifyCount" :min="1"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveAddVerifyCount">{{$t('save')}}</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveAddVerifyCount">{{ $t('save') }}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog top="5vh" v-model="noticePopupShow" :title="$t('noticePopup')" class="notice-popup" @closed="resetNoticeForm">
|
||||
<el-dialog top="5vh" v-model="noticePopupShow" :title="$t('noticePopup')" class="notice-popup"
|
||||
@closed="resetNoticeForm">
|
||||
<form>
|
||||
<el-input v-model="noticeForm.noticeTitle" :placeholder="t('titleDesc')" />
|
||||
<div class="notice-line-item" >
|
||||
<el-select v-model="noticeForm.noticeType" >
|
||||
<el-input v-model="noticeForm.noticeTitle" :placeholder="t('titleDesc')"/>
|
||||
<div class="notice-line-item">
|
||||
<el-select v-model="noticeForm.noticeType">
|
||||
<template #prefix>
|
||||
<span style="margin-right: 10px">{{$t('icon')}}</span>
|
||||
<span style="margin-right: 10px">{{ $t('icon') }}</span>
|
||||
</template>
|
||||
<el-option key="none" label="None" value="none" />
|
||||
<el-option key="primary" label="Primary" value="primary" />
|
||||
<el-option key="success" label="Success" value="success" />
|
||||
<el-option key="warning" label="Warning" value="warning" />
|
||||
<el-option key="info" label="Info" value="info" />
|
||||
<el-option key="none" label="None" value="none"/>
|
||||
<el-option key="primary" label="Primary" value="primary"/>
|
||||
<el-option key="success" label="Success" value="success"/>
|
||||
<el-option key="warning" label="Warning" value="warning"/>
|
||||
<el-option key="info" label="Info" value="info"/>
|
||||
</el-select>
|
||||
<el-select v-model="noticeForm.noticePosition" >
|
||||
<el-select v-model="noticeForm.noticePosition">
|
||||
<template #prefix>
|
||||
<span style="margin-right: 10px">{{$t('position')}}</span>
|
||||
<span style="margin-right: 10px">{{ $t('position') }}</span>
|
||||
</template>
|
||||
<el-option key="top-left" :label="t('topLeft')" value="top-left" />
|
||||
<el-option key="top-right" :label="t('topRight')" value="top-right" />
|
||||
<el-option key="bottom-left" :label="t('bottomLeft')" value="bottom-left" />
|
||||
<el-option key="bottom-right" :label="t('bottomRight')" value="bottom-right" />
|
||||
<el-option key="top-left" :label="t('topLeft')" value="top-left"/>
|
||||
<el-option key="top-right" :label="t('topRight')" value="top-right"/>
|
||||
<el-option key="bottom-left" :label="t('bottomLeft')" value="bottom-left"/>
|
||||
<el-option key="bottom-right" :label="t('bottomRight')" value="bottom-right"/>
|
||||
</el-select>
|
||||
<el-input-number v-model="noticeForm.noticeWidth" >
|
||||
<template #prefix >
|
||||
{{$t('width')}}
|
||||
<el-input-number v-model="noticeForm.noticeWidth">
|
||||
<template #prefix>
|
||||
{{ $t('width') }}
|
||||
</template>
|
||||
<template #suffix >
|
||||
<template #suffix>
|
||||
px
|
||||
</template>
|
||||
</el-input-number>
|
||||
<el-input-number v-model="noticeForm.noticeOffset" >
|
||||
<template #prefix >
|
||||
{{$t('offset')}}
|
||||
<el-input-number v-model="noticeForm.noticeOffset">
|
||||
<template #prefix>
|
||||
{{ $t('offset') }}
|
||||
</template>
|
||||
<template #suffix >
|
||||
<template #suffix>
|
||||
px
|
||||
</template>
|
||||
</el-input-number>
|
||||
<el-input-number v-model="noticeForm.noticeDuration" >
|
||||
<template #prefix >
|
||||
{{$t('duration')}}
|
||||
<el-input-number v-model="noticeForm.noticeDuration">
|
||||
<template #prefix>
|
||||
{{ $t('duration') }}
|
||||
</template>
|
||||
<template #suffix >
|
||||
<template #suffix>
|
||||
ms
|
||||
</template>
|
||||
</el-input-number>
|
||||
@@ -597,13 +619,14 @@
|
||||
</form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-switch v-model="noticeForm.notice" :active-value="0" :inactive-value="1" :active-text="$t('enable')" :inactive-text="$t('disable')" />
|
||||
<el-switch v-model="noticeForm.notice" :active-value="0" :inactive-value="1" :active-text="$t('enable')"
|
||||
:inactive-text="$t('disable')"/>
|
||||
<div>
|
||||
<el-button @click="previewNoticePopup">
|
||||
{{$t('preview')}}
|
||||
{{ $t('preview') }}
|
||||
</el-button>
|
||||
<el-button :loading="settingLoading" type="primary" @click="saveNoticePopup">
|
||||
{{$t('save')}}
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -627,14 +650,18 @@ import {debounce} from 'lodash-es'
|
||||
import {isEmail} from "@/utils/verify-utils.js";
|
||||
import loading from "@/components/loading/index.vue";
|
||||
import {getTextWidth} from "@/utils/text.js";
|
||||
import { fileToBase64 } from "@/utils/file-utils.js"
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {fileToBase64} from "@/utils/file-utils.js"
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import axios from "axios";
|
||||
|
||||
defineOptions({
|
||||
name: 'sys-setting'
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const currentVersion = 'v1.7.0'
|
||||
const hasUpdate = ref(false)
|
||||
let getUpdateErrorCount = 1;
|
||||
const {t, locale} = useI18n();
|
||||
const firstLoading = ref(true)
|
||||
const backgroundImage = ref('')
|
||||
const localUpShow = ref(false)
|
||||
@@ -711,6 +738,7 @@ const ruleType = ref(0)
|
||||
const ruleEmail = ref([])
|
||||
|
||||
getSettings()
|
||||
getUpdate()
|
||||
|
||||
function getSettings() {
|
||||
settingQuery().then(settingData => {
|
||||
@@ -772,8 +800,22 @@ const resendList = computed(() => {
|
||||
return list;
|
||||
});
|
||||
|
||||
function getUpdate() {
|
||||
if (getUpdateErrorCount > 5 || !getUpdateErrorCount) return
|
||||
axios.get('https://api.github.com/repos/eoao/cloud-mail/releases/latest').then(({data}) => {
|
||||
hasUpdate.value = data.name !== currentVersion
|
||||
getUpdateErrorCount = 0
|
||||
}).catch(e => {
|
||||
getUpdateErrorCount++
|
||||
setTimeout(() => {
|
||||
getUpdate()
|
||||
}, 2000)
|
||||
console.error('检查更新失败:', e)
|
||||
})
|
||||
}
|
||||
|
||||
function saveAddVerifyCount() {
|
||||
if(!addVerifyCount.value) {
|
||||
if (!addVerifyCount.value) {
|
||||
addVerifyCount.value = 1
|
||||
}
|
||||
editSetting({addVerifyCount: addVerifyCount.value})
|
||||
@@ -832,9 +874,9 @@ function resetNoticeForm() {
|
||||
}
|
||||
|
||||
function saveNoticePopup() {
|
||||
noticeForm.noticeOffset = noticeForm.noticeOffset || 0
|
||||
noticeForm.noticeWidth = noticeForm.noticeWidth || 0
|
||||
noticeForm.noticeDuration = noticeForm.noticeDuration || 0
|
||||
noticeForm.noticeOffset = noticeForm.noticeOffset || 0
|
||||
noticeForm.noticeWidth = noticeForm.noticeWidth || 0
|
||||
noticeForm.noticeDuration = noticeForm.noticeDuration || 0
|
||||
editSetting({...noticeForm})
|
||||
}
|
||||
|
||||
@@ -899,9 +941,9 @@ function addChatTag(val) {
|
||||
tgChatId.value.splice(tgChatId.value.length - 1, 1)
|
||||
|
||||
chatIds.forEach(id => {
|
||||
if (!isNaN(Number(id))) {
|
||||
tgChatId.value.push(id)
|
||||
}
|
||||
if (!isNaN(Number(id))) {
|
||||
tgChatId.value.push(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -934,7 +976,7 @@ function ruleEmailSave() {
|
||||
function doOpacityChange() {
|
||||
const form = {}
|
||||
form.loginOpacity = loginOpacity.value
|
||||
editSetting(form,true)
|
||||
editSetting(form, true)
|
||||
}
|
||||
|
||||
const opacityChange = debounce(doOpacityChange, 1000, {
|
||||
@@ -986,7 +1028,7 @@ async function saveBackground() {
|
||||
let image = ''
|
||||
|
||||
if (localUpShow.value) {
|
||||
image = await fileToBase64(backgroundFile,true);
|
||||
image = await fileToBase64(backgroundFile, true);
|
||||
} else {
|
||||
if (backgroundUrl.value && !backgroundUrl.value.startsWith('http')) {
|
||||
ElMessage({
|
||||
@@ -1127,7 +1169,8 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
.settings-container {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: #FAFCFF !important;
|
||||
background: var(--extra-light-fill) !important;
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1139,9 +1182,11 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
.scroll {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
|
||||
:deep(.el-scrollbar__view) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scroll-body {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
@@ -1169,7 +1214,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
width: 250px;
|
||||
height: 140px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border: 1px solid var(--light-border);
|
||||
@media (max-width: 500px) {
|
||||
width: 150px;
|
||||
height: 83px;
|
||||
@@ -1187,7 +1232,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
}
|
||||
|
||||
.settings-card {
|
||||
background-color: #fff;
|
||||
background-color: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
transition: all 300ms;
|
||||
@@ -1195,7 +1240,6 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
@@ -1215,6 +1259,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 10px;
|
||||
font-weight: normal;
|
||||
|
||||
> div:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1232,14 +1277,13 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
.title-icon.warning {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
color: gray;
|
||||
cursor: pointer;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.warning {
|
||||
margin-left: 4px;
|
||||
color: gray;
|
||||
color: grey;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1268,9 +1312,11 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 15px;
|
||||
|
||||
> * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 840px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
@@ -1318,7 +1364,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
}
|
||||
|
||||
:deep(.el-table__inner-wrapper:before) {
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
:deep(.cut-dialog.el-dialog) {
|
||||
@@ -1340,17 +1386,18 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
.forward-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.forward-set-title {
|
||||
top: 1px;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
font-weight: bold;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-image {
|
||||
background: #f5f7fa;
|
||||
background: var(--light-ill);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1363,6 +1410,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.el-button {
|
||||
width: fit-content;
|
||||
}
|
||||
@@ -1374,6 +1422,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1393,6 +1442,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
.el-switch {
|
||||
align-self: end;
|
||||
}
|
||||
@@ -1451,6 +1501,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
|
||||
:deep(.el-button) {
|
||||
padding: 0 10px;
|
||||
font-weight: normal;
|
||||
|
||||
i {
|
||||
font-size: 22px;
|
||||
@@ -1469,6 +1520,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
gap: 10px;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-select v-model="params.status" placeholder="Select" class="status-select" :style="`width: ${locale === 'en' ? 95 : 80 }px`">
|
||||
<el-select v-model="params.status" placeholder="Select" class="status-select"
|
||||
:style="`width: ${locale === 'en' ? 95 : 80 }px`">
|
||||
<el-option :key="-1" :label="$t('all')" :value="-1"/>
|
||||
<el-option :key="0" :label="$t('active')" :value="0"/>
|
||||
<el-option :key="1" :label="$t('banned')" :value="1"/>
|
||||
@@ -26,7 +27,8 @@
|
||||
</div>
|
||||
<el-scrollbar ref="scrollbarRef" class="scrollbar">
|
||||
<div>
|
||||
<div class="loading" :class="tableLoading ? 'loading-show' : 'loading-hide'">
|
||||
<div class="loading" :class="tableLoading ? 'loading-show' : 'loading-hide'"
|
||||
:style="first ? 'background: transparent' : ''">
|
||||
<loading/>
|
||||
</div>
|
||||
<el-table
|
||||
@@ -41,60 +43,78 @@
|
||||
<el-table-column :width="expandWidth" type="expand">
|
||||
<template #default="props">
|
||||
<div class="details">
|
||||
<div v-if="!sendNumShow"><span class="details-item-title">{{$t('tabSent')}}:</span>{{ props.row.sendEmailCount }}
|
||||
<div v-if="!sendNumShow"><span
|
||||
class="details-item-title">{{ $t('tabSent') }}:</span>{{ props.row.sendEmailCount }}
|
||||
</div>
|
||||
<div v-if="!accountNumShow"><span class="details-item-title">{{$t('tabMailboxes')}}:</span>{{
|
||||
<div v-if="!accountNumShow"><span class="details-item-title">{{ $t('tabMailboxes') }}:</span>{{
|
||||
props.row.accountCount
|
||||
}}
|
||||
</div>
|
||||
<div v-if="!createTimeShow"><span class="details-item-title">{{$t('tabRegisteredAt')}}:</span>{{
|
||||
<div v-if="!createTimeShow"><span class="details-item-title">{{ $t('tabRegisteredAt') }}:</span>{{
|
||||
tzDayjs(props.row.createTime).format('YYYY-MM-DD HH:mm')
|
||||
}}
|
||||
</div>
|
||||
<div v-if="!typeShow"><span class="details-item-title">{{$t('perm')}}:</span> {{ toRoleName(props.row.type) }}
|
||||
<div v-if="!typeShow"><span class="details-item-title">{{ $t('perm') }}:</span>
|
||||
{{ toRoleName(props.row.type) }}
|
||||
</div>
|
||||
<div v-if="!statusShow">
|
||||
<span class="details-item-title">{{$t('tabStatus')}}:</span>
|
||||
<el-tag disable-transitions v-if="props.row.isDel === 1" type="info">{{$t('deleted')}}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">{{$t('active')}}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">{{$t('banned')}}</el-tag>
|
||||
<span class="details-item-title">{{ $t('tabStatus') }}:</span>
|
||||
<el-tag disable-transitions v-if="props.row.isDel === 1" type="info">{{ $t('deleted') }}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">{{ $t('active') }}
|
||||
</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">{{ $t('banned') }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div><span class="details-item-title">{{$t('registrationIp')}}:</span>{{ props.row.createIp || $t('unknown') }}</div>
|
||||
<div><span class="details-item-title">{{$t('recentIP')}}:</span>{{ props.row.activeIp || $t('unknown') }}</div>
|
||||
<div><span class="details-item-title">{{$t('recentActivity')}}:</span>{{
|
||||
<div><span class="details-item-title">{{ $t('registrationIp') }}:</span>{{
|
||||
props.row.createIp || $t('unknown')
|
||||
}}
|
||||
</div>
|
||||
<div><span class="details-item-title">{{ $t('recentIP') }}:</span>{{
|
||||
props.row.activeIp || $t('unknown')
|
||||
}}
|
||||
</div>
|
||||
<div><span class="details-item-title">{{ $t('recentActivity') }}:</span>{{
|
||||
props.row.activeTime ? tzDayjs(props.row.activeTime).format('YYYY-MM-DD') : $t('unknown')
|
||||
}}
|
||||
</div>
|
||||
<div><span class="details-item-title">{{$t('loginDevice')}}:</span>{{ props.row.device || $t('unknown') }}</div>
|
||||
<div><span class="details-item-title">{{$t('loginSystem')}}:</span>{{ props.row.os || $t('unknown') }}</div>
|
||||
<div><span class="details-item-title">{{$t('browserLogin')}}:</span>{{ props.row.browser || $t('unknown') }}</div>
|
||||
<div><span
|
||||
class="details-item-title">{{ $t('loginDevice') }}:</span>{{ props.row.device || $t('unknown') }}
|
||||
</div>
|
||||
<div><span class="details-item-title">{{ $t('loginSystem') }}:</span>{{ props.row.os || $t('unknown') }}
|
||||
</div>
|
||||
<div><span
|
||||
class="details-item-title">{{ $t('browserLogin') }}:</span>{{ props.row.browser || $t('unknown') }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="details-item-title">{{$t('sendEmail')}}:</span>
|
||||
<span class="details-item-title">{{ $t('sendEmail') }}:</span>
|
||||
<span>{{ formatSendCount(props.row) }}</span>
|
||||
<el-tag style="margin-left: 10px" v-if="props.row.sendAction.hasPerm" >
|
||||
<el-tag style="margin-left: 10px" v-if="props.row.sendAction.hasPerm">
|
||||
{{ formatSendType(props.row) }}
|
||||
</el-tag>
|
||||
<el-button size="small" style="margin-left: 10px"
|
||||
v-if="props.row.sendAction.hasPerm && props.row.sendAction.sendCount"
|
||||
@click="resetSendCount(props.row)" type="primary">{{$t('reset')}}
|
||||
@click="resetSendCount(props.row)" type="primary">{{ $t('reset') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column show-overflow-tooltip :tooltip-formatter="tableRowFormatter" :label="$t('tabEmailAddress')" :min-width="emailWidth">
|
||||
<el-table-column show-overflow-tooltip :tooltip-formatter="tableRowFormatter" :label="$t('tabEmailAddress')"
|
||||
:min-width="emailWidth">
|
||||
<template #default="props">
|
||||
<div class="email-row">{{ props.row.email }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :formatter="formatterReceive" label-class-name="receive" column-key="receive"
|
||||
:filtered-value="filteredValue" :filters="filters" :width="receiveWidth" :label="$t('tabReceived')"
|
||||
:filtered-value="filteredValue" :filters="filters" :width="receiveWidth"
|
||||
:label="$t('tabReceived')"
|
||||
prop="receiveEmailCount"/>
|
||||
<el-table-column :formatter="formatterSend" label-class-name="send" column-key="send"
|
||||
:filtered-value="filteredValue" :filters="filters" v-if="sendNumShow" :label="$t('tabSent')"
|
||||
prop="sendEmailCount"/>
|
||||
<el-table-column :formatter="formatterAccount" label-class-name="account" column-key="account"
|
||||
:filtered-value="filteredValue" :filters="filters" v-if="accountNumShow" :label="$t('tabMailboxes')"
|
||||
:filtered-value="filteredValue" :filters="filters" v-if="accountNumShow"
|
||||
:label="$t('tabMailboxes')"
|
||||
prop="accountCount"/>
|
||||
<el-table-column v-if="createTimeShow" :label="$t('tabRegisteredAt')" min-width="160" prop="createTime">
|
||||
<template #default="props">
|
||||
@@ -103,9 +123,9 @@
|
||||
</el-table-column>
|
||||
<el-table-column v-if="statusShow" min-width="60px" :label="$t('tabStatus')" prop="status">
|
||||
<template #default="props">
|
||||
<el-tag disable-transitions v-if="props.row.isDel === 1" type="info">{{$t('deleted')}}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">{{$t('active')}}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">{{$t('banned')}}</el-tag>
|
||||
<el-tag disable-transitions v-if="props.row.isDel === 1" type="info">{{ $t('deleted') }}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">{{ $t('active') }}</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">{{ $t('banned') }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="typeShow" :label="$t('tabRole')" min-width="140" prop="type">
|
||||
@@ -118,16 +138,16 @@
|
||||
<el-table-column :label="$t('tabSetting')" :width="settingWidth">
|
||||
<template #default="props">
|
||||
<el-dropdown trigger="click">
|
||||
<el-button size="small" type="primary">{{$t('action')}}</el-button>
|
||||
<el-button size="small" type="primary">{{ $t('action') }}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openSetPwd(props.row)">{{$t('chgPwd')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="openSetType(props.row)">{{$t('perm')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="openSetPwd(props.row)">{{ $t('chgPwd') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="openSetType(props.row)">{{ $t('perm') }}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="props.row.isDel !== 1" @click="setStatus(props.row)">
|
||||
{{ setStatusName(props.row) }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-else @click="restore(props.row)">{{$t('restore')}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="delUser(props.row)">{{$t('delete')}}</el-dropdown-item>
|
||||
<el-dropdown-item v-else @click="restore(props.row)">{{ $t('restore') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="delUser(props.row)">{{ $t('delete') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -168,18 +188,18 @@
|
||||
<el-input v-model="userForm.password" type="password" :placeholder="$t('newPassword')" autocomplete="off">
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" :loading="settingLoading" @click="updatePwd"
|
||||
>{{$t('save')}}
|
||||
>{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog class="dialog" v-model="setTypeShow" :title="$t('changePerm')" @closed="resetUserForm">
|
||||
<div class="dialog-box">
|
||||
<el-input disabled :model-value="$t('admin')" v-if="userForm.type === 0" />
|
||||
<el-select v-else v-model="userForm.type" placeholder="Select" >
|
||||
<el-input disabled :model-value="$t('admin')" v-if="userForm.type === 0"/>
|
||||
<el-select v-else v-model="userForm.type" placeholder="Select">
|
||||
<el-option v-for="item in roleList" :label="item.name" :value="item.roleId" :key="item.roleId"/>
|
||||
</el-select>
|
||||
<el-button :disabled="userForm.type === 0" class="btn" :loading="settingLoading" type="primary" @click="setType"
|
||||
>{{$t('save')}}
|
||||
>{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -201,7 +221,7 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<div>
|
||||
<span>{{ addForm.suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
@@ -213,7 +233,7 @@
|
||||
<el-option v-for="item in roleList" :label="item.name" :value="item.roleId" :key="item.roleId"/>
|
||||
</el-select>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="addLoading"
|
||||
>{{$t('add')}}
|
||||
>{{ $t('add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -239,13 +259,13 @@ import {useSettingStore} from "@/store/setting.js";
|
||||
import {isEmail} from "@/utils/verify-utils.js";
|
||||
import {useRoleStore} from "@/store/role.js";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'user'
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const {t, locale} = useI18n();
|
||||
const roleStore = useRoleStore()
|
||||
const userStore = useUserStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -319,7 +339,7 @@ if (paramsStar) {
|
||||
}
|
||||
|
||||
watch(() => params, () => {
|
||||
localStorage.setItem('user-params',JSON.stringify(params))
|
||||
localStorage.setItem('user-params', JSON.stringify(params))
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
@@ -535,7 +555,7 @@ function toRoleName(type) {
|
||||
|
||||
function resetSendCount(user) {
|
||||
|
||||
ElMessageBox.confirm(t('reSendConfirm',{msg: user.email}), {
|
||||
ElMessageBox.confirm(t('reSendConfirm', {msg: user.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
@@ -552,7 +572,7 @@ function resetSendCount(user) {
|
||||
}
|
||||
|
||||
function delUser(user) {
|
||||
ElMessageBox.confirm(t('delConfirm',{msg: user.email}), {
|
||||
ElMessageBox.confirm(t('delConfirm', {msg: user.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
@@ -572,22 +592,22 @@ function restore(user) {
|
||||
|
||||
const type = ref(0)
|
||||
|
||||
ElMessageBox.confirm( null, {
|
||||
ElMessageBox.confirm(null, {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
message: () => h('div', [
|
||||
h('div', { class: 'mb-2' }, t('restoreConfirm', {msg: user.email})),
|
||||
h('div', {class: 'mb-2'}, t('restoreConfirm', {msg: user.email})),
|
||||
h(ElRadioGroup, {
|
||||
modelValue: type.value,
|
||||
'onUpdate:modelValue': (val) => (type.value = val),
|
||||
}, [
|
||||
h(ElRadio, { label: 'option1', value: 0 }, t('normalRestore')),
|
||||
h(ElRadio, { label: 'option2', value: 1 }, t('allRestore')),
|
||||
h(ElRadio, {label: 'option1', value: 0}, t('normalRestore')),
|
||||
h(ElRadio, {label: 'option2', value: 1}, t('allRestore')),
|
||||
])
|
||||
]),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userRestore(user.userId,type.value).then(() => {
|
||||
userRestore(user.userId, type.value).then(() => {
|
||||
user.isDel = 0
|
||||
ElMessage({
|
||||
message: t('restoreSuccessMsg'),
|
||||
@@ -601,7 +621,7 @@ function restore(user) {
|
||||
function setStatus(user) {
|
||||
|
||||
if (user.status === 0) {
|
||||
ElMessageBox.confirm(t('banRestore',{ msg: user.email }), {
|
||||
ElMessageBox.confirm(t('banRestore', {msg: user.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
@@ -740,7 +760,9 @@ function getUserList(loading = true) {
|
||||
scrollbarRef.value?.setScrollTop(0);
|
||||
}).finally(() => {
|
||||
tableLoading.value = false
|
||||
first.value = false
|
||||
setTimeout(() => {
|
||||
first.value = false
|
||||
}, 200)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -778,12 +800,6 @@ function adjustWidth() {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.el-table-filter__bottom {
|
||||
button:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table-filter__content {
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -810,7 +826,7 @@ function adjustWidth() {
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
box-shadow: var(--header-actions-border);
|
||||
font-size: 18px;
|
||||
|
||||
.search-input {
|
||||
@@ -864,6 +880,7 @@ function adjustWidth() {
|
||||
@media (max-width: 767px) {
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
.details-item-title {
|
||||
white-space: pre;
|
||||
color: #909399;
|
||||
@@ -925,7 +942,7 @@ function adjustWidth() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
background-color: var(--loadding-background);
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
@@ -956,13 +973,13 @@ function adjustWidth() {
|
||||
|
||||
:deep(.el-pagination .el-select) {
|
||||
width: 100px;
|
||||
background: #FFF;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0 !important;
|
||||
padding-left: 8px !important;
|
||||
background: #FFFFFF;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
:deep(.el-dialog) {
|
||||
@@ -997,7 +1014,7 @@ function adjustWidth() {
|
||||
}
|
||||
|
||||
:deep(.el-table__inner-wrapper:before) {
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
:deep(.el-message-box__container) {
|
||||
|
||||
Reference in New Issue
Block a user