新增支持API添加用户,查询邮件
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
NODE_ENV = 'remote'
|
||||
VITE_APP_TITLE = '远程环境'
|
||||
VITE_BASE_URL = 'https://mornglow.top/api'
|
||||
VITE_BASE_URL = ''
|
||||
|
||||
@@ -133,6 +133,7 @@ const en = {
|
||||
loginSwitch: 'Sign in',
|
||||
websiteSetting: 'Website',
|
||||
websiteReg: 'Sign Up',
|
||||
loginDomain: 'Sign-In Box Domain',
|
||||
multipleEmail: 'Multiple Accounts',
|
||||
multipleEmailDesc: 'Enable this feature to allow users to add multiple accounts.',
|
||||
physicallyWipeData: 'Physically Wipe Data',
|
||||
@@ -262,7 +263,7 @@ const en = {
|
||||
rulesVerifyTitle: 'Trigger After {count} Daily Uses per IP',
|
||||
botVerifyMsg: 'Please verify that you are human',
|
||||
noticeTitle: 'Notice',
|
||||
noticePopup: 'Sign-in Popup',
|
||||
noticePopup: 'Sign-In Popup',
|
||||
icon: 'Icon',
|
||||
position: 'Position',
|
||||
offset: 'Offset',
|
||||
@@ -278,7 +279,9 @@ const en = {
|
||||
popUp: 'Pop Up',
|
||||
noRecipientTitle: 'No Recipient',
|
||||
noRecipientDesc: 'Emails can be received even without a registered email address.',
|
||||
preview: 'Preview'
|
||||
preview: 'Preview',
|
||||
help: 'Help',
|
||||
document: 'Document'
|
||||
}
|
||||
|
||||
export default en
|
||||
|
||||
@@ -18,7 +18,7 @@ const zh = {
|
||||
deleteUserBtn: '删除账户',
|
||||
changePassword: '修改密码',
|
||||
newPassword: '新的密码',
|
||||
confirmPassword: '旧的密码',
|
||||
confirmPassword: '确认密码',
|
||||
add: '添加',
|
||||
manage: '管理',
|
||||
rename: '改名',
|
||||
@@ -133,6 +133,7 @@ const zh = {
|
||||
loginSwitch: '去登录',
|
||||
websiteSetting: '网站设置',
|
||||
websiteReg: '用户注册',
|
||||
loginDomain: '登录框域名',
|
||||
multipleEmail: '多号模式',
|
||||
multipleEmailDesc: '开启后账号栏出现一个用户可以添加多个邮箱',
|
||||
physicallyWipeData: '物理清空数据',
|
||||
@@ -246,7 +247,7 @@ const zh = {
|
||||
totalUserAccount: '{msg} 个',
|
||||
sendBanned: '已禁用',
|
||||
wrote: '来信',
|
||||
support: '赞助',
|
||||
support: '捐助',
|
||||
supportDesc: '请我喝杯奶茶',
|
||||
featDesc: '功能说明',
|
||||
emailInterception: '邮件拦截',
|
||||
@@ -278,7 +279,9 @@ const zh = {
|
||||
popUp: '弹出',
|
||||
noRecipientTitle: '无人收件',
|
||||
noRecipientDesc: '即使没有注册的邮箱也能收到邮件',
|
||||
preview: '预览'
|
||||
preview: '预览',
|
||||
help: '帮助',
|
||||
document: '项目文档'
|
||||
|
||||
}
|
||||
export default zh
|
||||
export default zh
|
||||
|
||||
@@ -1,28 +1,33 @@
|
||||
<template>
|
||||
<div class="account-box">
|
||||
<div class="head-opt" >
|
||||
<Icon v-perm="'account:add'" class="icon add" icon="ion:add-outline" width="23" height="23" @click="add" />
|
||||
<Icon class="icon refresh" icon="ion:reload" width="18" height="18" @click="refresh" />
|
||||
<div class="head-opt">
|
||||
<Icon v-perm="'account:add'" class="icon add" icon="ion:add-outline" width="23" height="23" @click="add"/>
|
||||
<Icon class="icon refresh" icon="ion:reload" width="18" height="18" @click="refresh"/>
|
||||
</div>
|
||||
<el-scrollbar class="scrollbar">
|
||||
<div v-infinite-scroll="getAccountList" :infinite-scroll-distance="600" :infinite-scroll-immediate="false">
|
||||
<el-card class="item" :class="itemBg(item.accountId)" v-for="item in accounts" :key="item.accountId" @click="changeAccount(item)">
|
||||
<div class="account" >
|
||||
<div v-infinite-scroll="getAccountList" :infinite-scroll-distance="600" :infinite-scroll-immediate="false">
|
||||
<el-card class="item" :class="itemBg(item.accountId)" v-for="item in accounts" :key="item.accountId"
|
||||
@click="changeAccount(item)">
|
||||
<div class="account">
|
||||
{{ item.email }}
|
||||
</div>
|
||||
<div class="opt">
|
||||
<div class="send-email" @click.stop>
|
||||
<Icon icon="eva:email-fill" width="22" height="22" color="#fccb1a" />
|
||||
<Icon icon="eva:email-fill" width="22" height="22" color="#fccb1a"/>
|
||||
</div>
|
||||
<div class="settings" @click.stop>
|
||||
<Icon icon="fluent-color:clipboard-24" width="22" height="22" @click.stop="copyAccount(item.email)"/>
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" v-if="showNullSetting(item)" />
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399"
|
||||
v-if="showNullSetting(item)"/>
|
||||
<el-dropdown v-else>
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" />
|
||||
<template #dropdown >
|
||||
<el-dropdown-menu >
|
||||
<el-dropdown-item v-if="hasPerm('email:send')" @click="openSetName(item)">{{$t('rename')}}</el-dropdown-item>
|
||||
<el-dropdown-item v-if="item.accountId !== userStore.user.accountId && hasPerm('account:delete')" @click="remove(item)">{{$t('delete')}}</el-dropdown-item>
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399"/>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPerm('email:send')" @click="openSetName(item)">{{ $t('rename') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="item.accountId !== userStore.user.accountId && hasPerm('account:delete')"
|
||||
@click="remove(item)">{{ $t('delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -32,13 +37,13 @@
|
||||
|
||||
<!-- Initial Loading Skeleton -->
|
||||
<template v-if="loading">
|
||||
<el-skeleton v-for="i in 3" :key="i" animated>
|
||||
<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: 20px"/>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<el-skeleton-item variant="text" style="width: 20px" />
|
||||
<el-skeleton-item variant="text" style="width: 20px" />
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -50,10 +55,10 @@
|
||||
<el-skeleton 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: 20px"/>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<el-skeleton-item variant="text" style="width: 20px" />
|
||||
<el-skeleton-item variant="text" style="width: 20px" />
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
<el-skeleton-item variant="text" style="width: 20px"/>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -61,43 +66,43 @@
|
||||
</template>
|
||||
|
||||
<div class="noLoading" v-if="noLoading && accounts.length > 0">
|
||||
<div>{{$t('noMoreData')}}</div>
|
||||
<div>{{ $t('noMoreData') }}</div>
|
||||
</div>
|
||||
<div class="empty" v-if="noLoading && accounts.length === 0">
|
||||
<el-empty :description="$t('noMessagesFound')" />
|
||||
<el-empty :description="$t('noMessagesFound')"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-scrollbar>
|
||||
<el-dialog v-model="showAdd" :title="$t('addAccount')" >
|
||||
<div class="container">
|
||||
<el-input v-model="addForm.email" ref="addRef" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="addForm.suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span >{{addForm.suffix}}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20" />
|
||||
</div>
|
||||
<el-dialog v-model="showAdd" :title="$t('addAccount')">
|
||||
<div class="container">
|
||||
<el-input v-model="addForm.email" ref="addRef" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="addForm.suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span>{{ addForm.suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="addLoading"
|
||||
>{{$t('add')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="addLoading"
|
||||
>{{ $t('add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div
|
||||
class="add-email-turnstile"
|
||||
:class="verifyShow ? 'turnstile-show' : 'turnstile-hide'"
|
||||
@@ -105,15 +110,15 @@
|
||||
data-callback="onTurnstileSuccess"
|
||||
data-error-callback="onTurnstileError"
|
||||
>
|
||||
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">人机验证模块加载失败,请刷新浏览器</span>
|
||||
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">{{ $t('verifyModuleFailed') }}</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="setNameShow" :title="$t('changeUserName')" >
|
||||
<el-dialog v-model="setNameShow" :title="$t('changeUserName')">
|
||||
<div class="container">
|
||||
<el-input v-model="accountName" type="text" :placeholder="$t('username')" autocomplete="off">
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="setName" :loading="setNameLoading"
|
||||
>{{$t('save')}}
|
||||
>{{ $t('save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -127,10 +132,10 @@ import {isEmail} from "@/utils/verify-utils.js";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import {useAccountStore} from "@/store/account.js";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import { hasPerm } from "@/perm/perm.js"
|
||||
import {hasPerm} from "@/perm/perm.js"
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const {t} = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const accountStore = useAccountStore();
|
||||
const settingStore = useSettingStore();
|
||||
@@ -150,6 +155,7 @@ let account = null
|
||||
let turnstileId = null
|
||||
const botJsError = ref(false)
|
||||
let verifyToken = ''
|
||||
let verifyErrorCount = 0
|
||||
const addForm = reactive({
|
||||
email: '',
|
||||
suffix: settingStore.domainList[0]
|
||||
@@ -175,14 +181,20 @@ const openSelect = () => {
|
||||
}
|
||||
|
||||
window.onTurnstileError = (e) => {
|
||||
console.log('人机验加载失败')
|
||||
nextTick(() => {
|
||||
if (!turnstileId) {
|
||||
turnstileId = window.turnstile.render('.register-turnstile')
|
||||
} else {
|
||||
window.turnstile.reset(turnstileId);
|
||||
}
|
||||
})
|
||||
if (verifyErrorCount >= 4) {
|
||||
return
|
||||
}
|
||||
verifyErrorCount++
|
||||
console.warn('人机验加载失败', e)
|
||||
setTimeout(() => {
|
||||
nextTick(() => {
|
||||
if (!turnstileId) {
|
||||
turnstileId = window.turnstile.render('.add-email-turnstile')
|
||||
} else {
|
||||
window.turnstile.reset(turnstileId);
|
||||
}
|
||||
})
|
||||
}, 1500)
|
||||
};
|
||||
|
||||
window.onTurnstileSuccess = (token) => {
|
||||
@@ -208,7 +220,7 @@ function setName() {
|
||||
}
|
||||
|
||||
setNameLoading.value = true
|
||||
accountSetName(account.accountId,name).then(() => {
|
||||
accountSetName(account.accountId, name).then(() => {
|
||||
account.name = name
|
||||
setNameShow.value = false
|
||||
|
||||
@@ -221,12 +233,12 @@ function setName() {
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
}).finally(()=> {
|
||||
}).finally(() => {
|
||||
setNameLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function openSetName (accountItem) {
|
||||
function openSetName(accountItem) {
|
||||
accountName.value = accountItem.name
|
||||
account = accountItem
|
||||
setNameShow.value = true
|
||||
@@ -241,7 +253,7 @@ function itemBg(accountId) {
|
||||
}
|
||||
|
||||
function remove(account) {
|
||||
ElMessageBox.confirm(t('delConfirm',{msg: account.email}), {
|
||||
ElMessageBox.confirm(t('delConfirm', {msg: account.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
@@ -272,6 +284,7 @@ function refresh() {
|
||||
accounts.splice(0, accounts.length)
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
function changeAccount(account) {
|
||||
accountStore.currentAccountId = account.accountId
|
||||
accountStore.currentAccount = account
|
||||
@@ -281,7 +294,7 @@ function add() {
|
||||
showAdd.value = true
|
||||
setTimeout(() => {
|
||||
addRef.value.focus()
|
||||
},100)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
async function copyAccount(account) {
|
||||
@@ -308,11 +321,11 @@ function getAccountList() {
|
||||
|
||||
if (accounts.length === 0) {
|
||||
loading.value = true
|
||||
}else {
|
||||
} else {
|
||||
followLoading.value = true
|
||||
}
|
||||
|
||||
accountList(queryParams.accountId,queryParams.size).then(list => {
|
||||
accountList(queryParams.accountId, queryParams.size).then(list => {
|
||||
if (list.length < queryParams.size) {
|
||||
noLoading.value = true
|
||||
}
|
||||
@@ -331,9 +344,9 @@ function getAccountList() {
|
||||
}
|
||||
|
||||
|
||||
function submit() {
|
||||
function submit() {
|
||||
|
||||
if (!addForm.email){
|
||||
if (!addForm.email) {
|
||||
ElMessage({
|
||||
message: t('emptyEmailMsg'),
|
||||
type: "error",
|
||||
@@ -342,7 +355,7 @@ function submit() {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isEmail(addForm.email+addForm.suffix)) {
|
||||
if (!isEmail(addForm.email + addForm.suffix)) {
|
||||
ElMessage({
|
||||
message: t('notEmailMsg'),
|
||||
type: "error",
|
||||
@@ -376,7 +389,7 @@ function submit() {
|
||||
}
|
||||
|
||||
addLoading.value = true
|
||||
accountAdd(addForm.email+addForm.suffix,verifyToken).then(account => {
|
||||
accountAdd(addForm.email + addForm.suffix, verifyToken).then(account => {
|
||||
addLoading.value = false
|
||||
showAdd.value = false
|
||||
addForm.email = ''
|
||||
@@ -418,6 +431,7 @@ path[fill="#ffdda1"] {
|
||||
background-color: #FFF;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.head-opt {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -425,9 +439,11 @@ path[fill="#ffdda1"] {
|
||||
box-shadow: inset 0 -1px 0 0 rgba(100, 121, 143, 0.12);
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
.icon{
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.refresh {
|
||||
margin-left: 10px;
|
||||
}
|
||||
@@ -440,6 +456,7 @@ path[fill="#ffdda1"] {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar {
|
||||
width: 100%;
|
||||
height: calc(100% - 38px);
|
||||
@@ -447,12 +464,14 @@ path[fill="#ffdda1"] {
|
||||
@media (max-width: 767px) {
|
||||
height: calc(100% - 98px);
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.noLoading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -461,6 +480,7 @@ path[fill="#ffdda1"] {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
margin-top: 15px;
|
||||
@@ -474,6 +494,7 @@ path[fill="#ffdda1"] {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
.account {
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
@@ -488,11 +509,13 @@ path[fill="#ffdda1"] {
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
|
||||
.settings {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.send-email {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -503,8 +526,9 @@ path[fill="#ffdda1"] {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.item:first-child{
|
||||
margin-top: 10px ;
|
||||
|
||||
.item:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.item-choose {
|
||||
@@ -560,4 +584,4 @@ path[fill="#ffdda1"] {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {createRouter, createWebHistory} from 'vue-router'
|
||||
import {useUiStore} from "@/store/ui.js";
|
||||
import {replace} from "lodash-es";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -81,7 +82,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
if (!token && to.name !== 'login') {
|
||||
|
||||
return next({
|
||||
name: 'login'
|
||||
name: 'login',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,6 +90,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
return next()
|
||||
}
|
||||
|
||||
if (token && to.name === 'login') {
|
||||
next(from.path)
|
||||
}
|
||||
|
||||
next()
|
||||
|
||||
})
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div v-if="analysisLoading" class="analysis-loading">
|
||||
<loading />
|
||||
<loading/>
|
||||
</div>
|
||||
<el-scrollbar v-else style="height: 100%;">
|
||||
<el-scrollbar v-else style="height: 100%;">
|
||||
<div class="analysis" :key="boxKey">
|
||||
<div class="number">
|
||||
<div class="number-item">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div>{{$t('totalReceived')}}</div>
|
||||
<div>{{ $t('totalReceived') }}</div>
|
||||
<div>
|
||||
<el-statistic :formatter="value => Math.round(value)" :value="receiveData"/>
|
||||
</div>
|
||||
@@ -20,14 +20,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-ratio">
|
||||
<div>{{$t('active')}} <span class="normal">{{numberCount.normalReceiveTotal}}</span></div>
|
||||
<div>{{$t('deleted')}} <span class="deleted">{{numberCount.delReceiveTotal}}</span></div>
|
||||
<div>{{ $t('active') }} <span class="normal">{{ numberCount.normalReceiveTotal }}</span></div>
|
||||
<div>{{ $t('deleted') }} <span class="deleted">{{ numberCount.delReceiveTotal }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="number-item">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div>{{$t('totalSent')}}</div>
|
||||
<div>{{ $t('totalSent') }}</div>
|
||||
<div>
|
||||
<el-statistic :formatter="value => Math.round(value)" :value="sendData"/>
|
||||
</div>
|
||||
@@ -39,14 +39,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-ratio">
|
||||
<div>{{$t('active')}} <span class="normal">{{numberCount.normalSendTotal}}</span></div>
|
||||
<div>{{$t('deleted')}} <span class="deleted">{{numberCount.delSendTotal}}</span></div>
|
||||
<div>{{ $t('active') }} <span class="normal">{{ numberCount.normalSendTotal }}</span></div>
|
||||
<div>{{ $t('deleted') }} <span class="deleted">{{ numberCount.delSendTotal }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="number-item">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div>{{$t('totalMailboxes')}}</div>
|
||||
<div>{{ $t('totalMailboxes') }}</div>
|
||||
<div>
|
||||
<el-statistic :formatter="value => Math.round(value)" :value="accountData"/>
|
||||
</div>
|
||||
@@ -58,14 +58,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-ratio">
|
||||
<div>{{$t('active')}} <span class="normal">{{numberCount.normalAccountTotal}}</span></div>
|
||||
<div>{{$t('deleted')}} <span class="deleted">{{numberCount.delAccountTotal}}</span></div>
|
||||
<div>{{ $t('active') }} <span class="normal">{{ numberCount.normalAccountTotal }}</span></div>
|
||||
<div>{{ $t('deleted') }} <span class="deleted">{{ numberCount.delAccountTotal }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="number-item">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div>{{$t('totalUsers')}}</div>
|
||||
<div>{{ $t('totalUsers') }}</div>
|
||||
<div>
|
||||
<el-statistic :formatter="value => Math.round(value)" :value="userData"/>
|
||||
</div>
|
||||
@@ -77,19 +77,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-ratio">
|
||||
<div>{{$t('active')}} <span class="normal">{{numberCount.normalUserTotal}}</span></div>
|
||||
<div>{{$t('deleted')}} <span class="deleted">{{numberCount.delUserTotal}}</span></div>
|
||||
<div>{{ $t('active') }} <span class="normal">{{ numberCount.normalUserTotal }}</span></div>
|
||||
<div>{{ $t('deleted') }} <span class="deleted">{{ numberCount.delUserTotal }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="picture">
|
||||
<div class="picture-item">
|
||||
<div class="title" style="display: flex;justify-content: space-between;">
|
||||
<span>{{$t('emailSource')}}</span>
|
||||
<span>{{ $t('emailSource') }}</span>
|
||||
<span class="source-button" v-if="false">
|
||||
<el-radio-group v-model="checkedSourceType" >
|
||||
<el-radio-button label="发件人" value="sender" />
|
||||
<el-radio-button label="邮箱" value="email" />
|
||||
<el-radio-group v-model="checkedSourceType">
|
||||
<el-radio-button label="发件人" value="sender"/>
|
||||
<el-radio-button label="邮箱" value="email"/>
|
||||
</el-radio-group>
|
||||
</span>
|
||||
</div>
|
||||
@@ -98,7 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="picture-item">
|
||||
<div class="title">{{$t('userGrowth')}}</div>
|
||||
<div class="title">{{ $t('userGrowth') }}</div>
|
||||
<div class="increase-line">
|
||||
|
||||
</div>
|
||||
@@ -106,11 +106,11 @@
|
||||
</div>
|
||||
<div class="picture-cs">
|
||||
<div class="picture-cs-item">
|
||||
<div class="title">{{$t('emailGrowth')}}</div>
|
||||
<div class="title">{{ $t('emailGrowth') }}</div>
|
||||
<div class="email-column"></div>
|
||||
</div>
|
||||
<div class="picture-cs-item">
|
||||
<div class="title">{{$t('sentToday')}}</div>
|
||||
<div class="title">{{ $t('sentToday') }}</div>
|
||||
<div class="send-count"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -129,13 +129,13 @@ import {useUiStore} from "@/store/ui.js";
|
||||
import {debounce} from "lodash-es";
|
||||
import loading from "@/components/loading/index.vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'analysis'
|
||||
})
|
||||
|
||||
const { t } = useI18n();
|
||||
const {t} = useI18n();
|
||||
const route = useRoute();
|
||||
const uiStore = useUiStore()
|
||||
const checkedSourceType = ref('sender')
|
||||
@@ -218,13 +218,12 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
userLineData.xdata = data.userDayCount.map(item => dayjs(item.date).format("M.D"))
|
||||
userLineData.xdata = data.userDayCount.map(item => dayjs(item.date).format("M.D"));
|
||||
userLineData.sdata = data.userDayCount.map(item => item.total)
|
||||
|
||||
emailColumnData.daysData = data.emailDayCount.receiveDayCount.map(item => dayjs(item.date).format("M.D"))
|
||||
emailColumnData.receiveData = data.emailDayCount.receiveDayCount.map(item => item.total)
|
||||
emailColumnData.sendData = data.emailDayCount.sendDayCount.map(item => item.total)
|
||||
|
||||
daySendTotal = data.daySendTotal
|
||||
analysisLoading.value = false
|
||||
initPicture();
|
||||
@@ -234,8 +233,8 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
function initPicture() {
|
||||
if(route.name !== 'analysis') return
|
||||
boxKey.value ++
|
||||
if (route.name !== 'analysis') return
|
||||
boxKey.value++
|
||||
setTimeout(() => {
|
||||
createSenderPie()
|
||||
createIncreaseLine()
|
||||
@@ -282,7 +281,7 @@ function setStyle() {
|
||||
const measureCtx = document.createElement('canvas').getContext('2d');
|
||||
measureCtx.font = '12px sans-serif';
|
||||
|
||||
function truncateTextByWidth(text,maxWidth = 140) {
|
||||
function truncateTextByWidth(text, maxWidth = 140) {
|
||||
|
||||
let width = measureCtx.measureText(text).width;
|
||||
if (width <= maxWidth) return text;
|
||||
@@ -311,22 +310,22 @@ function createSenderPie() {
|
||||
return `${params.marker} ${params.name}: ${params.value} (${params.percent}%)`;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
left: '10',
|
||||
top: '20',
|
||||
formatter: function (name) {
|
||||
return truncateTextByWidth(name)
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
type: 'scroll',
|
||||
orient: 'vertical',
|
||||
left: '10',
|
||||
top: '20',
|
||||
formatter: function (name) {
|
||||
return truncateTextByWidth(name)
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: senderData.value,
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['40%', '65%'],
|
||||
center: [ senderPieLeft, '45%'],
|
||||
center: [senderPieLeft, '45%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 4,
|
||||
@@ -378,7 +377,7 @@ function createIncreaseLine() {
|
||||
formatter: function (params) {
|
||||
let result = ''
|
||||
params.forEach(item => {
|
||||
result = `${item.marker} ${t('growthTotalUsers')} ${item.value}`;
|
||||
result = `${item.marker} ${t('growthTotalUsers')} ${item.value}`;
|
||||
});
|
||||
return result;
|
||||
},
|
||||
@@ -438,7 +437,7 @@ function createIncreaseLine() {
|
||||
},
|
||||
boundaryGap: [0, 0.1],
|
||||
max: (params) => {
|
||||
if (params.max < 8 ) {
|
||||
if (params.max < 8) {
|
||||
return 10
|
||||
}
|
||||
},
|
||||
@@ -493,6 +492,21 @@ function createIncreaseLine() {
|
||||
]
|
||||
};
|
||||
increaseLine.setOption(option);
|
||||
|
||||
let max = increaseLine.getModel().getComponent('yAxis', 0).axis.scale.getExtent()[1];
|
||||
|
||||
let left = 35
|
||||
|
||||
if (max > 99) left = 42
|
||||
if (max > 999) left = 51
|
||||
if (max > 9999) left = 58
|
||||
if (max > 99999) left = 66
|
||||
|
||||
increaseLine.setOption({
|
||||
grid: {
|
||||
left: left
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createEmailColumnChart() {
|
||||
@@ -537,7 +551,7 @@ function createEmailColumnChart() {
|
||||
},
|
||||
yAxis: {
|
||||
max: (params) => {
|
||||
if (params.max < 8 ) {
|
||||
if (params.max < 8) {
|
||||
return 10
|
||||
}
|
||||
},
|
||||
@@ -584,7 +598,7 @@ function createEmailColumnChart() {
|
||||
}
|
||||
|
||||
function createSendGauge() {
|
||||
if(sendGauge) {
|
||||
if (sendGauge) {
|
||||
sendGauge.dispose()
|
||||
}
|
||||
sendGauge = echarts.init(document.querySelector(".send-count"));
|
||||
@@ -649,6 +663,7 @@ function createSendGauge() {
|
||||
margin-top: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.percentage-label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
@@ -663,6 +678,7 @@ function createSendGauge() {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.analysis {
|
||||
height: 100%;
|
||||
padding: 20px 20px 30px;
|
||||
@@ -674,12 +690,14 @@ function createSendGauge() {
|
||||
padding: 15px 15px 30px;
|
||||
gap: 15px
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 10px;
|
||||
margin-left: 15px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.number {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
@@ -691,11 +709,13 @@ function createSendGauge() {
|
||||
@media (max-width: 767px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.number-item {
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
padding: 21px 20px;
|
||||
|
||||
.top {
|
||||
display: grid;
|
||||
justify-content: space-between;
|
||||
@@ -719,6 +739,7 @@ function createSendGauge() {
|
||||
.right {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
.count-icon {
|
||||
top: 3px;
|
||||
position: relative;
|
||||
@@ -740,6 +761,7 @@ function createSendGauge() {
|
||||
justify-content: start;
|
||||
gap: 20px;
|
||||
padding-top: 5px;
|
||||
|
||||
.normal {
|
||||
width: fit-content;
|
||||
color: var(--el-color-success);
|
||||
@@ -768,24 +790,29 @@ function createSendGauge() {
|
||||
@media (max-width: 1024px) {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.picture-item {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
|
||||
.source-button {
|
||||
padding-right: 15px;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
|
||||
:deep(.el-radio-button__inner) {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sender-pie {
|
||||
height: 350px;
|
||||
@media (max-width: 767px) {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.increase-line {
|
||||
height: 350px;
|
||||
@media (max-width: 767px) {
|
||||
@@ -803,16 +830,19 @@ function createSendGauge() {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.picture-cs-item {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color);
|
||||
|
||||
.send-count {
|
||||
height: 350px;
|
||||
@media (max-width: 767px) {
|
||||
height: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
.email-column {
|
||||
height: 350px;
|
||||
@media (max-width: 767px) {
|
||||
|
||||
@@ -9,89 +9,96 @@
|
||||
</div>
|
||||
<div v-else :style="background"></div>
|
||||
<div class="form-wrapper">
|
||||
<div class="container">
|
||||
<span class="form-title">{{settingStore.settings.title}}</span>
|
||||
<span class="form-desc" v-if="show === 'login'">{{$t('loginTitle')}}</span>
|
||||
<span class="form-desc" v-else>{{$t('regTitle')}}</span>
|
||||
<div v-show="show === 'login'">
|
||||
<el-input class="email-input" v-model="form.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
v-if="show === 'login'"
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
<div class="container">
|
||||
<span class="form-title">{{ settingStore.settings.title }}</span>
|
||||
<span class="form-desc" v-if="show === 'login'">{{ $t('loginTitle') }}</span>
|
||||
<span class="form-desc" v-else>{{ $t('regTitle') }}</span>
|
||||
<div v-show="show === 'login'">
|
||||
<el-input :class="settingStore.settings.loginDomain === 0 ? 'email-input' : ''" v-model="form.email"
|
||||
type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append v-if="settingStore.settings.loginDomain === 0">
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
v-if="show === 'login'"
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="form.password" :placeholder="$t('password')" type="password" autocomplete="off">
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="loginLoading"
|
||||
>{{$t('loginBtn')}}
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-show="show !== 'login'">
|
||||
<el-input class="email-input" v-model="registerForm.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
v-if="show !== 'login'"
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="registerForm.password" :placeholder="$t('password')" type="password" autocomplete="off" />
|
||||
<el-input v-model="registerForm.confirmPassword" :placeholder="$t('confirmPwd')" type="password" autocomplete="off" />
|
||||
<el-input v-if="settingStore.settings.regKey === 0" v-model="registerForm.code" :placeholder="$t('regKey')" type="text" autocomplete="off" />
|
||||
<el-input v-if="settingStore.settings.regKey === 2" v-model="registerForm.code" :placeholder="$t('regKeyOptional')" type="text" autocomplete="off" />
|
||||
<div v-show="verifyShow"
|
||||
class="register-turnstile"
|
||||
:data-sitekey="settingStore.settings.siteKey"
|
||||
data-callback="onTurnstileSuccess"
|
||||
data-error-callback="onTurnstileError"
|
||||
data-after-interactive-callback="loadAfter"
|
||||
data-before-interactive-callback="loadBefore"
|
||||
>
|
||||
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">{{$t('verifyModuleFailed')}}</span>
|
||||
</div>
|
||||
<el-button class="btn" type="primary" @click="submitRegister" :loading="registerLoading"
|
||||
>{{$t('regBtn')}}
|
||||
</el-button>
|
||||
</div>
|
||||
<template v-if="settingStore.settings.register === 0">
|
||||
<div class="switch" @click="show = 'register'" v-if="show === 'login'">{{$t('noAccount')}} <span>{{$t('regSwitch')}}</span></div>
|
||||
<div class="switch" @click="show = 'login'" v-else>{{$t('hasAccount')}} <span>{{$t('loginSwitch')}}</span></div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="form.password" :placeholder="$t('password')" type="password" autocomplete="off">
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="loginLoading"
|
||||
>{{ $t('loginBtn') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-show="show !== 'login'">
|
||||
<el-input class="email-input" v-model="registerForm.email" type="text" :placeholder="$t('emailAccount')"
|
||||
autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
v-if="show !== 'login'"
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in domainList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="color: #333">
|
||||
<span>{{ suffix }}</span>
|
||||
<Icon class="setting-icon" icon="mingcute:down-small-fill" width="20" height="20"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="registerForm.password" :placeholder="$t('password')" type="password" autocomplete="off"/>
|
||||
<el-input v-model="registerForm.confirmPassword" :placeholder="$t('confirmPwd')" type="password"
|
||||
autocomplete="off"/>
|
||||
<el-input v-if="settingStore.settings.regKey === 0" v-model="registerForm.code" :placeholder="$t('regKey')"
|
||||
type="text" autocomplete="off"/>
|
||||
<el-input v-if="settingStore.settings.regKey === 2" v-model="registerForm.code"
|
||||
:placeholder="$t('regKeyOptional')" type="text" autocomplete="off"/>
|
||||
<div v-show="verifyShow"
|
||||
class="register-turnstile"
|
||||
:data-sitekey="settingStore.settings.siteKey"
|
||||
data-callback="onTurnstileSuccess"
|
||||
data-error-callback="onTurnstileError"
|
||||
data-after-interactive-callback="loadAfter"
|
||||
data-before-interactive-callback="loadBefore"
|
||||
>
|
||||
<span style="font-size: 12px;color: #F56C6C" v-if="botJsError">{{ $t('verifyModuleFailed') }}</span>
|
||||
</div>
|
||||
<el-button class="btn" type="primary" @click="submitRegister" :loading="registerLoading"
|
||||
>{{ $t('regBtn') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<template v-if="settingStore.settings.register === 0">
|
||||
<div class="switch" @click="show = 'register'" v-if="show === 'login'">{{ $t('noAccount') }}
|
||||
<span>{{ $t('regSwitch') }}</span></div>
|
||||
<div class="switch" @click="show = 'login'" v-else>{{ $t('hasAccount') }} <span>{{ $t('loginSwitch') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -112,7 +119,7 @@ import {loginUserInfo} from "@/request/my.js";
|
||||
import {permsToRouter} from "@/perm/perm.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const {t} = useI18n();
|
||||
const accountStore = useAccountStore();
|
||||
const userStore = useUserStore();
|
||||
const uiStore = useUiStore();
|
||||
@@ -139,20 +146,27 @@ const verifyShow = ref(false)
|
||||
let verifyToken = ''
|
||||
let turnstileId = null
|
||||
let botJsError = ref(false)
|
||||
let verifyErrorCount = 0
|
||||
|
||||
window.onTurnstileSuccess = (token) => {
|
||||
verifyToken = token;
|
||||
};
|
||||
|
||||
window.onTurnstileError = (e) => {
|
||||
console.log('人机验加载失败')
|
||||
nextTick(() => {
|
||||
if (!turnstileId) {
|
||||
turnstileId = window.turnstile.render('.register-turnstile')
|
||||
} else {
|
||||
window.turnstile.reset(turnstileId);
|
||||
}
|
||||
})
|
||||
if (verifyErrorCount >= 4) {
|
||||
return
|
||||
}
|
||||
verifyErrorCount++
|
||||
console.warn('人机验加载失败', e)
|
||||
setTimeout(() => {
|
||||
nextTick(() => {
|
||||
if (!turnstileId) {
|
||||
turnstileId = window.turnstile.render('.register-turnstile')
|
||||
} else {
|
||||
window.turnstile.reset(turnstileId);
|
||||
}
|
||||
})
|
||||
}, 1500)
|
||||
};
|
||||
|
||||
window.loadAfter = (e) => {
|
||||
@@ -193,7 +207,9 @@ const submit = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isEmail(form.email + suffix.value)) {
|
||||
let email = form.email + (settingStore.settings.loginDomain === 0 ? suffix.value : '');
|
||||
|
||||
if (!isEmail(email)) {
|
||||
ElMessage({
|
||||
message: t('notEmailMsg'),
|
||||
type: 'error',
|
||||
@@ -212,7 +228,7 @@ const submit = () => {
|
||||
}
|
||||
|
||||
loginLoading.value = true
|
||||
login(form.email + suffix.value, form.password).then(async data => {
|
||||
login(email, form.password).then(async data => {
|
||||
localStorage.setItem('token', data.token)
|
||||
const user = await loginUserInfo();
|
||||
accountStore.currentAccountId = user.accountId;
|
||||
@@ -277,7 +293,7 @@ function submitRegister() {
|
||||
return
|
||||
}
|
||||
|
||||
if(settingStore.settings.regKey === 0) {
|
||||
if (settingStore.settings.regKey === 0) {
|
||||
|
||||
if (!registerForm.code) {
|
||||
|
||||
@@ -414,6 +430,7 @@ function submitRegister() {
|
||||
margin-right: 18px;
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 36px;
|
||||
width: 100%;
|
||||
@@ -434,6 +451,7 @@ function submitRegister() {
|
||||
.switch {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
color: #006be6;
|
||||
cursor: pointer;
|
||||
@@ -444,7 +462,7 @@ function submitRegister() {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.email-input :deep(.el-input__wrapper){
|
||||
.email-input :deep(.el-input__wrapper) {
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
|
||||
@@ -452,6 +470,7 @@ function submitRegister() {
|
||||
height: 38px;
|
||||
width: 100%;
|
||||
margin-bottom: 18px;
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
height: 36px;
|
||||
}
|
||||
@@ -497,7 +516,6 @@ function submitRegister() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
#login-box {
|
||||
background: linear-gradient(to bottom, #2980b9, #6dd5fa, #fff);
|
||||
color: #333;
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
</div>
|
||||
<el-dialog v-model="pwdShow" :title="$t('changePassword')" width="340">
|
||||
<div class="update-pwd">
|
||||
<el-input type="password" :placeholder="$t('newPassword')" v-model="form.password"/>
|
||||
<el-input type="password" :placeholder="$t('confirmPassword')" v-model="form.newPwd"/>
|
||||
<el-input type="password" :placeholder="$t('newPassword')" v-model="form.password" autocomplete="off"/>
|
||||
<el-input type="password" :placeholder="$t('confirmPassword')" v-model="form.newPwd" autocomplete="off"/>
|
||||
<el-button type="primary" :loading="setPwdLoading" @click="submitPwd">{{$t('save')}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -256,4 +256,4 @@ function submitPwd() {
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
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>
|
||||
@@ -326,7 +333,7 @@
|
||||
<div class="card-content">
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('version')}} :</span>
|
||||
<span>v1.6.0</span>
|
||||
<span>v1.7.0</span>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('community')}} : </span>
|
||||
@@ -345,13 +352,22 @@
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>{{$t('support')}} : </span>
|
||||
<el-button @click="jump('https://support.skymail.ink')" >
|
||||
<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" />
|
||||
</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>
|
||||
@@ -1150,8 +1166,8 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
}
|
||||
|
||||
.background {
|
||||
width: 230px;
|
||||
height: 120px;
|
||||
width: 250px;
|
||||
height: 140px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e4e7ed;
|
||||
@media (max-width: 500px) {
|
||||
@@ -1178,11 +1194,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-width: 885px) {
|
||||
.about {
|
||||
height: 210px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.card-title {
|
||||
font-size: 15px;
|
||||
@@ -1501,4 +1513,4 @@ form .el-button {
|
||||
<style>
|
||||
.el-popper.is-dark {
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user