LoongPanel-Asp/web/pages/SignIn.vue

255 lines
5.6 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>