新增中英文切换
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="box-404">
|
||||
<el-empty :image-size="isPhone ? 120 : 0" class="empty" description="404错误, 找不到页面" >
|
||||
<el-button type="primary" @click="router.replace({name: 'layout'})">返回首页</el-button>
|
||||
<el-empty :image-size="isPhone ? 120 : 0" class="empty" :description="$t('error404')" >
|
||||
<el-button type="primary" @click="router.replace({name: 'layout'})">{{$t('home')}}</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="email-list-box">
|
||||
<emailScroll ref="sysEmailScroll"
|
||||
:get-emailList="getEmailList"
|
||||
:email-delete="sysEmailDelete"
|
||||
:email-delete="allEmailDelete"
|
||||
:star-add="starAdd"
|
||||
:star-cancel="starCancel"
|
||||
:show-star="false"
|
||||
@@ -12,13 +12,13 @@
|
||||
:show-account-icon="false"
|
||||
@jump="jumpContent"
|
||||
@refresh-before="refreshBefore"
|
||||
:type="'sys-email'"
|
||||
:type="'all-email'"
|
||||
|
||||
>
|
||||
<template #first>
|
||||
<el-input
|
||||
v-model="searchValue"
|
||||
placeholder="输入内容查询"
|
||||
:placeholder="$t('searchByContent')"
|
||||
class="search-input"
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -26,13 +26,13 @@
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="params.searchType"
|
||||
placeholder="请选择"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option key="3" label="发件人" :value="'name'"/>
|
||||
<el-option key="4" label="主题" :value="'subject'"/>
|
||||
<el-option key="1" label="用户" :value="'user'"/>
|
||||
<el-option key="2" label="邮箱" :value="'account'"/>
|
||||
<el-option key="3" :label="$t('sender')" :value="'name'"/>
|
||||
<el-option key="4" :label="$t('subject')" :value="'subject'"/>
|
||||
<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;">
|
||||
<span>{{ selectTitle }}</span>
|
||||
@@ -42,11 +42,11 @@
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select v-model="params.type" placeholder="Select" class="status-select">
|
||||
<el-option key="1" label="全部" value="all"/>
|
||||
<el-option key="3" label="已接收" value="receive"/>
|
||||
<el-option key="2" label="已发送" value="send"/>
|
||||
<el-option key="4" label="已删除" value="delete"/>
|
||||
<el-option key="4" label="无人收件" value="noone"/>
|
||||
<el-option key="1" :label="$t('all')" value="all"/>
|
||||
<el-option key="3" :label="$t('received')" value="receive"/>
|
||||
<el-option key="2" :label="$t('sent')" value="send"/>
|
||||
<el-option key="4" :label="$t('deleted')" value="delete"/>
|
||||
<el-option key="4" :label="$t('noRecipient')" value="noone"/>
|
||||
</el-select>
|
||||
<Icon class="icon" icon="iconoir:search" @click="search" width="20" height="20"/>
|
||||
<Icon class="icon" @click="changeTimeSort" icon="material-symbols-light:timer-arrow-down-outline"
|
||||
@@ -64,16 +64,18 @@ import emailScroll from "@/components/email-scroll/index.vue"
|
||||
import {computed, defineOptions, reactive, ref, watch} from "vue";
|
||||
import {useEmailStore} from "@/store/email.js";
|
||||
import {
|
||||
sysEmailList,
|
||||
sysEmailDelete
|
||||
} from "@/request/sys-email.js";
|
||||
allEmailList,
|
||||
allEmailDelete
|
||||
} from "@/request/all-email.js";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import router from "@/router/index.js";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'sys-email'
|
||||
name: 'all-email'
|
||||
})
|
||||
|
||||
const { t } = useI18n();
|
||||
const emailStore = useEmailStore();
|
||||
const sysEmailScroll = ref({})
|
||||
const searchValue = ref('')
|
||||
@@ -95,13 +97,13 @@ const params = reactive({
|
||||
|
||||
|
||||
const selectTitle = computed(() => {
|
||||
if (params.searchType === 'user') return '用户'
|
||||
if (params.searchType === 'account') return '邮箱'
|
||||
if (params.searchType === 'name') return '发件人'
|
||||
if (params.searchType === 'subject') return '主题'
|
||||
if (params.searchType === 'user') return t('user')
|
||||
if (params.searchType === 'account') return t('selectEmail')
|
||||
if (params.searchType === 'name') return t('sender')
|
||||
if (params.searchType === 'subject') return t('subject')
|
||||
})
|
||||
|
||||
const paramsStar = localStorage.getItem('sys-email-params')
|
||||
const paramsStar = localStorage.getItem('all-email-params')
|
||||
if (paramsStar) {
|
||||
const locaParams = JSON.parse(paramsStar)
|
||||
params.type = locaParams.type
|
||||
@@ -111,7 +113,7 @@ if (paramsStar) {
|
||||
}
|
||||
|
||||
watch(() => params, () => {
|
||||
localStorage.setItem('sys-email-params',JSON.stringify(params))
|
||||
localStorage.setItem('all-email-params',JSON.stringify(params))
|
||||
}, {
|
||||
deep: true
|
||||
})
|
||||
@@ -163,12 +165,12 @@ function jumpContent(email) {
|
||||
emailStore.contentData.delType = 'physics'
|
||||
emailStore.contentData.showStar = false
|
||||
emailStore.contentData.showReply = false
|
||||
router.push('/content')
|
||||
router.push({name: 'content'})
|
||||
}
|
||||
|
||||
|
||||
function getEmailList(emailId, size) {
|
||||
return sysEmailList({emailId, size, ...params})
|
||||
return allEmailList({emailId, size, ...params})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="number-item">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div>收件数量</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>正常 <span class="normal">{{numberCount.normalReceiveTotal}}</span></div>
|
||||
<div>删除 <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>发件数量</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>正常 <span class="normal">{{numberCount.normalSendTotal}}</span></div>
|
||||
<div>删除 <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>邮箱数量</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>正常 <span class="normal">{{numberCount.normalAccountTotal}}</span></div>
|
||||
<div>删除 <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>用户数量</div>
|
||||
<div>{{$t('totalUsers')}}</div>
|
||||
<div>
|
||||
<el-statistic :formatter="value => Math.round(value)" :value="userData"/>
|
||||
</div>
|
||||
@@ -77,15 +77,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-ratio">
|
||||
<div>正常 <span class="normal">{{numberCount.normalUserTotal}}</span></div>
|
||||
<div>删除 <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>邮件来源</span>
|
||||
<span>{{$t('emailSource')}}</span>
|
||||
<span class="source-button" v-if="false">
|
||||
<el-radio-group v-model="checkedSourceType" >
|
||||
<el-radio-button label="发件人" value="sender" />
|
||||
@@ -98,7 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="picture-item">
|
||||
<div class="title">用户增长</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">邮件增长</div>
|
||||
<div class="title">{{$t('emailGrowth')}}</div>
|
||||
<div class="email-column"></div>
|
||||
</div>
|
||||
<div class="picture-cs-item">
|
||||
<div class="title">今日发件</div>
|
||||
<div class="title">{{$t('sentToday')}}</div>
|
||||
<div class="send-count"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -129,11 +129,14 @@ 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 {toUtc, tzDayjs} from "@/utils/day.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'analysis'
|
||||
})
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const uiStore = useUiStore()
|
||||
const checkedSourceType = ref('sender')
|
||||
@@ -194,7 +197,9 @@ let boxKey = ref(0)
|
||||
let senderPieLeft = window.innerWidth < 500 ? `${window.innerWidth - 110}` : '72%'
|
||||
|
||||
onMounted(() => {
|
||||
analysisEcharts().then(data => {
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
analysisEcharts(timeZone).then(data => {
|
||||
receiveTotal.value = data.numberCount.receiveTotal
|
||||
sendTotal.value = data.numberCount.sendTotal
|
||||
accountTotal.value = data.numberCount.accountTotal
|
||||
@@ -374,7 +379,7 @@ function createIncreaseLine() {
|
||||
formatter: function (params) {
|
||||
let result = ''
|
||||
params.forEach(item => {
|
||||
result = `${item.marker} 用户数: ${item.value}`;
|
||||
result = `${item.marker} ${t('growthTotalUsers')} ${item.value}`;
|
||||
});
|
||||
return result;
|
||||
},
|
||||
@@ -507,7 +512,7 @@ function createEmailColumnChart() {
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['接收', '发送'],
|
||||
data: [t('emailReceived'), t('emailSent')],
|
||||
top: '0'
|
||||
},
|
||||
grid: {
|
||||
@@ -542,7 +547,7 @@ function createEmailColumnChart() {
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '接收',
|
||||
name: t('emailReceived'),
|
||||
type: 'bar',
|
||||
stack: 'total', // 堆叠组标识(必须相同)
|
||||
barWidth: '60%',
|
||||
@@ -559,7 +564,7 @@ function createEmailColumnChart() {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '发送',
|
||||
name: t('emailSent'),
|
||||
type: 'bar',
|
||||
stack: 'total', // 堆叠组标识(必须相同)
|
||||
emphasis: {
|
||||
@@ -587,7 +592,7 @@ function createSendGauge() {
|
||||
let option = {
|
||||
tooltip: {},
|
||||
series: [{
|
||||
name: '今日发件',
|
||||
name: t('sentToday'),
|
||||
type: 'gauge',
|
||||
max: 100,
|
||||
// 进度条颜色(新增)
|
||||
@@ -625,7 +630,7 @@ function createSendGauge() {
|
||||
},
|
||||
data: [{
|
||||
value: daySendTotal,
|
||||
name: '次数',
|
||||
name: t('total'),
|
||||
// 名称标签颜色(新增)
|
||||
title: {
|
||||
color: '#333' // 灰色标签
|
||||
|
||||
@@ -18,20 +18,20 @@
|
||||
<div class="content">
|
||||
<div class="email-info">
|
||||
<div>
|
||||
<div class="send"><span class="send-source">发件人</span>
|
||||
<div class="send"><span class="send-source">{{$t('from')}}</span>
|
||||
<div class="send-name">
|
||||
<span class="send-name-title">{{ email.name }}</span>
|
||||
<span><{{ email.sendEmail }}></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="receive"><span class="source">收件人</span><span class="receive-email">{{ formateReceive(email.recipient) }}</span></div>
|
||||
<div class="receive"><span class="source">{{$t('recipient')}}</span><span class="receive-email">{{ formateReceive(email.recipient) }}</span></div>
|
||||
<div class="date">
|
||||
<div>{{ formatDetailDate(email.createTime) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-alert v-if="email.status === 3" :closable="false" :title="'发送失败: ' + toMessage(email.message)" class="email-msg" type="error" show-icon />
|
||||
<el-alert v-if="email.status === 4" :closable="false" title="被标记为垃圾邮件" class="email-msg" type="warning" show-icon />
|
||||
<el-alert v-if="email.status === 5" :closable="false" title="邮件发送被延迟" class="email-msg" type="warning" show-icon />
|
||||
<el-alert v-if="email.status === 3" :closable="false" :title="`${$t('bounced')} ` + toMessage(email.message)" class="email-msg" type="error" show-icon />
|
||||
<el-alert v-if="email.status === 4" :closable="false" :title="$t('complained')" class="email-msg" type="warning" show-icon />
|
||||
<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" />
|
||||
@@ -39,8 +39,8 @@
|
||||
</el-scrollbar>
|
||||
<div class="att" v-if="email.attList.length > 0">
|
||||
<div class="att-title">
|
||||
<span>附件列表</span>
|
||||
<span>共 {{email.attList.length}} 个</span>
|
||||
<span>{{$t('attachments')}}</span>
|
||||
<span>{{$t('attCount',{total: email.attList.length})}}</span>
|
||||
</div>
|
||||
<div class="att-box">
|
||||
|
||||
@@ -87,8 +87,9 @@ import {getExtName, formatBytes} from "@/utils/file-utils.js";
|
||||
import {cvtR2Url} from "@/utils/convert.js";
|
||||
import {getIconByName} from "@/utils/icon-utils.js";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import {sysEmailDelete} from "@/request/sys-email.js";
|
||||
import {allEmailDelete} from "@/request/all-email.js";
|
||||
import {useUiStore} from "@/store/ui.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const uiStore = useUiStore();
|
||||
const settingStore = useSettingStore();
|
||||
@@ -99,7 +100,7 @@ const email = emailStore.contentData.email
|
||||
const showPreview = ref(false)
|
||||
const srcList = reactive([])
|
||||
|
||||
|
||||
const { t } = useI18n()
|
||||
watch(() => accountStore.currentAccountId, () => {
|
||||
handleBack()
|
||||
})
|
||||
@@ -166,15 +167,15 @@ const handleBack = () => {
|
||||
}
|
||||
|
||||
const handleDelete = () => {
|
||||
ElMessageBox.confirm('确认删除该邮件吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delEmailConfirm'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (emailStore.contentData.delType === 'logic') {
|
||||
emailDelete(email.emailId).then(() => {
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
message: t('delSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -182,9 +183,9 @@ const handleDelete = () => {
|
||||
})
|
||||
} else {
|
||||
|
||||
sysEmailDelete(email.emailId).then(() => {
|
||||
allEmailDelete(email.emailId).then(() => {
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
message: t('delSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
:type="'draft'"
|
||||
>
|
||||
<template #name="props">
|
||||
<span class="send-email" >{{props.email.receiveEmail.join(',') || '(无收件人)'}}</span>
|
||||
<span class="send-email" >{{props.email.receiveEmail.join(',') || '('+$t('noRecipient')+')'}}</span>
|
||||
</template>
|
||||
<template #subject="props" >
|
||||
{{props.email.subject || '(无标题)'}}
|
||||
{{props.email.subject || '('+$t('noSubject')+')'}}
|
||||
</template>
|
||||
</emailScroll>
|
||||
</template>
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
<div class="form-wrapper">
|
||||
<div class="container">
|
||||
<span class="form-title">{{settingStore.settings.title}}</span>
|
||||
<span class="form-desc" v-if="show === 'login'">请输入账号信息以开始使用邮箱系统</span>
|
||||
<span class="form-desc" v-else>请输入账号密码以开始注册邮箱系统</span>
|
||||
<span class="form-desc" v-if="show === 'login'">{{$t('loginTitle')}}</span>
|
||||
<span class="form-desc" v-else>{{$t('regTitle')}}</span>
|
||||
<div v-if="show === 'login'">
|
||||
<el-input class="email-input" v-model="form.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<el-input class="email-input" v-model="form.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
placeholder="请选择"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
@@ -37,20 +37,20 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="form.password" placeholder="密码" type="password" autocomplete="off">
|
||||
<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-else>
|
||||
<el-input class="email-input" v-model="registerForm.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<el-input class="email-input" v-model="registerForm.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="suffix"
|
||||
placeholder="请选择"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
@@ -67,22 +67,22 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="registerForm.password" placeholder="密码" type="password" autocomplete="off" />
|
||||
<el-input v-model="registerForm.confirmPassword" placeholder="确认密码" type="password" autocomplete="off" />
|
||||
<el-input v-if="settingStore.settings.regKey === 0" v-model="registerForm.code" placeholder="注册码" type="text" autocomplete="off" />
|
||||
<el-input v-if="settingStore.settings.regKey === 2" v-model="registerForm.code" placeholder="注册码(可选)" type="text" autocomplete="off" />
|
||||
<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"
|
||||
></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'">还没有账号? <span>创建账号</span></div>
|
||||
<div class="switch" @click="show = 'login'" v-else>已有账号? <span>去登录</span></div>
|
||||
<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>
|
||||
@@ -101,8 +101,10 @@ import {useUserStore} from "@/store/user.js";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {cvtR2Url} from "@/utils/convert.js";
|
||||
import {loginUserInfo} from "@/request/my.js";
|
||||
import {permsToRouter} from "@/utils/perm.js";
|
||||
import {permsToRouter} from "@/perm/perm.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const accountStore = useAccountStore();
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
@@ -161,7 +163,7 @@ const submit = () => {
|
||||
|
||||
if (!form.email) {
|
||||
ElMessage({
|
||||
message: '邮箱不能为空',
|
||||
message: t('emptyEmailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -170,7 +172,7 @@ const submit = () => {
|
||||
|
||||
if (!isEmail(form.email + suffix.value)) {
|
||||
ElMessage({
|
||||
message: '输入的邮箱不合法',
|
||||
message: t('notEmailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -179,7 +181,7 @@ const submit = () => {
|
||||
|
||||
if (!form.password) {
|
||||
ElMessage({
|
||||
message: '密码不能为空',
|
||||
message: t('emptyPwdMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -207,7 +209,7 @@ function submitRegister() {
|
||||
|
||||
if (!registerForm.email) {
|
||||
ElMessage({
|
||||
message: '邮箱不能为空',
|
||||
message: t('emptyEmailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -216,7 +218,7 @@ function submitRegister() {
|
||||
|
||||
if (!isEmail(registerForm.email + suffix.value)) {
|
||||
ElMessage({
|
||||
message: '输入的邮箱不合法',
|
||||
message: t('notEmailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -225,7 +227,7 @@ function submitRegister() {
|
||||
|
||||
if (!registerForm.password) {
|
||||
ElMessage({
|
||||
message: '密码不能为空',
|
||||
message: t('emptyPwdMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -234,7 +236,7 @@ function submitRegister() {
|
||||
|
||||
if (registerForm.password.length < 6) {
|
||||
ElMessage({
|
||||
message: '密码最少六位',
|
||||
message: t('pwdLengthMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -244,7 +246,7 @@ function submitRegister() {
|
||||
if (registerForm.password !== registerForm.confirmPassword) {
|
||||
|
||||
ElMessage({
|
||||
message: '两次密码输入不一致',
|
||||
message: t('confirmPwdFailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -256,7 +258,7 @@ function submitRegister() {
|
||||
if (!registerForm.code) {
|
||||
|
||||
ElMessage({
|
||||
message: '注册码不能为空',
|
||||
message: t('emptyRegKeyMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -298,7 +300,7 @@ function submitRegister() {
|
||||
turnstileId = null
|
||||
verifyToken = ''
|
||||
ElMessage({
|
||||
message: '注册成功',
|
||||
message: t('regSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<el-input
|
||||
v-model="params.code"
|
||||
class="search-input"
|
||||
placeholder="输入注册码搜索"
|
||||
:placeholder="$t('searchRegKeyDesc')"
|
||||
>
|
||||
</el-input>
|
||||
</div>
|
||||
@@ -27,18 +27,18 @@
|
||||
<span class="code" @click="copyCode(item.code)">{{item.code}}</span>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>剩余次数:</div>
|
||||
<div>{{$t('remainingUses')}}:</div>
|
||||
<div v-if="item.count">{{item.count}}</div>
|
||||
<el-tag v-else type="danger">已用尽</el-tag>
|
||||
<el-tag v-else type="danger">{{$t('exhausted')}}</el-tag>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>权限身份:</div>
|
||||
<div>{{$t('roleDesc')}}:</div>
|
||||
<el-tag>{{item.roleName}}</el-tag>
|
||||
</div>
|
||||
<div class="info-left-item">
|
||||
<div>有效至期:</div>
|
||||
<div>{{$t('validUntil')}}:</div>
|
||||
<div v-if="item.expireTime">{{ formatExpireTime(item.expireTime)}}</div>
|
||||
<el-tag v-else type="danger">已过期</el-tag>
|
||||
<el-tag v-else type="danger">{{$t('expired')}}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-right">
|
||||
@@ -46,9 +46,9 @@
|
||||
<Icon icon="fluent:settings-24-filled" width="21" height="21" color="#909399" />
|
||||
<template #dropdown >
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="copyCode(item.code)">复制</el-dropdown-item>
|
||||
<el-dropdown-item @click="openHistory(item)">记录</el-dropdown-item>
|
||||
<el-dropdown-item @click="deleteRegKey(item)">删除</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>
|
||||
@@ -57,37 +57,37 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="empty" v-if="regKeyData.length === 0">
|
||||
<el-empty v-if="!regKeyFirst" :image-size="isMobile ? 120 : 0" description="没有任何注册码"/>
|
||||
<el-empty v-if="!regKeyFirst" :image-size="isMobile ? 120 : 0" :description="$t('noCodeFound')"/>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<el-dialog v-model="showAdd" title="添加注册码">
|
||||
<el-dialog v-model="showAdd" :title="$t('addRegKey')">
|
||||
<div class="container">
|
||||
<el-input v-model="addForm.code" placeholder="注册码">
|
||||
<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" />
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select v-model="addForm.roleId" placeholder="身份类型">
|
||||
<el-select v-model="addForm.roleId" :placeholder="$t('roleDesc')">
|
||||
<el-option v-for="item in roleList" :label="item.name" :value="item.roleId" :key="item.roleId"/>
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-model="addForm.expireTime"
|
||||
type="date"
|
||||
placeholder="有效至期"
|
||||
:placeholder="$t('validUntil')"
|
||||
/>
|
||||
<el-input-number v-model="addForm.count" :min="1" :max="99999"/>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="addLoading"
|
||||
>添加
|
||||
>{{$t('add')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog class="history-list" v-model="showRegKeyHistory" title="使用记录">
|
||||
<el-dialog class="history-list" v-model="showRegKeyHistory" :title="$t('useHistory')">
|
||||
<div class="loading" :class="historyLoading ? 'loading-show' : 'loading-hide'">
|
||||
<loading />
|
||||
</div>
|
||||
<el-table v-if="!historyLoading" :data="historyList" :fit="true" style="height: 100%" >
|
||||
<el-table-column :min-width="emailColumnWidth" property="email" label="用户" :show-overflow-tooltip="true" />
|
||||
<el-table-column :width="createTimeColumnWidth" :formatter="formatUserCreateTime" property="createTime" label="时间" fixed="right" :show-overflow-tooltip="true" />
|
||||
<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>
|
||||
@@ -104,6 +104,7 @@ import {regKeyAdd, regKeyList, regKeyClearNotUse, regKeyDelete, regKeyHistory} f
|
||||
import { getTextWidth } from "@/utils/text.js";
|
||||
import dayjs from "dayjs";
|
||||
import {tzDayjs} from "@/utils/day.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
defineOptions({
|
||||
name: 'reg-key'
|
||||
@@ -115,6 +116,7 @@ const params = reactive({
|
||||
code: '',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const roleList = reactive([])
|
||||
const addLoading = ref(false)
|
||||
const showAdd = ref(false)
|
||||
@@ -185,25 +187,44 @@ function formatUserCreateTime(regKey) {
|
||||
const currentYear = dayjs().year();
|
||||
const expireYear = createTime.year();
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return createTime.format('M月D日 HH:mm');
|
||||
if(settingStore.lang === 'zh') {
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return createTime.format('M月D日 HH:mm');
|
||||
} else {
|
||||
return createTime.format('YYYY年M月D日 HH:mm');
|
||||
}
|
||||
|
||||
} else {
|
||||
return createTime.format('YYYY年M月D日 HH:mm');
|
||||
|
||||
if (createYear === currentYear) {
|
||||
return createTime.format('MMM D, HH:mm');
|
||||
} else {
|
||||
return createTime.format('MMM D, YYYY HH:mm');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function formatExpireTime(expireTime) {
|
||||
|
||||
expireTime = tzDayjs(expireTime);
|
||||
const expireDate = tzDayjs(expireTime);
|
||||
const currentYear = dayjs().year();
|
||||
const expireYear = expireTime.year();
|
||||
const expireYear = expireDate.year();
|
||||
|
||||
if (expireYear === currentYear) {
|
||||
return expireTime.format('M月D日');
|
||||
if (settingStore.lang === 'zh') {
|
||||
|
||||
return expireYear === currentYear
|
||||
? expireDate.format('M月D日')
|
||||
: expireDate.format('YYYY年M月D日');
|
||||
} else {
|
||||
return expireTime.format('YYYY年M月D日');
|
||||
|
||||
return expireYear === currentYear
|
||||
? expireDate.format('MMM D')
|
||||
: expireDate.format('MMM D, YYYY');
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
params.code = null
|
||||
getList(true)
|
||||
@@ -229,7 +250,7 @@ async function copyCode(code) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(code);
|
||||
ElMessage({
|
||||
message: '复制成功',
|
||||
message: t('copySuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -257,14 +278,14 @@ function generateRandomCode(length = 8) {
|
||||
}
|
||||
|
||||
function clearNotUse() {
|
||||
ElMessageBox.confirm(`确认清除所有不可用的注册码?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('clearRegKey'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
regKeyClearNotUse().then(() => {
|
||||
ElMessage({
|
||||
message: '清除成功',
|
||||
message: t('clearSuccess'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -277,7 +298,7 @@ function submit() {
|
||||
|
||||
if (!addForm.code) {
|
||||
ElMessage({
|
||||
message: "注册码不能为空",
|
||||
message: $('emptyRegKeyMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -286,7 +307,7 @@ function submit() {
|
||||
|
||||
if (!addForm.roleId) {
|
||||
ElMessage({
|
||||
message: "身份类型不能为空",
|
||||
message: t('emptyRole'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -295,7 +316,7 @@ function submit() {
|
||||
|
||||
if (!addForm.expireTime) {
|
||||
ElMessage({
|
||||
message: "有效时间不能为空",
|
||||
message: t('emptyTimeMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -304,7 +325,7 @@ function submit() {
|
||||
|
||||
if (!addForm.count) {
|
||||
ElMessage({
|
||||
message: "使用次数不能为空",
|
||||
message: t('emptyCountMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -316,7 +337,7 @@ function submit() {
|
||||
showAdd.value = false
|
||||
resetForm()
|
||||
ElMessage({
|
||||
message: "添加成功",
|
||||
message: t('addSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -327,15 +348,15 @@ function submit() {
|
||||
}
|
||||
|
||||
function deleteRegKey(regKey){
|
||||
ElMessageBox.confirm(`确认删除${regKey.code}吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delConfirm',{msg: regKey.code}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
regKeyDelete([regKey.regKeyId]).then(() => {
|
||||
getList()
|
||||
ElMessage({
|
||||
message: "删除成功",
|
||||
message: t('delSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
|
||||
@@ -14,31 +14,31 @@
|
||||
style="width: 100%;"
|
||||
>
|
||||
<el-table-column width="10" />
|
||||
<el-table-column label="身份名称" prop="name" :min-width="roleWidth">
|
||||
<el-table-column :label="$t('roleName')" 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" >默认</el-tag></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="排序" :width="sortWidth" prop="sort"/>
|
||||
<el-table-column v-if="desShow" label="描述" min-width="200" prop="description" >
|
||||
<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="操作" :width="settingWidth">
|
||||
<el-table-column :label="$t('tabSetting')" :width="settingWidth">
|
||||
<template #default="props">
|
||||
<el-dropdown trigger="click">
|
||||
<el-button size="small" type="primary">操作</el-button>
|
||||
<el-button size="small" type="primary">{{$t('action')}}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openRoleSet(props.row)">修改</el-dropdown-item>
|
||||
<el-dropdown-item @click="setDef(props.row)">默认</el-dropdown-item>
|
||||
<el-dropdown-item @click="delRole(props.row)">删除</el-dropdown-item>
|
||||
<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>
|
||||
@@ -49,19 +49,19 @@
|
||||
</el-scrollbar>
|
||||
<el-dialog top="5vh" class="dialog" v-model="roleFormShow" :title="dialogType.title" @closed="resetForm">
|
||||
<div class="dialog-box">
|
||||
<el-input class="dialog-input" v-model="form.name" type="text" :maxlength="12" placeholder="身份名称" autocomplete="off" />
|
||||
<el-input class="dialog-input" v-model="form.description" :maxlength="30" type="text" placeholder="描述" 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="输入邮箱拦截收件, 拦截所有前缀 *@example.com" 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('emailBlock')" autocomplete="off" />
|
||||
<el-radio-group class="dialog-radio" v-model="form.banEmailType" v-if="form.banEmail.length > 0">
|
||||
<el-radio label="丢弃邮件" :value="0" />
|
||||
<el-radio label="移除正文" :value="1" />
|
||||
<el-radio :label="$t('removeAll')" :value="0" />
|
||||
<el-radio :label="$t('removeBody')" :value="1" />
|
||||
</el-radio-group>
|
||||
<div class="dialog-input">
|
||||
<el-input-number placeholder="排序" :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="展开" :value="true" />
|
||||
<el-radio-button label="收起" :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"
|
||||
@@ -79,25 +79,23 @@
|
||||
<div>
|
||||
<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" :max="99999" size="small" placeholder="数量" >
|
||||
<el-input-number v-model="form.sendCount" controls-position="right" :max="99999" size="small" :placeholder="$t('total')" >
|
||||
</el-input-number>
|
||||
<el-select v-model="form.sendType" placeholder="Select" size="small" style="width: 60px;margin-left: 5px;">
|
||||
<el-option label="总数" value="count" />
|
||||
<el-option label="每天" value="day" />
|
||||
<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>
|
||||
<el-tooltip effect="dark" content="零无限制 负数无次数">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</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="数量" >
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -111,11 +109,13 @@ import loading from '@/components/loading/index.vue';
|
||||
import {useRoleStore} from "@/store/role.js";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import {isEmail} from "@/utils/verify-utils.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
defineOptions({
|
||||
name: 'role'
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const roleStore = useRoleStore();
|
||||
const roleFormShow = ref(false)
|
||||
@@ -182,7 +182,7 @@ function roleFormClick() {
|
||||
function setDef(role) {
|
||||
roleSetDef(role.roleId).then(() => {
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -191,14 +191,14 @@ function setDef(role) {
|
||||
}
|
||||
|
||||
function delRole(role) {
|
||||
ElMessageBox.confirm(`确认删除 ${role.name} 吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delConfirm', {msg: role.name}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('confirm'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
roleDelete(role.roleId).then(() => {
|
||||
ElMessage({
|
||||
message: "删除成功",
|
||||
message: t('copySuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -228,7 +228,7 @@ function setRole() {
|
||||
|
||||
if (!form.name) {
|
||||
ElMessage({
|
||||
message: "身份名不能为空",
|
||||
message: t('emptyRoleNameMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -243,7 +243,7 @@ function setRole() {
|
||||
permLoading.value = true
|
||||
roleSet(params).then(() => {
|
||||
ElMessage({
|
||||
message: "修改成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -275,7 +275,7 @@ function resetForm() {
|
||||
|
||||
function openRoleSet(role) {
|
||||
chooseRole = role
|
||||
dialogType.title = '修改身份'
|
||||
dialogType.title = t('changeRoleTitle')
|
||||
dialogType.type = 'set'
|
||||
roleFormShow.value = true
|
||||
form.sort = role.sort
|
||||
@@ -292,7 +292,7 @@ function openRoleSet(role) {
|
||||
|
||||
|
||||
function openAddRole() {
|
||||
dialogType.title = '添加身份'
|
||||
dialogType.title = t('addRoleTitle')
|
||||
dialogType.type = 'add'
|
||||
roleFormShow.value = true
|
||||
}
|
||||
@@ -306,7 +306,7 @@ function addRole() {
|
||||
permLoading.value = true
|
||||
roleAdd(params).then(() => {
|
||||
ElMessage({
|
||||
message: "添加成功",
|
||||
message: t('addSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -335,7 +335,7 @@ function getRoleList() {
|
||||
|
||||
function adjustWidth() {
|
||||
desShow.value = window.innerWidth > 767
|
||||
settingWidth.value = window.innerWidth < 480 ? 75 : null
|
||||
settingWidth.value = window.innerWidth < 480 ? (locale.value === 'en' ? 85 : 75) : null
|
||||
sortWidth.value = window.innerWidth < 480 ? 75 : null
|
||||
roleWidth.value = window.innerWidth < 480 ? 180 : 200
|
||||
}
|
||||
|
||||
@@ -1,72 +1,97 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="pass">
|
||||
<div class="title">账户与密码</div>
|
||||
<div class="pass-item">
|
||||
<div>用户名</div>
|
||||
<div class="container">
|
||||
<div class="title">{{$t('profile')}}</div>
|
||||
<div class="item">
|
||||
<div>{{$t('username')}}</div>
|
||||
<div>
|
||||
<span v-if="setNameShow" class="edit-name-input">
|
||||
<el-input v-model="accountName" ></el-input>
|
||||
<span class="edit-name" @click="setName">
|
||||
保存
|
||||
{{$t('save')}}
|
||||
</span>
|
||||
</span>
|
||||
<span v-else class="user-name">
|
||||
<span >{{ userStore.user.name }}</span>
|
||||
<span class="edit-name" @click="showSetName">
|
||||
修改
|
||||
{{$t('change')}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pass-item">
|
||||
<div>邮箱</div>
|
||||
<div class="item">
|
||||
<div>{{$t('emailAccount')}}</div>
|
||||
<div>{{ userStore.user.email }}</div>
|
||||
</div>
|
||||
<div class="pass-item">
|
||||
<div>密码</div>
|
||||
<div class="item">
|
||||
<div>{{$t('password')}}</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="pwdShow = true">修改密码</el-button>
|
||||
<el-button type="primary" @click="pwdShow = true">{{$t('changePwdBtn')}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="del-email" v-perm="'my:delete'">
|
||||
<div class="title">删除账户</div>
|
||||
<div style="color: #585d69;">
|
||||
此操作将永久删除您的账户及其所有数据,无法恢复
|
||||
</div>
|
||||
<div class="container lang">
|
||||
<div class="title">{{$t('language')}}</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="deleteConfirm">删除账户</el-button>
|
||||
<el-select v-model="lang" placeholder="Select" style="width: 100px">
|
||||
<el-option
|
||||
key="zh"
|
||||
label="简体中文"
|
||||
value="zh"/>
|
||||
<el-option
|
||||
key="en"
|
||||
label="English"
|
||||
value="en"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="pwdShow" title="修改密码" width="340">
|
||||
<div class="del-email" v-perm="'my:delete'">
|
||||
<div class="title">{{$t('deleteUser')}}</div>
|
||||
<div style="color: #585d69;">
|
||||
{{$t('delAccountMsg')}}
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="deleteConfirm">{{$t('deleteUserBtn')}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="pwdShow" :title="$t('changePassword')" width="340">
|
||||
<div class="update-pwd">
|
||||
<el-input type="password" placeholder="新的密码" v-model="form.password"/>
|
||||
<el-input type="password" placeholder="确认密码" v-model="form.newPwd"/>
|
||||
<el-button type="primary" :loading="setPwdLoading" @click="submitPwd">保存</el-button>
|
||||
<el-input type="password" :placeholder="$t('newPassword')" v-model="form.password"/>
|
||||
<el-input type="password" :placeholder="$t('confirmPassword')" v-model="form.newPwd"/>
|
||||
<el-button type="primary" :loading="setPwdLoading" @click="submitPwd">{{$t('save')}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {defineOptions} from "vue";
|
||||
import {reactive, ref} from 'vue'
|
||||
import {reactive, ref, defineOptions, watch} from 'vue'
|
||||
import {resetPassword, userDelete} from "@/request/my.js";
|
||||
import {useUserStore} from "@/store/user.js";
|
||||
import router from "@/router/index.js";
|
||||
import { storeToRefs } from 'pinia'
|
||||
import {accountSetName} from "@/request/account.js";
|
||||
import {useAccountStore} from "@/store/account.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useSettingStore} from "@/store/setting.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const settingStore = useSettingStore()
|
||||
const accountStore = useAccountStore()
|
||||
const userStore = useUserStore();
|
||||
const setPwdLoading = ref(false)
|
||||
const setNameShow = ref(false)
|
||||
const accountName = ref(null)
|
||||
const { lang } = storeToRefs(settingStore)
|
||||
|
||||
defineOptions({
|
||||
name: 'setting'
|
||||
})
|
||||
|
||||
watch(() => lang.value,() => {
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
function showSetName() {
|
||||
accountName.value = userStore.user.name
|
||||
setNameShow.value = true
|
||||
@@ -76,7 +101,7 @@ function setName() {
|
||||
|
||||
if (!accountName.value) {
|
||||
ElMessage({
|
||||
message: '用户名不能为空',
|
||||
message: t('emptyUserNameMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -94,7 +119,7 @@ function setName() {
|
||||
|
||||
accountSetName(userStore.user.accountId,name).then(() => {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
message: t('changSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -113,16 +138,16 @@ const form = reactive({
|
||||
})
|
||||
|
||||
const deleteConfirm = () => {
|
||||
ElMessageBox.confirm('确认删除当前账号及所有数据吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delAccountConfirm'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userDelete().then(() => {
|
||||
localStorage.removeItem('token');
|
||||
router.replace('/login');
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
message: t('delSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -135,7 +160,7 @@ function submitPwd() {
|
||||
|
||||
if (!form.password) {
|
||||
ElMessage({
|
||||
message: '密码不能为空',
|
||||
message: t('emptyPwdMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -144,7 +169,7 @@ function submitPwd() {
|
||||
|
||||
if (form.password.length < 6) {
|
||||
ElMessage({
|
||||
message: '密码不能小于6位',
|
||||
message: t('pwdLengthMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -153,7 +178,7 @@ function submitPwd() {
|
||||
|
||||
if (form.password !== form.newPwd) {
|
||||
ElMessage({
|
||||
message: '两次密码输入不一致',
|
||||
message: t('confirmPwdFailMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -163,7 +188,7 @@ function submitPwd() {
|
||||
setPwdLoading.value = true
|
||||
resetPassword(form.password).then(() => {
|
||||
ElMessage({
|
||||
message: '修改成功',
|
||||
message: t('changSuccessMsg'),
|
||||
type: 'success',
|
||||
plain: true,
|
||||
})
|
||||
@@ -197,13 +222,13 @@ function submitPwd() {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pass {
|
||||
.container {
|
||||
font-size: 14px;
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.pass-item {
|
||||
.item {
|
||||
display: grid;
|
||||
grid-template-columns: 50px 1fr;
|
||||
gap: 140px;
|
||||
|
||||
@@ -8,21 +8,21 @@
|
||||
<div class="card-grid">
|
||||
<!-- Website Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">网站设置</div>
|
||||
<div class="card-title">{{$t('websiteSetting')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>用户注册</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>注册码</span></div>
|
||||
<div><span>{{$t('regKey')}}</span></div>
|
||||
<div>
|
||||
<el-select
|
||||
@change="change"
|
||||
style="width: 80px;"
|
||||
:style="`width: ${ locale === 'en' ? 100 : 80 }px;`"
|
||||
v-model="setting.regKey"
|
||||
placeholder="Select"
|
||||
>
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>添加邮箱</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"/>
|
||||
@@ -44,8 +44,8 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>多号模式</span>
|
||||
<el-tooltip effect="dark" content="开启后账号栏出现一个用户可以添加多个邮箱">
|
||||
<span>{{$t('multipleEmail')}}</span>
|
||||
<el-tooltip effect="dark" :content="$t('multipleEmailDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
@@ -56,8 +56,8 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>物理清空数据</span>
|
||||
<el-tooltip effect="dark" content="该操作会物理清空所有已被删除的数据">
|
||||
<span>{{$t('physicallyWipeData')}}</span>
|
||||
<el-tooltip effect="dark" :content="$t('physicallyWipeDataDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
@@ -73,10 +73,10 @@
|
||||
|
||||
<!-- Personalization Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">个性化设置</div>
|
||||
<div class="card-title">{{$t('customization')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div class="title-item"><span>网站标题</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">
|
||||
@@ -85,13 +85,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title-item"><span>登录透明</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" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item personalized">
|
||||
<div><span>登录背景</span></div>
|
||||
<div><span>{{$t('loginBackground')}}</span></div>
|
||||
<div>
|
||||
<el-image
|
||||
class="background"
|
||||
@@ -121,10 +121,10 @@
|
||||
|
||||
<!-- Email Sending Settings Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">邮件设置</div>
|
||||
<div class="card-title">{{$t('emailSetting')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>邮件接收</span></div>
|
||||
<div><span>{{$t('receiveEmails')}}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.receive"/>
|
||||
@@ -132,15 +132,15 @@
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div>
|
||||
<span>轮询刷新</span>
|
||||
<el-tooltip effect="dark" content="轮询请求服务器获取最新邮件">
|
||||
<span>{{$t('autoRefresh')}}</span>
|
||||
<el-tooltip effect="dark" :content="$t('autoRefreshDesc')">
|
||||
<Icon class="warning" icon="fe:warning" width="18" height="18"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<el-select
|
||||
@change="change"
|
||||
style="width: 80px;"
|
||||
:style="`width: ${ locale === 'en' ? 100 : 80 }px;`"
|
||||
v-model="setting.autoRefreshTime"
|
||||
placeholder="Select"
|
||||
>
|
||||
@@ -154,14 +154,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>邮件发送</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"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>添加 Resend Token</span></div>
|
||||
<div><span>{{$t('resendToken')}}</span></div>
|
||||
<div>
|
||||
<el-button class="opt-button" style="margin-top: 0" @click="openResendList" size="small" type="primary">
|
||||
<Icon icon="ic:round-list" width="18" height="18"/>
|
||||
@@ -176,12 +176,12 @@
|
||||
|
||||
<!-- R2 Object Storage Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">R2对象存储</div>
|
||||
<div class="card-title">{{$t('R2OS')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>访问域名</span></div>
|
||||
<div><span>{{$t('osDomain')}}</span></div>
|
||||
<div class="r2domain">
|
||||
<span>{{ setting.r2Domain || '空' }}</span>
|
||||
<span>{{ setting.r2Domain || '' }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="r2DomainShow = true">
|
||||
<Icon icon="lsicon:edit-outline" width="16" height="16"/>
|
||||
</el-button>
|
||||
@@ -191,30 +191,30 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<div class="card-title">邮件推送</div>
|
||||
<div class="card-title">{{$t('emailPush')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>Telegram 机器人</span></div>
|
||||
<div><span>{{$t('tgBot')}}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.tgBotStatus === 0 ? '已开启' : '已关闭' }}</span>
|
||||
<span>{{ setting.tgBotStatus === 0 ? $t('enabled') : $t('disabled') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openTgSetting">
|
||||
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>第三方邮箱</span></div>
|
||||
<div><span>{{$t('otherEmail')}}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.forwardStatus === 0 ? '已开启' : '已关闭' }}</span>
|
||||
<span>{{ setting.forwardStatus === 0 ? $t('enabled') : $t('disabled') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openThirdEmailSetting">
|
||||
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>转发规则</span></div>
|
||||
<div><span>{{$t('forwardingRules')}}</span></div>
|
||||
<div class="forward">
|
||||
<span>{{ setting.ruleType === 0 ? '全部转发' : '规则转发' }}</span>
|
||||
<span>{{ setting.ruleType === 0 ? $t('forwardAll') : $t('rules') }}</span>
|
||||
<el-button class="opt-button" size="small" type="primary" @click="openForwardRules">
|
||||
<Icon icon="fluent:settings-48-regular" width="18" height="18"/>
|
||||
</el-button>
|
||||
@@ -225,17 +225,17 @@
|
||||
|
||||
<!-- Turnstile Verification Card -->
|
||||
<div class="settings-card">
|
||||
<div class="card-title">Turnstile 人机验证</div>
|
||||
<div class="card-title">{{$t('turnstileSetting')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="setting-item">
|
||||
<div><span>注册验证</span></div>
|
||||
<div><span>{{$t('signUpVerification')}}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.registerVerify"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div><span>添加验证</span></div>
|
||||
<div><span>{{$t('addEmailVerification')}}</span></div>
|
||||
<div>
|
||||
<el-switch @change="change" :before-change="beforeChange" :active-value="0" :inactive-value="1"
|
||||
v-model="setting.addEmailVerify"/>
|
||||
@@ -263,14 +263,14 @@
|
||||
</div>
|
||||
|
||||
<div class="settings-card about">
|
||||
<div class="card-title">关于</div>
|
||||
<div class="card-title">{{$t('about')}}</div>
|
||||
<div class="card-content">
|
||||
<div class="concerning-item">
|
||||
<span>版本:</span>
|
||||
<span>v1.4.0</span>
|
||||
<span>{{$t('version')}} :</span>
|
||||
<span>v1.3.1</span>
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>交流:</span>
|
||||
<span>{{$t('community')}} : </span>
|
||||
<el-button @click="jump('https://t.me/cloud_mail_tg')">
|
||||
telegram
|
||||
<template #icon>
|
||||
@@ -290,13 +290,13 @@
|
||||
</div>
|
||||
|
||||
<!-- Dialogs remain the same -->
|
||||
<el-dialog v-model="editTitleShow" title="修改标题" width="340" @closed="editTitle = ''">
|
||||
<el-dialog v-model="editTitleShow" :title="$t('changeTitle')" width="340" @closed="editTitle = ''">
|
||||
<form>
|
||||
<el-input type="text" placeholder="网站标题" v-model="editTitle"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTitle">保存</el-button>
|
||||
<el-input type="text" :placeholder="$t('websiteTitle')" v-model="editTitle"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTitle">{{$t('save')}}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="resendTokenFormShow" title="添加 Resend Token" width="340" @closed="cleanResendTokenForm">
|
||||
<el-dialog v-model="resendTokenFormShow" :title="$t('resendToken')" width="340" @closed="cleanResendTokenForm">
|
||||
<form>
|
||||
<el-select style="margin-bottom: 15px" v-model="resendTokenForm.domain" placeholder="Select">
|
||||
<el-option
|
||||
@@ -306,27 +306,27 @@
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input type="text" placeholder="输入内容添加,不填则删除" v-model="resendTokenForm.token"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveResendToken">保存</el-button>
|
||||
<el-input type="text" :placeholder="$t('addResendTokenDesc')" v-model="resendTokenForm.token"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveResendToken">{{$t('save')}}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="r2DomainShow" title="添加R2访问域名" width="340" @closed="r2DomainInput = ''">
|
||||
<el-dialog v-model="r2DomainShow" :title="$t('addOsDomain')" width="340" @closed="r2DomainInput = ''">
|
||||
<form>
|
||||
<el-input type="text" placeholder="R2访问域名" v-model="r2DomainInput"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveR2domain">保存</el-button>
|
||||
<el-input type="text" :placeholder="$t('domainDesc')" v-model="r2DomainInput"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveR2domain">{{$t('save')}}</el-button>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="turnstileShow" title="添加 Turnstile 密钥" width="340"
|
||||
<el-dialog v-model="turnstileShow" :title="$t('addTurnstileSecret')" width="340"
|
||||
@closed="turnstileForm.secretKey = '';turnstileForm.siteKey = ''">
|
||||
<form>
|
||||
<el-input type="text" placeholder="siteKey" v-model="turnstileForm.siteKey"/>
|
||||
<el-input type="text" style="margin-top: 15px" placeholder="secretKey" v-model="turnstileForm.secretKey"/>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveTurnstileKey">保存</el-button>
|
||||
<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>
|
||||
</form>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="cutShow"
|
||||
title="背景截图"
|
||||
:title="$t('backgroundCropping')"
|
||||
class="cut-dialog"
|
||||
>
|
||||
<div class="cropper">
|
||||
@@ -343,31 +343,30 @@
|
||||
></vueCropper>
|
||||
</div>
|
||||
<div class="cut-button">
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveBackground">保存</el-button>
|
||||
<el-button type="primary" :loading="settingLoading" @click="saveBackground">{{$t('save')}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="tgSettingShow"
|
||||
title="Telegram 机器人"
|
||||
class="forward-dialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">Telegram 机器人</span>
|
||||
<el-tooltip effect="dark" content="可以将接收的邮件转发到Tg机器人">
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
<div class="forward-set-body">
|
||||
<el-input placeholder="机器人 token" v-model="tgBotToken"></el-input>
|
||||
<el-input-tag tag-type="warning" placeholder="用户 chat_id 多个用,分开 12345,54321" v-model="tgChatId" @add-tag="addChatTag" ></el-input-tag>
|
||||
<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>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-switch v-model="tgBotStatus" :active-value="0" :inactive-value="1" active-text="开启" inactive-text="关闭" />
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -378,20 +377,20 @@
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">第三方邮箱</span>
|
||||
<el-tooltip effect="dark" content="可以将邮件转到其他服务商邮箱,需要在cloudflare验证邮箱">
|
||||
<span class="forward-set-title">{{$t('otherEmail')}}</span>
|
||||
<el-tooltip effect="dark" :content="$t('otherEmailDec')">
|
||||
<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="多个邮箱用, 分开 example1.com,example2.com" 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="开启" inactive-text="关闭" />
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -402,31 +401,31 @@
|
||||
>
|
||||
<template #header>
|
||||
<div class="forward-head">
|
||||
<span class="forward-set-title">转发规则</span>
|
||||
<el-tooltip effect="dark" content="规则转发只会转发设置邮箱所接收的邮件">
|
||||
<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="多个邮箱用, 分开 example1.com,example2.com" 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" >全部转发</el-radio>
|
||||
<el-radio :value="1" >规则转发</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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog class="resend-table" v-model="showResendList" title="Token 列表">
|
||||
<el-dialog class="resend-table" v-model="showResendList" :title="$t('resendTokenList')">
|
||||
<el-table :data="resendList" >
|
||||
<el-table-column :min-width="emailColumnWidth" property="key" label="域名" :show-overflow-tooltip="true" />
|
||||
<el-table-column :width="tokenColumnWidth" property="value" label="token" fixed="right" :show-overflow-tooltip="true" />
|
||||
<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-scrollbar>
|
||||
@@ -446,11 +445,13 @@ 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 { useI18n } from 'vue-i18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'sys-setting'
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const firstLoading = ref(true)
|
||||
const cropper = ref()
|
||||
const cutImage = ref('')
|
||||
@@ -482,13 +483,13 @@ const turnstileForm = reactive({
|
||||
})
|
||||
|
||||
const regKeyOptions = [
|
||||
{label: '开启', value: 0},
|
||||
{label: '关闭', value: 1},
|
||||
{label: '可选', value: 2},
|
||||
{label: t('enable'), value: 0},
|
||||
{label: t('disable'), value: 1},
|
||||
{label: t('optional'), value: 2},
|
||||
]
|
||||
|
||||
const options = [
|
||||
{label: '关闭', value: 0},
|
||||
{label: t('disable'), value: 0},
|
||||
{label: '3s', value: 3},
|
||||
{label: '5s', value: 5},
|
||||
{label: '7s', value: 7},
|
||||
@@ -658,18 +659,18 @@ const opacityChange = debounce(doOpacityChange, 1000, {
|
||||
})
|
||||
|
||||
function physicsDeleteAllData() {
|
||||
ElMessageBox.prompt('此操作不可逆转, 输入 <b style="font-weight: bold">确认删除</b> 继续操作', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.prompt(t('clearAllDelConfirm'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
dangerouslyUseHTMLString: true,
|
||||
title: '警告',
|
||||
title: t('warning'),
|
||||
type: 'warning',
|
||||
inputPattern: /^确认删除$/,
|
||||
inputErrorMessage: '请输入确认删除',
|
||||
inputPattern: new RegExp(`^${t('delInputPattern')}$`),
|
||||
inputErrorMessage: t('inputErrorMessage'),
|
||||
}).then(() => {
|
||||
physicsDeleteAll().then(() => {
|
||||
ElMessage({
|
||||
message: "删除成功",
|
||||
message: t('delSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -678,9 +679,9 @@ function physicsDeleteAllData() {
|
||||
}
|
||||
|
||||
function delBackground() {
|
||||
ElMessageBox.confirm('确定要删除这个背景吗?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delBackgroundConfirm'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
setting.value.background = null
|
||||
@@ -702,7 +703,7 @@ function saveBackground() {
|
||||
setting.value.background = key
|
||||
cutShow.value = false
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -725,14 +726,6 @@ function openCut() {
|
||||
|
||||
function saveR2domain() {
|
||||
const settingForm = {r2Domain: r2DomainInput.value}
|
||||
if (settingForm.r2Domain && !settingForm.r2Domain.startsWith('http')) {
|
||||
ElMessage({
|
||||
message: "域名必须以http或https开头",
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
return;
|
||||
}
|
||||
editSetting(settingForm)
|
||||
}
|
||||
|
||||
@@ -800,7 +793,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
settingSet(settingForm).then(() => {
|
||||
settingLoading.value = false
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
<el-input
|
||||
v-model="params.email"
|
||||
class="search-input"
|
||||
placeholder="输入邮箱名搜索"
|
||||
:placeholder="$t('searchByEmail')"
|
||||
>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-select v-model="params.status" placeholder="Select" class="status-select">
|
||||
<el-option :key="-1" label="全部" :value="-1"/>
|
||||
<el-option :key="0" label="正常" :value="0"/>
|
||||
<el-option :key="1" label="封禁" :value="1"/>
|
||||
<el-option :key="-2" label="删除" :value="-2"/>
|
||||
<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"/>
|
||||
<el-option :key="-2" :label="$t('deleted')" :value="-2"/>
|
||||
</el-select>
|
||||
<Icon class="icon" icon="iconoir:search" @click="search" width="20" height="20"/>
|
||||
<Icon class="icon" @click="changeTimeSort" icon="material-symbols-light:timer-arrow-down-outline"
|
||||
@@ -41,93 +41,93 @@
|
||||
<el-table-column :width="expandWidth" type="expand">
|
||||
<template #default="props">
|
||||
<div class="details">
|
||||
<div v-if="!sendNumShow"><span class="details-item-title">发件数量:</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">邮箱数量:</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">注册时间:</span>{{
|
||||
tzDayjs(props.row.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
<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">身份类型:</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">状态:</span>
|
||||
<el-tag disable-transitions v-if="props.row.isDel === 1" type="info">删除</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">正常</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">封禁</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">注册IP:</span>{{ props.row.createIp || '未知' }}</div>
|
||||
<div><span class="details-item-title">近期IP:</span>{{ props.row.activeIp || '未知' }}</div>
|
||||
<div><span class="details-item-title">近期活动:</span>{{
|
||||
props.row.activeTime ? tzDayjs(props.row.activeTime).format('YYYY-MM-DD') : '未知'
|
||||
<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">登录设备:</span>{{ props.row.device || '未知' }}</div>
|
||||
<div><span class="details-item-title">登录系统:</span>{{ props.row.os || '未知' }}</div>
|
||||
<div><span class="details-item-title">登录浏览器:</span>{{ props.row.browser || '未知' }}</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">发件次数:</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" >
|
||||
{{ 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">重置
|
||||
@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="用户邮箱" :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="收件数量"
|
||||
: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="发件数量"
|
||||
: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="邮箱数量"
|
||||
:filtered-value="filteredValue" :filters="filters" v-if="accountNumShow" :label="$t('tabMailboxes')"
|
||||
prop="accountCount"/>
|
||||
<el-table-column v-if="createTimeShow" label="注册时间" min-width="160" prop="createTime">
|
||||
<el-table-column v-if="createTimeShow" :label="$t('tabRegisteredAt')" min-width="160" prop="createTime">
|
||||
<template #default="props">
|
||||
{{ tzDayjs(props.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
{{ tzDayjs(props.row.createTime).format('YYYY-MM-DD HH:mm') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="statusShow" min-width="60px" label="状态" prop="status">
|
||||
<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">删除</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 0" type="primary">正常</el-tag>
|
||||
<el-tag disable-transitions v-else-if="props.row.status === 1" type="danger">封禁</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="身份类型" min-width="140" prop="type">
|
||||
<el-table-column v-if="typeShow" :label="$t('tabRole')" min-width="140" prop="type">
|
||||
<template #default="props">
|
||||
<div class="type">
|
||||
{{ toRoleName(props.row.type) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设置" :width="settingWidth">
|
||||
<el-table-column :label="$t('tabSetting')" :width="settingWidth">
|
||||
<template #default="props">
|
||||
<el-dropdown trigger="click">
|
||||
<el-button size="small" type="primary">操作</el-button>
|
||||
<el-button size="small" type="primary">{{$t('action')}}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openSetPwd(props.row)">改密</el-dropdown-item>
|
||||
<el-dropdown-item @click="openSetType(props.row)">权限</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)">恢复</el-dropdown-item>
|
||||
<el-dropdown-item @click="delUser(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-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -163,35 +163,35 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<el-dialog class="dialog" v-model="setPwdShow" title="修改密码" @closed="resetUserForm">
|
||||
<el-dialog class="dialog" v-model="setPwdShow" :title="$t('changePassword')" @closed="resetUserForm">
|
||||
<div class="dialog-box">
|
||||
<el-input v-model="userForm.password" type="password" placeholder="密码" autocomplete="off">
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog class="dialog" v-model="setTypeShow" title="设置权限" @closed="resetUserForm">
|
||||
<el-dialog class="dialog" v-model="setTypeShow" :title="$t('changePerm')" @closed="resetUserForm">
|
||||
<div class="dialog-box">
|
||||
<el-input disabled model-value="超级管理员" v-if="userForm.type === 0" />
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="showAdd" title="添加用户">
|
||||
<el-dialog v-model="showAdd" :title="$t('addUser')">
|
||||
<div class="container">
|
||||
<el-input v-model="addForm.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<el-input v-model="addForm.email" type="text" :placeholder="$t('emailAccount')" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
ref="mySelect"
|
||||
v-model="addForm.suffix"
|
||||
placeholder="请选择"
|
||||
:placeholder="$t('select')"
|
||||
class="select"
|
||||
>
|
||||
<el-option
|
||||
@@ -208,12 +208,12 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input type="password" v-model="addForm.password" placeholder="密码"/>
|
||||
<el-select v-model="addForm.type" placeholder="身份类型">
|
||||
<el-input type="password" v-model="addForm.password" :placeholder="$t('password')"/>
|
||||
<el-select v-model="addForm.type" :placeholder="$t('perm')">
|
||||
<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')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -239,16 +239,18 @@ 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';
|
||||
|
||||
defineOptions({
|
||||
name: 'user'
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const roleStore = useRoleStore()
|
||||
const userStore = useUserStore()
|
||||
const settingStore = useSettingStore()
|
||||
const filteredValue = ['normal', 'del']
|
||||
const filters = [{text: '正常', value: 'normal'}, {text: '删除', value: 'del'}]
|
||||
const filters = [{text: t('active'), value: 'normal'}, {text: t('deleted'), value: 'del'}]
|
||||
const preserveExpanded = ref(false)
|
||||
const emailWidth = ref(230)
|
||||
const expandWidth = ref(40)
|
||||
@@ -402,9 +404,9 @@ function formatterReceive(e) {
|
||||
}
|
||||
|
||||
function setStatusName(user) {
|
||||
if (user.isDel === 1) return '恢复'
|
||||
if (user.status === 0) return '禁用'
|
||||
if (user.status === 1) return '启用'
|
||||
if (user.isDel === 1) return t('restore')
|
||||
if (user.status === 0) return t('btnBan')
|
||||
if (user.status === 1) return t('enable')
|
||||
}
|
||||
|
||||
const tableRowFormatter = (data) => {
|
||||
@@ -435,7 +437,7 @@ function submit() {
|
||||
|
||||
if (!addForm.email) {
|
||||
ElMessage({
|
||||
message: "邮箱不能为空",
|
||||
message: t('emptyEmailMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -444,7 +446,7 @@ function submit() {
|
||||
|
||||
if (!isEmail(addForm.email + addForm.suffix)) {
|
||||
ElMessage({
|
||||
message: "非法邮箱",
|
||||
message: t('notEmailMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -453,7 +455,7 @@ function submit() {
|
||||
|
||||
if (!addForm.password) {
|
||||
ElMessage({
|
||||
message: "密码不能为空",
|
||||
message: t('emptyPwdMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -462,7 +464,7 @@ function submit() {
|
||||
|
||||
if (addForm.password.length < 6) {
|
||||
ElMessage({
|
||||
message: "密码至少六位",
|
||||
message: t('pwdLengthMsg'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -471,7 +473,7 @@ function submit() {
|
||||
|
||||
if (!addForm.type) {
|
||||
ElMessage({
|
||||
message: "身份类型不能为空",
|
||||
message: t('emptyRole'),
|
||||
type: "error",
|
||||
plain: true
|
||||
})
|
||||
@@ -485,7 +487,7 @@ function submit() {
|
||||
addLoading.value = false
|
||||
showAdd.value = false
|
||||
ElMessage({
|
||||
message: "添加成功",
|
||||
message: t('addSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -498,27 +500,29 @@ function submit() {
|
||||
|
||||
|
||||
function formatSendType(user) {
|
||||
if (user.sendAction.sendType === 'day') return '每天'
|
||||
if (user.sendAction.sendType === 'count') return '总数'
|
||||
if (user.sendAction.sendType === 'day') return t('daily')
|
||||
if (user.sendAction.sendType === 'count') return t('total')
|
||||
}
|
||||
|
||||
function formatSendCount(user) {
|
||||
|
||||
if (!user.sendAction.hasPerm) {
|
||||
return '无权限'
|
||||
return t('noPerm')
|
||||
}
|
||||
|
||||
if (!user.sendAction.sendCount) {
|
||||
return '无限制';
|
||||
return t('noLimit');
|
||||
}
|
||||
|
||||
return user.sendCount + '/' + user.sendAction.sendCount + '次'
|
||||
let count = user.sendCount + '/' + user.sendAction.sendCount
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
function toRoleName(type) {
|
||||
|
||||
if (type === 0) {
|
||||
return '超级管理员'
|
||||
return t('admin')
|
||||
}
|
||||
|
||||
const index = roleList.findIndex(role => role.roleId === type)
|
||||
@@ -530,14 +534,14 @@ function toRoleName(type) {
|
||||
|
||||
function resetSendCount(user) {
|
||||
|
||||
ElMessageBox.confirm(`确认重置${user.email}发件次数吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('reSendConfirm',{msg: user.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userRestSendCount(user.userId).then(() => {
|
||||
ElMessage({
|
||||
message: "重置成功",
|
||||
message: t('reSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -547,14 +551,14 @@ function resetSendCount(user) {
|
||||
}
|
||||
|
||||
function delUser(user) {
|
||||
ElMessageBox.confirm(`确认删除${user.email}吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('delConfirm',{msg: user.email}), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userDelete(user.userId).then(() => {
|
||||
ElMessage({
|
||||
message: "删除成功",
|
||||
message: t('delSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -568,16 +572,16 @@ function restore(user) {
|
||||
const type = ref(0)
|
||||
|
||||
ElMessageBox.confirm( null, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
message: () => h('div', [
|
||||
h('div', { class: 'mb-2' }, `确认要恢复 ${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 }, '普通恢复'),
|
||||
h(ElRadio, { label: 'option2', value: 1 }, '包括已删除的数据'),
|
||||
h(ElRadio, { label: 'option1', value: 0 }, t('normalRestore')),
|
||||
h(ElRadio, { label: 'option2', value: 1 }, t('allRestore')),
|
||||
])
|
||||
]),
|
||||
type: 'warning'
|
||||
@@ -585,7 +589,7 @@ function restore(user) {
|
||||
userRestore(user.userId,type.value).then(() => {
|
||||
user.isDel = 0
|
||||
ElMessage({
|
||||
message: "恢复成功",
|
||||
message: t('restoreSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -596,9 +600,9 @@ function restore(user) {
|
||||
function setStatus(user) {
|
||||
|
||||
if (user.status === 0) {
|
||||
ElMessageBox.confirm(`确认禁用 ${user.email} 吗?`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
ElMessageBox.confirm(t('banRestore',{ msg: user.email }), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
httpSetStatus(user)
|
||||
@@ -613,7 +617,7 @@ function httpSetStatus(user) {
|
||||
userSetStatus({status: status, userId: user.userId}).then(() => {
|
||||
user.status = status
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -626,7 +630,7 @@ function setType() {
|
||||
chooseUser.type = userForm.type
|
||||
setTypeShow.value = false
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -652,7 +656,7 @@ function updatePwd() {
|
||||
|
||||
if (!userForm.password) {
|
||||
ElMessage({
|
||||
message: '密码不能为空',
|
||||
message: t('emptyPwdMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -661,7 +665,7 @@ function updatePwd() {
|
||||
|
||||
if (userForm.password.length < 6) {
|
||||
ElMessage({
|
||||
message: '密码最少六位',
|
||||
message: t('pwdLengthMsg'),
|
||||
type: 'error',
|
||||
plain: true,
|
||||
})
|
||||
@@ -672,7 +676,7 @@ function updatePwd() {
|
||||
userSetPwd({password: userForm.password, userId: userForm.userId}).then(() => {
|
||||
setPwdShow.value = false
|
||||
ElMessage({
|
||||
message: "设置成功",
|
||||
message: t('changSuccessMsg'),
|
||||
type: "success",
|
||||
plain: true
|
||||
})
|
||||
@@ -754,7 +758,7 @@ function adjustWidth() {
|
||||
sendNumShow.value = width > 685
|
||||
typeShow.value = width > 767
|
||||
emailWidth.value = width > 480 ? 230 : null
|
||||
settingWidth.value = width < 480 ? 75 : null
|
||||
settingWidth.value = width < 480 ? (locale.value === 'en' ? 85 : 75) : null
|
||||
expandWidth.value = width < 480 ? 25 : 40
|
||||
pagerCount.value = width < 768 ? 7 : 11
|
||||
receiveWidth.value = width < 480 ? 90 : null
|
||||
@@ -894,7 +898,7 @@ function adjustWidth() {
|
||||
}
|
||||
|
||||
.status-select {
|
||||
width: 80px;
|
||||
width: 95px;
|
||||
|
||||
:deep(.el-select__wrapper) {
|
||||
min-height: 28px;
|
||||
|
||||
Reference in New Issue
Block a user