LoongPanel-Asp/web/pages/SignIn.vue

255 lines
5.6 KiB
Vue
Raw Normal View History

2024-06-22 10:54:02 +08:00
<script lang="ts" setup>
import Vcode from 'vue3-puzzle-vcode';
definePageMeta({
layout: 'login',
})
import * as Yup from 'yup';
import type {HttpType} from "~/types/baseType";
import {useToast} from "#imports";
const toast = useToast()
const errors = ref<string[]>([]);
const isShow = ref(false);
//表单存储对象
const form = reactive({
emailOrUserName: '',
password: '',
remember: false
});
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 HttpType<any>;
if (data.code == 200) {
useCookie('token').value = data.data['token'];
toast.add({severity: 'success', summary: '登录成功', detail: `欢迎回来!${data.data['userName']}`, life: 3000})
setTimeout(() => {
navigateTo('/Home')
}, 1000)
} else {
toast.add({severity: 'error', summary: data.message, detail: "发生了错误", life: 3000})
}
})
}
</script>
<template>
<div class="SignIn-Box">
<Vcode :show="isShow" @success="onSuccess"/>
<div class="SignIn-Box-Header"><h1>登录</h1>
<h3>登录以保持连接.</h3></div>
<div class="SignIn-Box-From">
<div v-if="errors.length>0" class="SignIn-Box-From-Errors">
<InlineMessage v-for="error in errors" severity="error">{{ error }}</InlineMessage>
</div>
<form @submit.prevent="handleSubmit">
<div class="From-Group">
<label for="email">邮箱/用户名</label>
<InputText id="email" v-model="form.emailOrUserName" aria-describedby="username-help"/>
</div>
<div class="From-Group">
<label for="password">密码</label>
<Password id="password" v-model="form.password" :feedback="false"/>
</div>
<div class="From-Group-Check">
<div class="flex align-items-center">
<Checkbox v-model="form.remember" :binary="true" inputId="remember" name="remember"/>
<label class="ml-2" for="remember"> 记住我? </label>
</div>
<a href="#">
忘记密码?
</a>
</div>
<div class="From-Action">
<Button label="登录" type="submit"/>
</div>
</form>
</div>
<div class="SignIn-Box-Bottom">
<p>还是使用其他帐户登录</p>
<div>
<NuxtImg height="40" src="/Gmail.svg" width="40"/>
<NuxtImg height="40" src="/Facebook.svg" width="40"/>
<NuxtImg height="40" src="/Instagram.svg" width="40"/>
<NuxtImg height="40" src="/Linkedin.svg" width="40"/>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
@import "base";
.SignIn-Box {
display: flex;
flex-direction: column;
gap: $gap*2;
width: 360px;
> * {
transition: all 0.3s ease;
}
}
.SignIn-Box-Header {
display: flex;
flex-direction: column;
gap: $gap*2;
align-items: center;
h3 {
color: $unfocused-color;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 175%; /* 28px */
}
}
.SignIn-Box-From {
display: flex;
flex-direction: column;
gap: $gap*2;
> form {
display: flex;
flex-direction: column;
gap: $gap*2;
}
}
.From-Group {
display: flex;
flex-direction: column;
gap: $gap;
label {
color: $unfocused-color;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 175%; /* 28px */
}
}
.SignIn-Box-Bottom {
display: flex;
gap: $gap*2;
flex-direction: column;
align-items: center;
justify-content: center;
> p {
color: $light-text-color;
font-size: 16px;
}
> div {
display: flex;
height: 30px;
overflow: hidden;
gap: 24px;
}
}
.SignIn-Box-From-Errors {
display: flex;
flex-direction: column;
align-items: center;
gap: $gap;
.p-inline-message {
padding: $padding*.25 $padding;
min-width: 250px;
gap: $gap;
}
}
//primeVue
:deep(.p-inputtext) {
padding: $padding*.5 $padding;
border-radius: $radius;
width: 100%;
border: 1px solid $primary-color;
&:enabled:hover {
border: 1px solid $primary-color;
box-shadow: 0 0 0 2px $primary-color;
}
&:enabled:focus {
outline: 2px solid $primary-color;
}
}
.From-Group-Check {
display: flex;
justify-content: space-between;
& > * {
display: flex;
align-items: center;
gap: $gap;
}
label {
color: $unfocused-color;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 175%; /* 28px */
}
}
.From-Action {
display: flex;
justify-content: center;
margin-top: $padding*.5;
.p-button {
display: flex;
width: 100%;
padding: $padding*.75;
justify-content: center;
align-items: center;
border-radius: $radius;
background: $primary-color;
}
}
.dark-mode {
h1, h2, h3, p {
color: $dark-text-color;
}
:deep(.p-inputtext) {
background: $dark-bg-color;
}
}
</style>