feat: login i18n
This commit is contained in:
parent
506788fc76
commit
e11054ed0d
|
@ -6,6 +6,10 @@ import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
|||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
const info = useKUNGalgameMessageStore()
|
||||
|
||||
// 导入 i18n
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { tm } = useI18n()
|
||||
|
||||
// 父组件让它发送验证码它再发送
|
||||
const props = defineProps<{
|
||||
email: string
|
||||
|
@ -37,16 +41,14 @@ const sendCode = () => {
|
|||
// 发送验证码
|
||||
useKUNGalgameUserStore().sendCode(props.email)
|
||||
|
||||
info.info(
|
||||
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
|
||||
)
|
||||
info.info(tm('AlertInfo.code.code'))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button @click="sendCode" :disabled="isSending">
|
||||
{{ isSending ? countdown : '发送验证码' }}
|
||||
{{ isSending ? countdown : $tm('login.register.send') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ export default {
|
|||
publish: 'Confirm Publish',
|
||||
draft: 'Save Draft',
|
||||
},
|
||||
login: {
|
||||
login: {
|
||||
loginTitle: 'Login',
|
||||
forget: 'Forgot your password? Click here to send reset email',
|
||||
|
@ -175,6 +176,30 @@ export default {
|
|||
loginPassword: 'Password',
|
||||
capture: 'Click to proceed with the human verification process',
|
||||
},
|
||||
overlay: {
|
||||
title: 'Welcome to KUN Visual Novel Registration',
|
||||
world: `The World's`,
|
||||
moe: 'Cutest',
|
||||
forum: 'Galgame Forum',
|
||||
login: 'Login',
|
||||
home: 'Welcome Back',
|
||||
kun: 'KUN Visual Novel Gives You',
|
||||
hug: 'The Warmest Hug',
|
||||
register: 'Register',
|
||||
},
|
||||
register: {
|
||||
title: 'Register',
|
||||
name: 'username',
|
||||
email: 'email',
|
||||
password: 'password',
|
||||
code: 'Email verification code',
|
||||
send: 'Send code',
|
||||
click: 'Clicking Register means you have agreed to our',
|
||||
agreement: 'User Agreement',
|
||||
and: 'and',
|
||||
privacy: 'Privacy Policy',
|
||||
},
|
||||
},
|
||||
// 非页面组件这里统一用大驼峰
|
||||
ComponentAlert: {
|
||||
confirm: 'OK',
|
||||
|
@ -189,8 +214,6 @@ export default {
|
|||
},
|
||||
login: {
|
||||
success: 'Login Successfully! Welcome to KUN Visual Novel ~ ',
|
||||
emptyUsername: 'Username cannot be empty',
|
||||
emptyPassword: 'Password cannot be empty',
|
||||
invalidUsername:
|
||||
'Invalid username. Username should be 1 to 17 characters long and can include: Chinese characters, English letters, numbers, underscore, and tilde (~)',
|
||||
invalidPassword:
|
||||
|
@ -206,5 +229,8 @@ export default {
|
|||
hint4: `Za~~~ko~♡ zako~♡ Just you wait, you'll regret it in the end`,
|
||||
answer: 'Answer',
|
||||
},
|
||||
code: {
|
||||
code: `The verification code has been sent. You can check it in your email. Please check your spam folder. If you haven't received the email, you can try to resend the email verification code after 30 seconds.`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -167,6 +167,7 @@ export default {
|
|||
publish: '确认发布',
|
||||
draft: '保存草稿',
|
||||
},
|
||||
login: {
|
||||
login: {
|
||||
loginTitle: '登录',
|
||||
forget: '忘记密码? 点击发送重置邮件',
|
||||
|
@ -174,6 +175,30 @@ export default {
|
|||
loginPassword: '密码',
|
||||
capture: '点击进行人机身份验证',
|
||||
},
|
||||
overlay: {
|
||||
title: '欢迎注册 KUNgalgame',
|
||||
world: `世界上最`,
|
||||
moe: '萌',
|
||||
forum: '的 Galgame 论坛',
|
||||
login: '登录',
|
||||
home: '欢迎回家',
|
||||
kun: 'KUNgalgame 给你',
|
||||
hug: '最温暖的拥抱',
|
||||
register: '注册',
|
||||
},
|
||||
register: {
|
||||
title: '注册',
|
||||
name: '用户名',
|
||||
email: '邮箱',
|
||||
password: '密码',
|
||||
code: '邮箱验证码',
|
||||
send: '发送验证码',
|
||||
click: '点击注册表示您已经同意我们的',
|
||||
agreement: '用户协议',
|
||||
and: '和',
|
||||
privacy: '隐私政策',
|
||||
},
|
||||
},
|
||||
// 非页面组件这里统一用大驼峰
|
||||
ComponentAlert: {
|
||||
confirm: '确定',
|
||||
|
@ -188,8 +213,6 @@ export default {
|
|||
},
|
||||
login: {
|
||||
login: '登陆成功!欢迎来到 鲲 Galgame ~ ',
|
||||
emptyUsername: '用户名不可为空',
|
||||
emptyPassword: '密码不可为空',
|
||||
invalidUsername:
|
||||
'非法的用户名,用户名为 1 到 17 位,可以包含:中文、英文、数字、下划线、波浪线',
|
||||
invalidPassword:
|
||||
|
@ -205,5 +228,8 @@ export default {
|
|||
hint4: '杂~~~鱼~♡杂鱼~♡你就看吧,最后害的还是你自己',
|
||||
answer: '答案',
|
||||
},
|
||||
code: {
|
||||
code: '验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
width: 100%;
|
||||
/* 头部的颜色 */
|
||||
background-color: var(--kungalgame-trans-blue-0);
|
||||
border-radius: 7px 7px 0 0;
|
||||
align-items: center;
|
||||
span:nth-child(1) {
|
||||
font-family: serif;
|
||||
|
|
|
@ -70,6 +70,7 @@ const navBar: nav[] = [
|
|||
height: 100%;
|
||||
width: 120px;
|
||||
background-color: var(--kungalgame-trans-pink-0);
|
||||
border-radius: 0 0 0 7px;
|
||||
border-right: 1px solid var(--kungalgame-blue-4);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
|
|
@ -38,19 +38,28 @@ const handleClickRegister = () => {
|
|||
<div class="overlay">
|
||||
<div class="panel left">
|
||||
<h2>
|
||||
欢迎注册 KUNgalgame <br /><br />—— 世界上最<span>萌</span>的
|
||||
galgame 论坛
|
||||
{{ $tm('login.overlay.title') }}<br /><br />——
|
||||
{{ $tm('login.overlay.world') }}
|
||||
<span>{{ $tm('login.overlay.moe') }}</span>
|
||||
{{ $tm('login.overlay.forum') }}
|
||||
</h2>
|
||||
<br />
|
||||
<button class="btn" @click="handleClickSignIn">登陆</button>
|
||||
<button class="btn" @click="handleClickSignIn">
|
||||
{{ $tm('login.overlay.login') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel right">
|
||||
<h2>
|
||||
欢迎回家 <br />
|
||||
{{ $tm('login.overlay.home') }}
|
||||
<br />
|
||||
KUNgalgame 给你最温暖的拥抱
|
||||
<br />
|
||||
{{ $tm('login.overlay.kun') }}
|
||||
<br />
|
||||
{{ $tm('login.overlay.hug') }}
|
||||
</h2>
|
||||
<button class="btn" @click="handleClickRegister">注册</button>
|
||||
<button class="btn" @click="handleClickRegister">
|
||||
{{ $tm('login.overlay.register') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -98,45 +107,29 @@ const handleClickRegister = () => {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.container.active .login {
|
||||
.container.active {
|
||||
.login {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.container.active .register {
|
||||
.register {
|
||||
animation: show 0.6s;
|
||||
opacity: 1;
|
||||
transform: translateX(100%);
|
||||
z-index: 5;
|
||||
}
|
||||
@keyframes show {
|
||||
0%,
|
||||
49.99% {
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
50%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
|
||||
.container.active .container-overlay {
|
||||
.container-overlay {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.container.active .overlay {
|
||||
.overlay {
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
.container.active .left {
|
||||
.left {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.container.active .right {
|
||||
.right {
|
||||
transform: translateX(20%);
|
||||
}
|
||||
}
|
||||
|
||||
.container-overlay {
|
||||
height: 100%;
|
||||
|
@ -155,55 +148,6 @@ const handleClickRegister = () => {
|
|||
transform: translateX(0);
|
||||
transition: transform 0.6s ease-in-out;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: absolute;
|
||||
bottom: 7%;
|
||||
border-radius: 50px;
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-blue-4);
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
letter-spacing: 0.1rem;
|
||||
padding: 0.6rem 4rem;
|
||||
text-transform: uppercase;
|
||||
transition: transform 80ms ease-in;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn:hover {
|
||||
background-color: var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-white);
|
||||
}
|
||||
/* 交互页面的盒子 */
|
||||
.panel {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
transform: translateX(0);
|
||||
transition: transform 0.6s ease-in-out;
|
||||
width: 50%;
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
}
|
||||
.btn {
|
||||
/* 红色按钮距离底部的距离 */
|
||||
position: absolute;
|
||||
bottom: 7%;
|
||||
background-color: var(--kungalgame-red-0);
|
||||
border: 1px solid var(--kungalgame-red-4);
|
||||
color: var(--kungalgame-red-4);
|
||||
}
|
||||
.btn:hover {
|
||||
background-color: var(--kungalgame-red-4);
|
||||
color: var(--kungalgame-white);
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 150px;
|
||||
|
@ -225,12 +169,64 @@ h2 span {
|
|||
right: 0;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
/* 交互页面的盒子 */
|
||||
.panel {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
transform: translateX(0);
|
||||
transition: transform 0.6s ease-in-out;
|
||||
width: 50%;
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
padding: 7px 0px;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.2s;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
/* 红色按钮距离底部的距离 */
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
background-color: var(--kungalgame-red-0);
|
||||
border: 1px solid var(--kungalgame-red-4);
|
||||
color: var(--kungalgame-red-4);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--kungalgame-red-4);
|
||||
color: var(--kungalgame-white);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
.btn:focus {
|
||||
outline: none;
|
||||
@keyframes show {
|
||||
0%,
|
||||
49.99% {
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
50%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
z-index: 5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,6 +4,8 @@ import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
|||
import { useRouter } from 'vue-router'
|
||||
// 使用全局通知
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
|
||||
// 导入人机验证组件
|
||||
const Capture = defineAsyncComponent(
|
||||
|
@ -38,7 +40,6 @@ const handleVerify = (result: boolean) => {
|
|||
if (result) {
|
||||
// 处理人机校验完成后的逻辑
|
||||
isShowValidate.value = false
|
||||
info.info(tm('AlertInfo.capture.success'))
|
||||
isCaptureComplete.value = true
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +48,11 @@ const isEmptyInput = (): boolean => {
|
|||
// 如果输入的字段为空
|
||||
if (!loginForm.name.trim()) {
|
||||
// 提示用户输入的名字为空
|
||||
info.info(tm('AlertInfo.login.emptyUsername'))
|
||||
message('Username cannot be empty', '用户名不可为空', 'warn')
|
||||
return false
|
||||
} else if (!loginForm.password.trim()) {
|
||||
// 提示用户输入的密码为空
|
||||
info.info(tm('AlertInfo.login.emptyPassword'))
|
||||
message('Password cannot be empty', '密码不可为空', 'warn')
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
|
@ -86,7 +87,11 @@ const handleLogin = () => {
|
|||
}
|
||||
// 未完成人机身份验证提示信息,直接返回
|
||||
if (!isCaptureComplete.value) {
|
||||
info.info(tm('AlertInfo.capture.click'))
|
||||
message(
|
||||
'Please click above to complete the human verification',
|
||||
'请点击上方完成人机身份验证',
|
||||
'warn'
|
||||
)
|
||||
return
|
||||
}
|
||||
// 所有的验证都通过了再向后端发送请求
|
||||
|
@ -110,29 +115,29 @@ const handleLogin = () => {
|
|||
:isShowValidate="isShowValidate"
|
||||
/>
|
||||
<div class="form">
|
||||
<h2 class="title">{{ $tm('login.loginTitle') }}</h2>
|
||||
<h2 class="title">{{ $tm('login.login.loginTitle') }}</h2>
|
||||
<input
|
||||
v-model="loginForm.name"
|
||||
type="text"
|
||||
:placeholder="($tm('login.loginUsername') as string)"
|
||||
:placeholder="($tm('login.login.loginUsername') as string)"
|
||||
class="input"
|
||||
/>
|
||||
<input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
:placeholder="($tm('login.loginPassword') as string)"
|
||||
:placeholder="($tm('login.login.loginPassword') as string)"
|
||||
class="input"
|
||||
/>
|
||||
|
||||
<!-- 忘记密码 -->
|
||||
<span class="forget">{{ $tm('login.forget') }}</span>
|
||||
<span class="forget">{{ $tm('login.login.forget') }}</span>
|
||||
<span @click="isShowValidate = true" class="capture">{{
|
||||
$tm('login.capture')
|
||||
$tm('login.login.capture')
|
||||
}}</span>
|
||||
|
||||
<!-- 点击登录 -->
|
||||
<button @click="handleLogin" class="btn" type="submit">
|
||||
{{ $tm('login.loginTitle') }}
|
||||
{{ $tm('login.login.loginTitle') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,6 +204,7 @@ const handleLogin = () => {
|
|||
}
|
||||
|
||||
.btn {
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
border-radius: 50px;
|
||||
|
@ -208,7 +214,7 @@ const handleLogin = () => {
|
|||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
padding: 7px 50px;
|
||||
padding: 7px 0px;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.2s;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<!--
|
||||
TODO: 注册表单未完成,注册逻辑未完成,发送验证码的逻辑未完成,i18n 未完成
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// 使用全局通知
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
// 全局消息组件(顶部)
|
||||
import message from '@/components/alert/Message'
|
||||
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
||||
|
@ -16,6 +15,11 @@ import {
|
|||
import Code from '@/components/verification-code/Code.vue'
|
||||
import Capture from '@/components/capture/Capture.vue'
|
||||
|
||||
// 导入 i18n
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { tm } = useI18n()
|
||||
const info = useKUNGalgameMessageStore()
|
||||
|
||||
const router = useRouter()
|
||||
const isShowValidate = ref(false)
|
||||
const isCaptureComplete = ref(false)
|
||||
|
@ -83,6 +87,7 @@ const isValidInput = (): boolean => {
|
|||
const handleSendCode = () => {
|
||||
// 表单为空
|
||||
if (!isValidInput()) {
|
||||
message('Form cannot be empty', '表单不可为空', 'warn')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -99,10 +104,20 @@ const handleSendCode = () => {
|
|||
|
||||
const handleRegister = () => {
|
||||
if (!isSendCode.value) {
|
||||
message(
|
||||
'Need to send an email verification code',
|
||||
'需要发送邮箱验证码',
|
||||
'warn'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (!registerForm.code.trim()) {
|
||||
message(
|
||||
'Email verification code cannot be empty',
|
||||
'邮箱验证码不可为空',
|
||||
'warn'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -124,6 +139,7 @@ const handleRegister = () => {
|
|||
if (res.code === 200) {
|
||||
router.push('/')
|
||||
message('Register successfully!', '注册成功!', 'success')
|
||||
info.info(tm('AlertInfo.login.success'))
|
||||
} else {
|
||||
}
|
||||
})
|
||||
|
@ -146,13 +162,13 @@ const handleRegister = () => {
|
|||
<!-- 注册表单 -->
|
||||
<div class="form">
|
||||
<!-- 标题 -->
|
||||
<h2 class="title">注册</h2>
|
||||
<h2 class="title">{{ $tm('login.register.title') }}</h2>
|
||||
|
||||
<div class="container" v-for="item in registerFormItem" :key="item.index">
|
||||
<input
|
||||
v-model="registerForm[item.value]"
|
||||
:type="item.type"
|
||||
:placeholder="item.placeholder"
|
||||
:placeholder="`${$tm(`login.register.${item.placeholder}`)}`"
|
||||
:class="item.class"
|
||||
/>
|
||||
</div>
|
||||
|
@ -165,14 +181,24 @@ const handleRegister = () => {
|
|||
/>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button @click="handleRegister" class="btn" type="submit">注册</button>
|
||||
<button @click="handleRegister" class="btn" type="submit">
|
||||
{{ $tm('login.register.title') }}
|
||||
</button>
|
||||
|
||||
<!-- 用户协议提示等 -->
|
||||
<span class="user-agreement">
|
||||
点击注册表示您已经同意我们的
|
||||
<router-link to="/licence"><span>用户协议</span></router-link>
|
||||
和
|
||||
<router-link to="/privacy"><span>隐私政策</span></router-link>
|
||||
{{ $tm('login.register.click') }}
|
||||
|
||||
<!-- 用户协议和隐私政策 -->
|
||||
<div class="licence">
|
||||
<router-link to="/licence">
|
||||
<span>{{ $tm('login.register.agreement') }}</span>
|
||||
</router-link>
|
||||
{{ $tm('login.register.and') }}
|
||||
<router-link to="/privacy">
|
||||
<span>{{ $tm('login.register.privacy') }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -246,9 +272,15 @@ const handleRegister = () => {
|
|||
color: var(--kungalgame-red-4);
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.licence {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
border-radius: 50px;
|
||||
|
@ -258,7 +290,7 @@ const handleRegister = () => {
|
|||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
letter-spacing: 2px;
|
||||
padding: 7px 50px;
|
||||
padding: 7px 0;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.2s;
|
||||
margin-top: 30px;
|
||||
|
|
|
@ -11,28 +11,28 @@ export const registerFormItem: RegisterFormItem[] = [
|
|||
index: 1,
|
||||
value: 'name',
|
||||
type: 'text',
|
||||
placeholder: '用户名',
|
||||
placeholder: 'name',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
value: 'email',
|
||||
type: 'email',
|
||||
placeholder: '邮箱',
|
||||
placeholder: 'email',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
value: 'password',
|
||||
type: 'text',
|
||||
placeholder: '密码',
|
||||
placeholder: 'password',
|
||||
class: 'input',
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
value: 'code',
|
||||
type: 'text',
|
||||
placeholder: '邮箱验证码',
|
||||
placeholder: 'code',
|
||||
class: 'input',
|
||||
},
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue