2024-07-02 14:28:15 +08:00
|
|
|
<script lang="ts" setup>
|
|
|
|
import Vcode from 'vue3-puzzle-vcode';
|
|
|
|
|
|
|
|
definePageMeta({
|
|
|
|
layout: 'login',
|
|
|
|
})
|
|
|
|
import * as Yup from 'yup';
|
|
|
|
import {useToast} from "vue-toastification";
|
|
|
|
|
|
|
|
const toast = useToast()
|
|
|
|
const errors = ref<string[]>([]);
|
|
|
|
const isShow = ref(false);
|
|
|
|
|
|
|
|
//表单存储对象
|
|
|
|
const form = reactive({
|
|
|
|
emailOrUserName: '',
|
|
|
|
password: '',
|
|
|
|
});
|
|
|
|
const schema = Yup.object().shape({
|
|
|
|
emailOrUserName: Yup.string().required('邮箱或用户名不能为空'),
|
|
|
|
password: Yup.string().min(6, '密码至少需要6个字符').required('密码不能为空')
|
|
|
|
});
|
|
|
|
//登录表单提交事件
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
try {
|
|
|
|
// 验证表单
|
|
|
|
await schema.validate(form, {abortEarly: false});
|
|
|
|
errors.value = []; // 清空错误信息
|
|
|
|
// 表单验证通过,处理登录逻辑
|
|
|
|
isShow.value = true;
|
|
|
|
// 这里可以调用你的登录API
|
|
|
|
} catch (error) {
|
|
|
|
// 处理验证错误
|
|
|
|
if (error instanceof Yup.ValidationError) {
|
|
|
|
errors.value = error.inner.map(e => e.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const onSuccess = () => {
|
|
|
|
isShow.value = false;
|
|
|
|
$fetch('/Api/Account/Login', {
|
|
|
|
method: 'post',
|
|
|
|
body: form,
|
|
|
|
baseURL: useRuntimeConfig().public.baseUrl,
|
|
|
|
}).then((res) => {
|
|
|
|
const data=res as any;
|
|
|
|
useCookie('token').value =data.token;
|
|
|
|
toast.success(`欢迎回来 ${data.nickName}!`)
|
|
|
|
setTimeout(()=>{
|
|
|
|
navigateTo("/home")
|
|
|
|
},2000)
|
|
|
|
}).catch(err=>{
|
|
|
|
if(err.response.status===401){
|
|
|
|
toast.error('登录失败,邮箱未验证')
|
|
|
|
const data=err.response._data
|
|
|
|
console.log(data)
|
|
|
|
setTimeout(()=>{
|
|
|
|
navigateTo(`/verifyEmail/${data.id}_${data.email}`)
|
|
|
|
},2000)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if(err.response.status===402){
|
2024-07-02 16:08:07 +08:00
|
|
|
toast.info('登录失败,密码过期,请修改密码')
|
2024-07-02 14:28:15 +08:00
|
|
|
const data=err.response._data
|
2024-07-02 16:08:07 +08:00
|
|
|
useCookie('tokenPassword').value =data.tokenPassword;
|
2024-07-02 14:28:15 +08:00
|
|
|
setTimeout(()=>{
|
2024-07-02 16:08:07 +08:00
|
|
|
navigateTo({
|
|
|
|
path:'/changePassword',
|
|
|
|
query:{
|
|
|
|
id:data.id
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
2024-07-02 14:28:15 +08:00
|
|
|
},2000)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
toast.error('登录失败,'+err.response._data)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<div class="SignIn-Box">
|
|
|
|
<Vcode :show="isShow" @success="onSuccess"/>
|
|
|
|
<div class="intro">
|
|
|
|
<h1>欢迎回来 👋</h1>
|
|
|
|
<h2>今天是新的一天。这是你的一天。你塑造它。
|
|
|
|
登录以开始管理您的项目。</h2>
|
|
|
|
</div>
|
|
|
|
<form class="login-form" @submit.prevent="handleSubmit">
|
|
|
|
<div class="form-item">
|
|
|
|
<label>电子邮件/账号</label>
|
|
|
|
<input required type="text" v-model="form.emailOrUserName" placeholder="Example@email.com">
|
|
|
|
</div>
|
|
|
|
<div class="form-item">
|
|
|
|
<label>密码</label>
|
|
|
|
<input required minlength="8" v-model="form.password" type="password" placeholder="至少 8 个字符">
|
|
|
|
</div>
|
|
|
|
<a :href="'/forgotPassword/'+form.emailOrUserName">忘记密码</a>
|
|
|
|
<button type="submit">登录</button>
|
|
|
|
</form>
|
|
|
|
<div class="social-sign-in">
|
|
|
|
<div class="or">
|
|
|
|
<hr/>
|
|
|
|
<span>or</span>
|
|
|
|
<hr/>
|
|
|
|
</div>
|
|
|
|
<div class="social-button">
|
|
|
|
<button>
|
2024-08-03 11:27:39 +08:00
|
|
|
<img src="/Google.svg" alt=""/>
|
2024-07-02 14:28:15 +08:00
|
|
|
<p>使用 Google 帐号登录</p>
|
|
|
|
</button>
|
|
|
|
<button>
|
2024-08-03 11:27:39 +08:00
|
|
|
<img src="/Facebook.svg" alt=""/>
|
2024-07-02 14:28:15 +08:00
|
|
|
<p>使用 Facebook 登录</p></button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
@import "base";
|
|
|
|
|
|
|
|
.SignIn-Box {
|
|
|
|
display: grid;
|
|
|
|
grid-template-rows: repeat(3,auto);
|
|
|
|
width: 400px;
|
|
|
|
gap: 48px;
|
|
|
|
}
|
|
|
|
@media screen and (max-width: 400px){
|
|
|
|
.SignIn-Box{
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.intro{
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: 28px;
|
|
|
|
h1{
|
|
|
|
color: #0C1421;
|
|
|
|
text-align: center;
|
|
|
|
font-size: 36px;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 800;
|
|
|
|
line-height: 100%; /* 36px */
|
|
|
|
letter-spacing: 0.36px;
|
2024-07-22 21:05:18 +08:00
|
|
|
.dark-mode &{
|
|
|
|
color: #FFF;
|
|
|
|
}
|
2024-07-02 14:28:15 +08:00
|
|
|
}
|
|
|
|
h2{
|
|
|
|
color: #313957;
|
|
|
|
font-size: 20px;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 400;
|
|
|
|
line-height: 160%; /* 32px */
|
|
|
|
letter-spacing: 0.2px;
|
2024-07-22 21:05:18 +08:00
|
|
|
|
|
|
|
.dark-mode &{
|
|
|
|
color: #e3e3e3;
|
|
|
|
}
|
2024-07-02 14:28:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.login-form{
|
|
|
|
display: flex;
|
|
|
|
gap: 24px;
|
|
|
|
flex-direction: column;
|
|
|
|
.form-item{
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: 8px;
|
2024-07-22 21:05:18 +08:00
|
|
|
|
|
|
|
.dark-mode &{
|
|
|
|
label{
|
|
|
|
color: #FFF;
|
|
|
|
}
|
|
|
|
input{
|
|
|
|
background: #0C1421;
|
|
|
|
color: #FFF;
|
|
|
|
}
|
|
|
|
}
|
2024-07-02 14:28:15 +08:00
|
|
|
label{
|
|
|
|
color: #0C1421;
|
|
|
|
font-feature-settings: 'clig' off, 'liga' off;
|
|
|
|
font-size: 16px;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 400;
|
|
|
|
line-height: 100%; /* 16px */
|
|
|
|
letter-spacing: 0.16px;
|
|
|
|
}
|
|
|
|
input{
|
|
|
|
padding: 16px;
|
|
|
|
border-radius: 12px;
|
|
|
|
border: 1px solid #D4D7E3;
|
|
|
|
background: #F7FBFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a:first-of-type{
|
|
|
|
align-self: end;
|
|
|
|
color: #1E4AE9;
|
|
|
|
font-feature-settings: 'clig' off, 'liga' off;
|
|
|
|
font-size: 16px;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 400;
|
|
|
|
line-height: 100%; /* 16px */
|
|
|
|
letter-spacing: 0.16px;
|
|
|
|
}
|
|
|
|
button{
|
|
|
|
display: flex;
|
|
|
|
padding: 16px 0;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
border-radius: 12px;
|
|
|
|
background: #162D3A;
|
|
|
|
color: #FFF;
|
|
|
|
text-align: center;
|
|
|
|
font-size: 20px;
|
|
|
|
font-weight: 400;
|
|
|
|
line-height: 100%; /* 20px */
|
|
|
|
letter-spacing: 2px;
|
2024-07-22 21:05:18 +08:00
|
|
|
.dark-mode &{
|
|
|
|
background: #FFF;
|
|
|
|
color: #162D3A;
|
|
|
|
}
|
2024-07-02 14:28:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.social-sign-in{
|
|
|
|
display: flex;
|
|
|
|
gap: 24px;
|
|
|
|
flex-direction: column;
|
|
|
|
.or{
|
|
|
|
display: flex;
|
|
|
|
width: 100%;
|
|
|
|
gap: 16px;
|
|
|
|
align-items: center;
|
|
|
|
hr{
|
|
|
|
flex: 1;
|
|
|
|
height: 1px;
|
|
|
|
color: #CFDFE2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.social-button{
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: 16px;
|
|
|
|
button{
|
|
|
|
height: 52px;
|
|
|
|
display: flex;
|
|
|
|
padding: 12px 9px;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
gap: 16px;
|
|
|
|
border: unset;
|
|
|
|
align-self: stretch;
|
|
|
|
border-radius: 12px;
|
|
|
|
background: #F3F9FA;
|
|
|
|
color: #313957;
|
|
|
|
font-feature-settings: 'clig' off, 'liga' off;
|
|
|
|
font-size: 16px;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 400;
|
|
|
|
line-height: 100%;
|
|
|
|
letter-spacing: 0.16px;
|
|
|
|
svg{
|
|
|
|
height: 28px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|