提交 9a297d19 编写于 作者: H haoxr

feat: 新增登录验证码

上级 40c40fa9
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LoginData, LoginResult } from './types';
import { CaptchaResult, LoginData, LoginResult } from './types';
/**
* 登录API
......@@ -25,3 +25,15 @@ export function logoutApi() {
method: 'delete'
});
}
/**
* 获取验证码
*/
export function getCaptchaApi(): AxiosPromise<CaptchaResult> {
return request({
url: '/api/v1/auth/captcha',
method: 'get'
});
}
......@@ -5,11 +5,21 @@ export interface LoginData {
/**
* 用户名
*/
username: string;
username?: string;
/**
* 密码
*/
password: string;
password?: string;
/**
* 验证码缓存key
*/
verifyCodeKey?: string;
/**
* 验证码
*/
verifyCode?: string;
}
/**
......@@ -33,3 +43,18 @@ export interface LoginResult {
*/
tokenType?: string;
}
/**
* 验证码响应
*/
export interface CaptchaResult {
/**
* 验证码缓存key
*/
verifyCodeKey: string;
/**
* 验证码图片Base64字符串
*/
verifyCodeBase64: string;
}
<svg t="1655050462467" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2131"
width="200" height="200">
<path
d="M917.6 267.2c-36.1-2.5-72.4-9.3-103.6-19.3-10.1-3-20.2-6.4-30.3-10-21.4-6.3-50.5-18.8-83.6-36.6-0.4-0.2-0.7-0.4-1.1-0.6-7.8-4.2-15.7-8.7-23.8-13.4-10.9-6.3-21.7-12.9-32.5-19.9-0.4-0.3-0.8-0.5-1.2-0.8-7.7-5-15.5-10.2-23.1-15.5-5-3.4-10-7.1-15-10.7-3.8-2.8-7.5-5.3-11.3-8.2-27.4-20.5-54.5-43.5-79.9-68.3-25.4 24.8-52.5 47.8-79.9 68.3-3.7 2.8-7.5 5.4-11.3 8.2-5 3.6-10 7.3-15 10.7-7.7 5.4-15.4 10.5-23.1 15.5-0.4 0.3-0.8 0.5-1.2 0.8-10.8 6.9-21.6 13.6-32.5 19.9-8.1 4.7-16 9.2-23.8 13.4-0.3 0.2-0.7 0.4-1 0.6-33 17.8-62.2 30.3-83.6 36.6-10.1 3.6-20.2 7-30.3 10-31.1 10-67.4 16.8-103.6 19.3h0.1c1.1 16.2 2.1 37.7 3.4 60.9h0.7c6.1 86.8 23.5 210.2 49.7 282.8 1.2 3.2 2.2 6.5 3.3 9.6 0.6 1.5 1.2 2.8 1.8 4.3 62.8 162.1 171.9 280.1 303 323.4v0.4c17.3 5.7 31.9 9.3 43.5 11.5 11.5-2.2 26.1-5.8 43.5-11.5v-0.4C687 905 796.1 787 858.9 624.8c0.6-1.5 1.2-2.8 1.8-4.3 1.2-3.1 2.2-6.4 3.3-9.6 26.2-72.5 43.6-196 49.7-282.8h0.7c1.1-23.3 2.2-44.7 3.2-60.9z m-47.4 41.9l-0.5 9.5c-0.5 2.2-0.9 4.4-1 6.6C863 406 847 525.7 821.3 596.7c-0.7 1.9-1.4 3.9-2 5.8-0.4 1.2-0.8 2.5-1.4 4.1-0.5 1.2-1 2.5-1.4 3.4C758.1 760.8 657.7 869.3 541 907.8c-1.9 0.6-3.7 1.4-5.5 2.2-7.9 2.5-15.7 4.6-23.2 6.3-7.5-1.7-15.2-3.8-23.1-6.3-1.8-0.9-3.6-1.6-5.5-2.2-116.7-38.5-217.1-147-275.4-297.5-0.5-1.2-0.9-2.4-1.7-4.1-0.4-1.2-0.8-2.4-1.3-3.6-0.7-2-1.3-3.9-1.9-5.6-25.8-71.2-41.7-191-47.4-271.7-0.2-2.3-0.5-4.5-1-6.6l-0.5-9.3c-0.1-1.5-0.2-3-0.2-4.5 24.6-3.8 48.4-9.3 70-16.2 10.1-3 20.4-6.4 31.4-10.4 25.2-7.6 56.5-21.2 90.5-39.6 0.6-0.3 1.2-0.6 1.7-0.9 8.2-4.4 16.7-9.2 24.8-14 10.7-6.1 22-13 34.5-21.1 0.4-0.2 1-0.6 1.3-0.8 8.2-5.3 16.4-10.8 24.1-16.2 4.5-3.1 9.1-6.4 13.7-9.7l2.4-1.8 4-2.9c2.6-1.9 5.2-3.7 7.5-5.5 17.9-13.4 35.3-27.5 52-42.1 16.7 14.7 34 28.7 51.8 42 2.6 1.9 5.1 3.8 7.7 5.6l4.3 3.1 1.5 1.1c4.8 3.5 9.6 6.9 14 9.9 8.1 5.7 16.3 11.2 23.7 16l2.1 1.3c12.4 8 23.7 14.9 34.1 20.8 8.6 5 17 9.8 25 14.1 0.4 0.2 1 0.5 1.5 0.8 34.2 18.4 65.6 32.1 90.9 39.7 11 3.9 21.3 7.3 30.6 10.1 22.1 7.1 46.1 12.6 70.8 16.5 0.1 1.5 0.1 3 0 4.4z"
p-id="2132"></path>
<path
d="M710.6 411.2L476.1 651.6l-120-123c-8.3-8.5-21.8-8.5-30.1 0s-8.3 22.3 0 30.9L461.1 698c4.2 4.3 9.6 6.4 15.1 6.4 5.4 0 10.9-2.1 15-6.4l249.5-255.7c8.3-8.5 8.3-22.3 0-30.9-8.3-8.7-21.8-8.7-30.1-0.2z"
p-id="2133"></path>
</svg>
......@@ -10,10 +10,7 @@ export default {
username: 'Username',
password: 'Password',
login: 'Login',
code: 'Verification Code',
copyright: '',
icp: '',
thirdPartyLogin: 'third-party login'
verifyCode: 'Verify Code',
},
// 导航栏国际化
navbar: {
......
......@@ -10,10 +10,7 @@ export default {
username: '用户名',
password: '密码',
login: '登 录',
code: '请输入验证码',
copyright: '',
icp: '',
thirdPartyLogin: '第三方登录'
verifyCode: '验证码'
},
navbar: {
dashboard: '首页',
......
<template>
<div class="login-container">
<el-form
ref="loginFormRef"
:model="loginData"
:rules="loginRules"
class="login-form"
>
<el-form ref="loginFormRef" :model="loginData" :rules="loginRules" class="login-form">
<div class="flex text-white items-center py-4">
<span class="text-2xl flex-1 text-center">{{ $t('login.title') }}</span>
<lang-select style="color: #fff" />
......@@ -15,51 +10,40 @@
<div class="p-2 text-white">
<svg-icon icon-class="user" />
</div>
<el-input
class="flex-1"
ref="username"
size="large"
v-model="loginData.username"
:placeholder="$t('login.username')"
name="username"
/>
<el-input class="flex-1" ref="username" size="large" v-model="loginData.username"
:placeholder="$t('login.username')" name="username" />
</el-form-item>
<el-tooltip
:disabled="isCapslock === false"
content="Caps lock is On"
placement="right"
>
<el-tooltip :disabled="isCapslock === false" content="Caps lock is On" placement="right">
<el-form-item prop="password">
<span class="p-2 text-white">
<svg-icon icon-class="password" />
</span>
<el-input
class="flex-1"
v-model="loginData.password"
placeholder="密码"
:type="passwordVisible === false ? 'password' : 'input'"
size="large"
name="password"
@keyup="checkCapslock"
@keyup.enter="handleLogin"
/>
<el-input class="flex-1" v-model="loginData.password" placeholder="密码"
:type="passwordVisible === false ? 'password' : 'input'" size="large" name="password" @keyup="checkCapslock"
@keyup.enter="handleLogin" />
<span class="mr-2" @click="passwordVisible = !passwordVisible">
<svg-icon
:icon-class="passwordVisible === false ? 'eye' : 'eye-open'"
class="text-white cursor-pointer"
/>
<svg-icon :icon-class="passwordVisible === false ? 'eye' : 'eye-open'" class="text-white cursor-pointer" />
</span>
</el-form-item>
</el-tooltip>
<el-button
size="default"
:loading="loading"
type="primary"
class="w-full"
@click.prevent="handleLogin"
>{{ $t('login.login') }}
<!-- 验证码 -->
<el-form-item prop="verifyCode">
<span class="p-2 text-white">
<svg-icon icon-class="verify_code" />
</span>
<el-input v-model="loginData.verifyCode" auto-complete="off" :placeholder="$t('login.verifyCode')" class="w-[60%]"
@keyup.enter="handleLogin" />
<div class="captcha">
<img :src="captchaBase64" @click="getCaptcha" />
</div>
</el-form-item>
<el-button size="default" :loading="loading" type="primary" class="w-full" @click.prevent="handleLogin">{{
$t('login.login') }}
</el-button>
<!-- 账号密码提示 -->
......@@ -81,6 +65,7 @@ import { useUserStore } from '@/store/modules/user';
// API依赖
import { LocationQuery, LocationQueryValue, useRoute } from 'vue-router';
import { getCaptchaApi } from '@/api/auth';
import { LoginData } from '@/api/auth/types';
const userStore = useUserStore();
......@@ -90,15 +75,17 @@ const loginFormRef = ref(ElForm);
const loginData = ref<LoginData>({
username: 'admin',
password: '123456'
password: '123456',
});
const loginRules = {
username: [{ required: true, trigger: 'blur' }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
password: [{ required: true, trigger: 'blur', validator: validatePassword }],
// verifyCode: [{ required: true, trigger: 'blur' }],
};
const passwordVisible = ref(false);
const captchaBase64 = ref()
const loading = ref(false);
......@@ -119,7 +106,18 @@ function checkCapslock(e: any) {
}
/**
* 登录
* 验证码
*/
function getCaptcha() {
getCaptchaApi().then(({ data }) => {
const { verifyCodeBase64, verifyCodeKey } = data;
loginData.value.verifyCodeKey = verifyCodeKey;
captchaBase64.value = verifyCodeBase64;
});
}
/**
* 登录
*/
function handleLogin() {
loginFormRef.value.validate((valid: boolean) => {
......@@ -150,9 +148,26 @@ function handleLogin() {
}
});
}
onMounted(() => {
getCaptcha();
});
</script>
<style lang="scss" scoped>
.captcha {
position: absolute;
right: 0;
top: 0;
img {
height: 48px;
width: 120px;
cursor: pointer;
}
}
.login-container {
min-height: 100%;
width: 100%;
......@@ -167,6 +182,7 @@ function handleLogin() {
overflow: hidden;
}
}
.el-form-item {
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.1);
......@@ -175,17 +191,20 @@ function handleLogin() {
.el-input {
background: transparent;
// 子组件 scoped 无效,使用 :deep
:deep(.el-input__wrapper) {
padding: 0;
background: transparent;
box-shadow: none;
.el-input__inner {
background: transparent;
border: 0px;
border-radius: 0px;
color: #fff;
caret-color: #fff;
&:-webkit-autofill {
box-shadow: 0 0 0 1000px transparent inset !important;
-webkit-text-fill-color: #fff !important;
......@@ -202,5 +221,6 @@ function handleLogin() {
}
}
}
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册