|
@ -0,0 +1,155 @@ |
|
|
|
|
|
<template> |
|
|
|
|
|
<context-holder /> |
|
|
|
|
|
<div id="container"> |
|
|
|
|
|
<a-spin v-if="loading" tip="Loading..."></a-spin> |
|
|
|
|
|
<a-form v-else :model="formState" name="normal_login" class="login-form" @submit.prevent="login"> |
|
|
|
|
|
<h2>博客管理系统</h2> |
|
|
|
|
|
<a-form-item label="用户名" name="username" :rules="[{ required: true, validator: verifyName }]"> |
|
|
|
|
|
<a-input v-model:value="formState.username" placeholder="请输入用户名"> |
|
|
|
|
|
<template #prefix> |
|
|
|
|
|
<UserOutlined class="site-form-item-icon" /> |
|
|
|
|
|
</template> |
|
|
|
|
|
</a-input> |
|
|
|
|
|
</a-form-item> |
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="密 码" name="password" |
|
|
|
|
|
:rules="[{ required: true, validator: verifyPassword }]"> |
|
|
|
|
|
<a-input-password v-model:value="formState.password" placeholder="请输入密码"> |
|
|
|
|
|
<template #prefix> |
|
|
|
|
|
<LockOutlined class="site-form-item-icon" /> |
|
|
|
|
|
</template> |
|
|
|
|
|
</a-input-password> |
|
|
|
|
|
</a-form-item> |
|
|
|
|
|
<a-form-item> |
|
|
|
|
|
<a-form-item name="remember" no-style> |
|
|
|
|
|
<a-checkbox v-model:checked="formState.remember">记住我</a-checkbox> |
|
|
|
|
|
</a-form-item> |
|
|
|
|
|
<a class="login-form-forgot" href="">忘记密码?</a> |
|
|
|
|
|
</a-form-item> |
|
|
|
|
|
|
|
|
|
|
|
<a-form-item> |
|
|
|
|
|
<a-button type="primary" html-type="submit" class="login-form-button" :disabled="disabled"> |
|
|
|
|
|
登 录 |
|
|
|
|
|
</a-button> |
|
|
|
|
|
Or |
|
|
|
|
|
<a href="">注册</a> |
|
|
|
|
|
</a-form-item> |
|
|
|
|
|
</a-form> |
|
|
|
|
|
</div> |
|
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
|
|
|
import { reactive, computed, ref, onMounted } from 'vue'; |
|
|
|
|
|
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'; |
|
|
|
|
|
import { useRouter } from 'vue-router'; |
|
|
|
|
|
import { post } from '@/tools/request' |
|
|
|
|
|
import { message } from 'ant-design-vue'; |
|
|
|
|
|
import { validator } from '@/hooks/intex' |
|
|
|
|
|
const [messageApi, contextHolder] = message.useMessage(); |
|
|
|
|
|
|
|
|
|
|
|
interface FormState { |
|
|
|
|
|
username: string; |
|
|
|
|
|
password: string; |
|
|
|
|
|
remember: boolean; |
|
|
|
|
|
} |
|
|
|
|
|
const verifyName = validator(4, 10, { |
|
|
|
|
|
info: '请输入用户名', |
|
|
|
|
|
tooshort: '用户名不能少于4个字符', |
|
|
|
|
|
toolong: '用户名不能超过10个字符', |
|
|
|
|
|
}); |
|
|
|
|
|
const verifyPassword = validator(6, 10, { |
|
|
|
|
|
info: "请输入密码", |
|
|
|
|
|
tooshort: "密码不能少于6个字符", |
|
|
|
|
|
toolong: "密码不能超过10个字符" |
|
|
|
|
|
}); |
|
|
|
|
|
const formState = reactive<FormState>({ |
|
|
|
|
|
username: '', |
|
|
|
|
|
password: '', |
|
|
|
|
|
remember: false, |
|
|
|
|
|
}); |
|
|
|
|
|
const loading = ref(false) |
|
|
|
|
|
const disabled = computed(() => { |
|
|
|
|
|
return !(formState.username && formState.password); |
|
|
|
|
|
}); |
|
|
|
|
|
const router = useRouter(); |
|
|
|
|
|
const login = async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
loading.value = true; |
|
|
|
|
|
const response = await post( |
|
|
|
|
|
'users/token', |
|
|
|
|
|
{ |
|
|
|
|
|
username: formState.username, |
|
|
|
|
|
password: formState.password, |
|
|
|
|
|
}, |
|
|
|
|
|
false, |
|
|
|
|
|
{ |
|
|
|
|
|
'Accept': 'application/json', |
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded' |
|
|
|
|
|
} |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const token = response.data.access_token; |
|
|
|
|
|
localStorage.setItem('token', token); |
|
|
|
|
|
messageApi.success("登录成功") |
|
|
|
|
|
if (formState.remember) { |
|
|
|
|
|
localStorage.setItem('rememberedUsername', formState.username); |
|
|
|
|
|
} else { |
|
|
|
|
|
localStorage.removeItem('rememberedUsername'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
router.push('/admin/dashboard'); |
|
|
|
|
|
}, 2000); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
messageApi.error('用户或密码输入错误'); |
|
|
|
|
|
} finally { |
|
|
|
|
|
loading.value = false; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
onMounted(() => { |
|
|
|
|
|
const rememberedUsername = localStorage.getItem('rememberedUsername'); |
|
|
|
|
|
if (rememberedUsername) { |
|
|
|
|
|
formState.username = rememberedUsername; |
|
|
|
|
|
formState.remember = true; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
<style scoped> |
|
|
|
|
|
#container { |
|
|
|
|
|
display: flex; |
|
|
|
|
|
width: 100vw; |
|
|
|
|
|
height: 100vh; |
|
|
|
|
|
justify-content: center; |
|
|
|
|
|
align-items: center; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#container::before { |
|
|
|
|
|
content: ''; |
|
|
|
|
|
position: absolute; |
|
|
|
|
|
top: 0; |
|
|
|
|
|
left: 0; |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
height: 100%; |
|
|
|
|
|
background-image: url('@/assets/images/login.jpg'); |
|
|
|
|
|
opacity: 0.2; |
|
|
|
|
|
/* 设置透明度 */ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
h2 { |
|
|
|
|
|
text-align: center; |
|
|
|
|
|
color: rgba(41, 39, 51, 0.88); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#components-form-demo-normal-login .login-form { |
|
|
|
|
|
max-width: 300px; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#components-form-demo-normal-login .login-form-forgot { |
|
|
|
|
|
float: right; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#components-form-demo-normal-login .login-form-button { |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
} |
|
|
|
|
|
</style> |