修改登录页面
This commit is contained in:
12
README.md
12
README.md
@@ -18,6 +18,8 @@
|
||||
|
||||
[**👉在线演示**](https://skymail.ink)
|
||||
|
||||
[**👉小白保姆教程-界面部署**](https://doc.skymail.ink)
|
||||
|
||||
|  |  |
|
||||
|---------------------|---------------------|
|
||||
|  |  |
|
||||
@@ -76,8 +78,6 @@
|
||||
|
||||
## 使用教程
|
||||
|
||||
[**👉小白保姆教程-界面部署**](https://doc.skymail.ink)
|
||||
|
||||
### 环境要求
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ jwt_secret = "" #登录身份令牌的密钥,随便填一串字符串
|
||||
npm run deploy
|
||||
```
|
||||
|
||||
然后进入域名管理->电子邮件->路由规则->Catch-all 地址. 这里选择发送到 worker, 然后选择创建的worker
|
||||
然后在Cloudflare->域名管理->电子邮件->路由规则->Catch-all 地址. 这里选择发送到 worker, 然后选择创建的worker
|
||||
|
||||
浏览器输入 https://<你的项目域名>/api/init/<你的jwt_secret> 初始化或更新 d1和kv数据库
|
||||
|
||||
@@ -148,9 +148,9 @@ npm run deploy
|
||||
|
||||
**邮件发送**
|
||||
|
||||
在resend官网注册后验证你的域名并创建ApiKey,回到项目网站设置页面添加 resend token
|
||||
在resend注册后验证你的域名并创建ApiKey, 回到项目网站设置页面添加 resend token
|
||||
|
||||
Webhooks 添加回调地址https://<你的项目域名>/api/webhooks
|
||||
在resend Webhooks 添加回调地址https://<你的项目域名>/api/webhooks
|
||||
|
||||
勾选✅ (email.bounced email.complained email.delivered email.delivery_delayed)
|
||||
|
||||
@@ -165,7 +165,7 @@ npm run dev
|
||||
```
|
||||
浏览器输入http://127.0.0.1:8787/api/init/<你的jwt_secret>初始化d1和kv数据库
|
||||
|
||||
本地运行r2域名可设置为http://127.0.0.1:8787/api/file
|
||||
本地运行项目页面设置r2域名可设置为http://127.0.0.1:8787/api/file
|
||||
|
||||
|
||||
## 目录结构
|
||||
|
||||
5
mail-vue/package-lock.json
generated
5
mail-vue/package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "video-admin-vue",
|
||||
"name": "mail-vue",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "video-admin-vue",
|
||||
"name": "mail-vue",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@iconify/vue": "^4.3.0",
|
||||
@@ -17,6 +17,7 @@
|
||||
"date-time-format-timezone": "^1.0.22",
|
||||
"dayjs": "^1.11.13",
|
||||
"element-plus": "^2.9.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^3.0.2",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"date-time-format-timezone": "^1.0.22",
|
||||
"dayjs": "^1.11.13",
|
||||
"element-plus": "^2.9.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^3.0.2",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
|
||||
@@ -610,7 +610,7 @@ function loadData() {
|
||||
@media (max-width: 1199px) {
|
||||
padding-right: 15px;
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
@media (max-width: 1024px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
@@ -630,7 +630,7 @@ function loadData() {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-columns: auto 1fr;
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
grid-template-columns: 1fr;
|
||||
> span:last-child {
|
||||
display: none;
|
||||
@@ -719,7 +719,7 @@ function loadData() {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
@media (max-width: 1024px) {
|
||||
.pc-star {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ function submit() {
|
||||
.item {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
padding: 12px 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
|
||||
@@ -52,11 +52,6 @@
|
||||
</el-menu>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<div class="github">
|
||||
<a href="https://github.com/LaziestRen/cloud-mail">
|
||||
<Icon icon="codicon:github-inverted" width="28" height="28" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -75,7 +70,7 @@ const route = useRoute();
|
||||
.title {
|
||||
margin: 15px 10px;
|
||||
height: 50px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
@@ -110,7 +105,7 @@ const route = useRoute();
|
||||
|
||||
.el-menu-item {
|
||||
margin: 5px 10px !important;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
height: 36px;
|
||||
padding: 10px !important;
|
||||
}
|
||||
@@ -148,7 +143,7 @@ const route = useRoute();
|
||||
border-right: 0;
|
||||
width: 250px;
|
||||
@media (max-width: 1199px) {
|
||||
width: 230px;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{{ userStore.user.email }}
|
||||
</div>
|
||||
<div class="detail-user-type">
|
||||
<el-tag type="warning">{{userStore.user.role.name}}</el-tag>
|
||||
<el-tag >{{userStore.user.role.name}}</el-tag>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div>
|
||||
@@ -38,14 +38,14 @@
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span v-if="sendCount !== null" style="margin-right: 5px">{{ sendCount }}</span>
|
||||
<el-tag v-if="!hasPerm('email:send')" type="warning">{{sendType}}</el-tag>
|
||||
<el-tag v-else type="success">{{sendType}}</el-tag>
|
||||
<span v-if="sendCount" style="margin-right: 5px" >{{ sendCount }}</span>
|
||||
<el-tag v-if="!hasPerm('email:send')" >{{sendType}}</el-tag>
|
||||
<el-tag v-else >{{sendType}}</el-tag>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="accountCount && hasPerm('account:add')" style="margin-right: 5px">{{ accountCount }}个</span>
|
||||
<el-tag v-if="!accountCount && hasPerm('account:add')" type="success">无限制</el-tag>
|
||||
<el-tag v-if="!hasPerm('account:add')" type="warning">无权限</el-tag>
|
||||
<el-tag v-if="!accountCount && hasPerm('account:add')" >无限制</el-tag>
|
||||
<el-tag v-if="!hasPerm('account:add')" >无权限</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,6 +84,11 @@ const sendType = computed(() => {
|
||||
if (!hasPerm('email:send')) {
|
||||
return '无权限'
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendCount === 0) {
|
||||
return '无限制'
|
||||
}
|
||||
|
||||
if (userStore.user.role.sendType === 'day') {
|
||||
return '每天'
|
||||
}
|
||||
@@ -99,7 +104,7 @@ const sendCount = computed(() => {
|
||||
}
|
||||
|
||||
if (!userStore.user.role.sendCount) {
|
||||
return '无限制'
|
||||
return null
|
||||
}
|
||||
return userStore.user.sendCount + '/' + userStore.user.role.sendCount
|
||||
})
|
||||
@@ -143,7 +148,7 @@ function formatName(email) {
|
||||
}
|
||||
|
||||
:deep(.el-popper.is-pure) {
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
@@ -196,20 +201,21 @@ function formatName(email) {
|
||||
padding-right: 10px;
|
||||
padding-bottom: 10px;
|
||||
.el-button {
|
||||
height: 26px;
|
||||
border-radius: 8px;
|
||||
height: 28px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.details-avatar {
|
||||
margin-top: 20px;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ import writer from '@/layout/write/index.vue'
|
||||
|
||||
const uiStore = useUiStore();
|
||||
const writerRef = ref({})
|
||||
const isMobile = ref(window.innerWidth < 992)
|
||||
const isMobile = ref(window.innerWidth < 1024)
|
||||
const handleResize = () => {
|
||||
isMobile.value = window.innerWidth < 992
|
||||
uiStore.asideShow = window.innerWidth >= 991;
|
||||
isMobile.value = window.innerWidth < 1024
|
||||
uiStore.asideShow = window.innerWidth >= 1024;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -66,7 +66,7 @@ onBeforeUnmount(() => {
|
||||
transform: translateX(0);
|
||||
transition: all 100ms ease;
|
||||
z-index: 101;
|
||||
@media (max-width: 991px) {
|
||||
@media (max-width: 1024px) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -78,7 +78,7 @@ const handleResize = () => {
|
||||
@media (max-width: 767px) {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
width: 229px;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ const handleResize = () => {
|
||||
position: fixed;
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
@media (max-width: 991px) {
|
||||
width: 229px;
|
||||
@media (max-width: 1024px) {
|
||||
width: 250px;
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ const handleResize = () => {
|
||||
grid-template-columns: 250px 1fr;
|
||||
height: calc(100% - 60px);
|
||||
@media (max-width: 1200px) {
|
||||
grid-template-columns: 229px 1fr;
|
||||
grid-template-columns: 250px 1fr;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@@ -285,13 +285,13 @@ function close() {
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (max-width: 991px) {
|
||||
@media (max-width: 1024px) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
height: min(800px, calc(100vh - 60px));
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ router.afterEach((to) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (window.innerWidth < 992) {
|
||||
if (window.innerWidth < 1024) {
|
||||
uiStore.asideShow = false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4,7 +4,8 @@ export const useSettingStore = defineStore('setting', {
|
||||
state: () => ({
|
||||
domainList: [],
|
||||
settings: {
|
||||
r2Domain: ''
|
||||
r2Domain: '',
|
||||
loginOpacity: 1.00,
|
||||
}
|
||||
}),
|
||||
actions: {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
|
||||
|
||||
export const useUiStore = defineStore('ui', {
|
||||
state: () => ({
|
||||
asideShow: window.innerWidth > 991,
|
||||
asideShow: window.innerWidth > 1024,
|
||||
accountShow: false,
|
||||
backgroundLoading: true,
|
||||
writerRef: null,
|
||||
|
||||
@@ -65,20 +65,20 @@ button, input, select, textarea {
|
||||
}
|
||||
|
||||
.tox .tox-dialog--width-lg {
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
height: 850px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tox .tox-dialog__body-content {
|
||||
max-height: min(850px, calc(100vh - 110px)) !important;
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
max-height: min(850px, calc(100vh - 110px));
|
||||
}
|
||||
}
|
||||
|
||||
.tox .tox-dialog__body-content {
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 1024px) {
|
||||
max-height: min(850px, calc(100vh - 110px)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="login-box" :style="background">
|
||||
<div id="login-box">
|
||||
<div id="background-wrap" v-if="!settingStore.settings.background">
|
||||
<div class="x1 cloud"></div>
|
||||
<div class="x2 cloud"></div>
|
||||
@@ -7,17 +7,14 @@
|
||||
<div class="x4 cloud"></div>
|
||||
<div class="x5 cloud"></div>
|
||||
</div>
|
||||
<div v-else :style="background"></div>
|
||||
<div class="form-wrapper">
|
||||
<div class="container">
|
||||
<span class="form-title">{{ settingStore.settings.title }}</span>
|
||||
<div class="custom-style" v-if="settingStore.settings.register === 0">
|
||||
<el-segmented v-model="show" :options="options"/>
|
||||
</div>
|
||||
<span class="form-title">{{settingStore.settings.title}}</span>
|
||||
<span class="form-desc" v-if="show === 'login'">请输入你的账号信息以开始使用邮箱系统</span>
|
||||
<span class="form-desc" v-else>请输入你的账号密码以开始注册邮箱系统</span>
|
||||
<div v-if="show === 'login'">
|
||||
<el-input v-model="form.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<template #prefix>
|
||||
<Icon icon="weui:email-outlined" width="22" height="22"/>
|
||||
</template>
|
||||
<el-input class="email-input" v-model="form.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
@@ -41,19 +38,13 @@
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="form.password" placeholder="密码" type="password" autocomplete="off">
|
||||
<template #prefix>
|
||||
<Icon icon="carbon:password" width="22" height="22"/>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button class="btn" type="primary" @click="submit" :loading="loginLoading"
|
||||
>登录
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-input v-model="registerForm.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<template #prefix>
|
||||
<Icon icon="weui:email-outlined" width="22" height="22"/>
|
||||
</template>
|
||||
<el-input class="email-input" v-model="registerForm.email" type="text" placeholder="邮箱" autocomplete="off">
|
||||
<template #append>
|
||||
<div @click.stop="openSelect">
|
||||
<el-select
|
||||
@@ -76,34 +67,21 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="registerForm.password" placeholder="密码" type="password" autocomplete="off">
|
||||
<template #prefix>
|
||||
<Icon icon="carbon:password" width="22" height="22"/>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="registerForm.confirmPassword" placeholder="确认密码" type="password" autocomplete="off">
|
||||
<template #prefix>
|
||||
<Icon icon="carbon:password" width="22" height="22"/>
|
||||
</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" />
|
||||
<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"
|
||||
>注册
|
||||
</el-button>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="verifyShow"
|
||||
title="验证你是不是人"
|
||||
width="332"
|
||||
align-center
|
||||
>
|
||||
<div
|
||||
class="register-turnstile"
|
||||
:data-sitekey="settingStore.settings.siteKey"
|
||||
data-callback="onTurnstileSuccess"
|
||||
></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -132,7 +110,6 @@ const form = reactive({
|
||||
password: '',
|
||||
|
||||
});
|
||||
const options = [{label: '登录', value: 'login'}, {label: '注册', value: 'register'}];
|
||||
const mySelect = ref()
|
||||
const suffix = ref('')
|
||||
const registerForm = reactive({
|
||||
@@ -147,6 +124,19 @@ const verifyShow = ref(false)
|
||||
let verifyToken = ''
|
||||
let turnstileId = ''
|
||||
|
||||
|
||||
window.onTurnstileSuccess = (token) => {
|
||||
verifyToken = token;
|
||||
setTimeout(() => {
|
||||
verifyShow.value = false
|
||||
}, 2000)
|
||||
};
|
||||
|
||||
|
||||
const loginOpacity = computed(() => {
|
||||
return `rgba(255, 255, 255, ${settingStore.settings.loginOpacity})`
|
||||
})
|
||||
|
||||
const background = computed(() => {
|
||||
|
||||
return settingStore.settings.background ? {
|
||||
@@ -157,12 +147,6 @@ const background = computed(() => {
|
||||
} : ''
|
||||
})
|
||||
|
||||
window.onTurnstileSuccess = (token) => {
|
||||
verifyToken = token;
|
||||
setTimeout(() => {
|
||||
verifyShow.value = false
|
||||
}, 1500)
|
||||
};
|
||||
|
||||
const openSelect = () => {
|
||||
mySelect.value.toggleMenu()
|
||||
@@ -302,53 +286,103 @@ function submitRegister() {
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.el-select-dropdown__item {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.no-autofill-pwd {
|
||||
.el-input__inner {
|
||||
-webkit-text-security: disc !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.form-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
z-index: 110;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@media (max-width: 767px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 380px;
|
||||
background: #FFFFFF;
|
||||
padding: 20px;
|
||||
margin: 0 20px;
|
||||
border-radius: 8px;
|
||||
background: v-bind(loginOpacity);
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 450px;
|
||||
height: 100%;
|
||||
border: 1px solid #e4e7ed;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
.switch {
|
||||
padding-top: 10px;
|
||||
font-size: 14px;
|
||||
@media (max-width: 1024px) {
|
||||
padding: 20px 18px;
|
||||
border-radius: 6px;
|
||||
width: 384px;
|
||||
margin-left: 18px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
padding: 20px 18px;
|
||||
border-radius: 6px;
|
||||
height: fit-content;
|
||||
width: 100%;
|
||||
margin-right: 18px;
|
||||
margin-left: 18px;
|
||||
}
|
||||
.btn {
|
||||
height: 36px;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
.form-desc {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 18px;
|
||||
color: #71717a;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 22px !important;
|
||||
}
|
||||
|
||||
.switch {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
span {
|
||||
color: #006be6;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.email-input :deep(.el-input__wrapper){
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
height: 38px;
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown__item) {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.setting-icon {
|
||||
position: relative;
|
||||
@@ -358,7 +392,13 @@ function submitRegister() {
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0 !important;
|
||||
padding-left: 8px !important;
|
||||
padding-right: 4px !important;
|
||||
background: #FFFFFF;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.register-turnstile {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.select {
|
||||
@@ -378,6 +418,8 @@ function submitRegister() {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#login-box {
|
||||
background: linear-gradient(to bottom, #2980b9, #6dd5fa, #fff);
|
||||
color: #333;
|
||||
@@ -386,6 +428,8 @@ function submitRegister() {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -242,6 +242,7 @@ function openRoleSet(role) {
|
||||
roleFormShow.value = true
|
||||
form.sort = role.sort
|
||||
form.name = role.name
|
||||
form.description = role.description
|
||||
form.sendType = role.sendType
|
||||
form.sendCount = role.sendCount
|
||||
form.accountCount = role.accountCount
|
||||
|
||||
@@ -85,6 +85,12 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="title-item"><span>登录透明</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>
|
||||
@@ -211,16 +217,21 @@
|
||||
</div>
|
||||
<div class="concerning-item">
|
||||
<span>交流:</span>
|
||||
<el-button @click="jumpTelegram">
|
||||
<el-button @click="jump('https://t.me/cloud_mail_tg')">
|
||||
telegram
|
||||
<template #icon>
|
||||
<Icon icon="logos:telegram" width="30" height="30"/>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button @click="jump('https://github.com/LaziestRen/cloud-mail')">
|
||||
github
|
||||
<template #icon>
|
||||
<Icon icon="codicon:github-inverted" width="22" height="22" />
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -296,6 +307,7 @@ import {Icon} from "@iconify/vue";
|
||||
import {compressImage} from "@/utils/file-utils.js";
|
||||
import {cvtR2Url} from "@/utils/convert.js";
|
||||
import {storeToRefs} from "pinia";
|
||||
import { debounce } from 'lodash-es'
|
||||
|
||||
defineOptions({
|
||||
name: 'sys-setting'
|
||||
@@ -315,7 +327,8 @@ const {settings: setting} = storeToRefs(settingStore);
|
||||
const editTitle = ref('')
|
||||
const settingLoading = ref(false)
|
||||
const r2DomainInput = ref('')
|
||||
let backup = {}
|
||||
const loginOpacity = ref(0)
|
||||
let backup = '{}'
|
||||
const resendTokenForm = reactive({
|
||||
domain: '',
|
||||
token: '',
|
||||
@@ -336,6 +349,18 @@ const options = [
|
||||
|
||||
onMounted(() => {
|
||||
resendTokenForm.domain = settingStore.domainList[0];
|
||||
loginOpacity.value = settingStore.settings.loginOpacity
|
||||
})
|
||||
|
||||
function doOpacityChange() {
|
||||
const form = {...setting.value}
|
||||
form.loginOpacity = loginOpacity.value
|
||||
editSetting(form,true)
|
||||
}
|
||||
|
||||
const opacityChange = debounce(doOpacityChange, 1000, {
|
||||
leading: false,
|
||||
trailing: true
|
||||
})
|
||||
|
||||
function physicsDeleteAllData() {
|
||||
@@ -468,14 +493,15 @@ function saveTitle() {
|
||||
editSetting({title: editTitle.value})
|
||||
}
|
||||
|
||||
function jumpTelegram() {
|
||||
function jump(href) {
|
||||
const doc = document.createElement('a')
|
||||
doc.href = 'https://t.me/cloud_mail_tg'
|
||||
doc.href = href
|
||||
doc.target = '_blank'
|
||||
doc.click()
|
||||
}
|
||||
|
||||
|
||||
|
||||
function editSetting(settingForm, refreshStatus = true) {
|
||||
if (settingLoading.value) return
|
||||
settingLoading.value = true
|
||||
@@ -497,6 +523,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
resendTokenFormShow.value = false
|
||||
turnstileShow.value = false
|
||||
}).catch(() => {
|
||||
loginOpacity.value = setting.value.loginOpacity
|
||||
setting.value = {...setting.value, ...JSON.parse(backup)}
|
||||
}).finally(() => {
|
||||
settingLoading.value = false
|
||||
@@ -535,8 +562,8 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e4e7ed;
|
||||
@media (max-width: 500px) {
|
||||
width: 140px;
|
||||
height: 79px;
|
||||
width: 150px;
|
||||
height: 83px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +729,7 @@ function editSetting(settingForm, refreshStatus = true) {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
align-items: center;
|
||||
span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -728,7 +728,7 @@ adjustWidth()
|
||||
|
||||
function adjustWidth() {
|
||||
const width = window.innerWidth
|
||||
statusShow.value = width > 1060
|
||||
statusShow.value = width > 1090
|
||||
createTimeShow.value = width > 1200
|
||||
accountNumShow.value = width > 650
|
||||
sendNumShow.value = width > 685
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
mail-worker/dist/index.html
vendored
4
mail-worker/dist/index.html
vendored
@@ -6,8 +6,8 @@
|
||||
<title></title>
|
||||
<link rel="icon" href="/assets/favicon-C5dAZutX.svg" type="image/svg+xml">
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||
<script type="module" crossorigin src="/assets/index-BMdBWW7j.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Blmh8UBo.css">
|
||||
<script type="module" crossorigin src="/assets/index-DQ5PlDSG.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-6pbK1Sk3.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading-first">
|
||||
|
||||
@@ -13,6 +13,7 @@ export const setting = sqliteTable('setting', {
|
||||
secretKey: text('secret_key'),
|
||||
siteKey: text('site_key'),
|
||||
background: text('background'),
|
||||
loginOpacity: integer('login_opacity').default(0.9),
|
||||
resendTokens: text('resend_tokens').default("{}").notNull(),
|
||||
});
|
||||
export default setting
|
||||
|
||||
@@ -29,6 +29,7 @@ const initService = {
|
||||
`ALTER TABLE setting ADD COLUMN site_key TEXT;`,
|
||||
`ALTER TABLE setting ADD COLUMN secret_key TEXT;`,
|
||||
`ALTER TABLE setting ADD COLUMN background TEXT;`,
|
||||
`ALTER TABLE setting ADD COLUMN login_opacity INTEGER NOT NULL DEFAULT 0.88;`,
|
||||
|
||||
`ALTER TABLE user ADD COLUMN create_ip TEXT;`,
|
||||
`ALTER TABLE user ADD COLUMN active_ip TEXT;`,
|
||||
|
||||
@@ -58,7 +58,7 @@ const loginService = {
|
||||
|
||||
const userId = await userService.insert(c, { email, password: hash, salt, type: roleRow.roleId });
|
||||
|
||||
await userService.updateUserInfo(c, userId);
|
||||
await userService.updateUserInfo(c, userId, true);
|
||||
|
||||
await accountService.insert(c, { userId: userId, email });
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user