重构:重构登录页面前端代码

This commit is contained in:
Charles7c 2023-02-04 13:16:41 +08:00
parent d035d5a362
commit 35e2964b49
3 changed files with 95 additions and 114 deletions

View File

@ -2,25 +2,29 @@ import axios from 'axios';
import type { RouteRecordNormalized } from 'vue-router'; import type { RouteRecordNormalized } from 'vue-router';
import { UserState } from '@/store/modules/login/types'; import { UserState } from '@/store/modules/login/types';
const BASE_URL = '/auth';
export interface LoginReq { export interface LoginReq {
username: string; username: string;
password: string; password: string;
captcha: string; captcha: string;
uuid: string; uuid: string;
} }
export interface LoginRes { export interface LoginRes {
token: string; token: string;
} }
export function login(req: LoginReq) { export function login(req: LoginReq) {
return axios.post<LoginRes>('/auth/login', req); return axios.post<LoginRes>(`${BASE_URL}/login`, req);
} }
export function logout() { export function logout() {
return axios.post('/auth/logout'); return axios.post(`${BASE_URL}/logout`);
} }
export function getUserInfo() { export function getUserInfo() {
return axios.get<UserState>('/auth/user/info'); return axios.get<UserState>(`${BASE_URL}/user/info`);
} }
export function getMenuList() { export function getMenuList() {

View File

@ -2,66 +2,46 @@
<div class="login-form-wrapper"> <div class="login-form-wrapper">
<div class="login-form-title">{{ $t('login.form.title') }}</div> <div class="login-form-title">{{ $t('login.form.title') }}</div>
<div class="login-form-sub-title">{{ $t('login.form.subTitle') }}</div> <div class="login-form-sub-title">{{ $t('login.form.subTitle') }}</div>
<div class="login-form-error-msg">{{ errorMessage }}</div>
<a-form <a-form
ref="formRef" ref="formRef"
:model="formData" :model="form"
:rules="rules" :rules="rules"
class="login-form"
layout="vertical" layout="vertical"
class="login-form"
@submit="handleLogin" @submit="handleLogin"
> >
<a-form-item <a-form-item field="username" hide-label>
field="username"
:validate-trigger="['change', 'blur']"
hide-label
>
<a-input <a-input
v-model="formData.username" v-model="form.username"
:placeholder="$t('login.form.placeholder.username')" :placeholder="$t('login.form.placeholder.username')"
size="large"
max-length="50" max-length="50"
size="large"
> >
<template #prefix> <template #prefix><icon-user /></template>
<icon-user />
</template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item <a-form-item field="password" hide-label>
field="password"
:validate-trigger="['change', 'blur']"
hide-label
>
<a-input-password <a-input-password
v-model="formData.password" v-model="form.password"
:placeholder="$t('login.form.placeholder.password')" :placeholder="$t('login.form.placeholder.password')"
size="large"
allow-clear
max-length="32" max-length="32"
allow-clear
size="large"
> >
<template #prefix> <template #prefix><icon-lock /></template>
<icon-lock />
</template>
</a-input-password> </a-input-password>
</a-form-item> </a-form-item>
<a-form-item <a-form-item class="login-form-captcha" field="captcha" hide-label>
class="login-form-captcha"
field="captcha"
:validate-trigger="['change', 'blur']"
hide-label
>
<a-input <a-input
v-model="formData.captcha" v-model="form.captcha"
:placeholder="$t('login.form.placeholder.captcha')" :placeholder="$t('login.form.placeholder.captcha')"
allow-clear
size="large" size="large"
style="width: 63%" style="width: 63%"
allow-clear
> >
<template #prefix> <template #prefix><icon-check-circle /></template>
<icon-check-circle />
</template>
</a-input> </a-input>
<img :src="captchaImgBase64" @click="getCaptcha" :alt="$t('login.form.captcha')"> <img :src="captchaImgBase64" :alt="$t('login.form.captcha')" @click="getCaptcha">
</a-form-item> </a-form-item>
<a-space :size="16" direction="vertical"> <a-space :size="16" direction="vertical">
<div class="login-form-remember-me"> <div class="login-form-remember-me">
@ -73,7 +53,7 @@
{{ $t('login.form.rememberMe') }} {{ $t('login.form.rememberMe') }}
</a-checkbox> </a-checkbox>
</div> </div>
<a-button type="primary" size="large" html-type="submit" long :loading="loading"> <a-button :loading="loading" type="primary" size="large" long html-type="submit">
{{ $t('login.form.login') }} {{ $t('login.form.login') }}
</a-button> </a-button>
</a-space> </a-space>
@ -82,23 +62,23 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed, onMounted } from 'vue'; import { getCurrentInstance, ref, toRefs, reactive, computed } from "vue";
import { useRouter } from 'vue-router'; import { FieldRule, ValidatedError } from '@arco-design/web-vue';
import { FieldRule, Message } from '@arco-design/web-vue'; import { LoginReq } from '@/api/auth/login';
import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
// import debug from '@/utils/env'; import { useRouter } from 'vue-router';
import { encryptByRsa } from '@/utils/encrypt';
import { useStorage } from '@vueuse/core'; import { useStorage } from '@vueuse/core';
import { useLoginStore } from '@/store'; import { useLoginStore } from '@/store';
import useLoading from '@/hooks/loading'; import { encryptByRsa } from '@/utils/encrypt';
// import debug from '@/utils/env';
const { proxy } = getCurrentInstance() as any;
const captchaImgBase64 = ref('');
const loginStore = useLoginStore();
const loading = ref(false);
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
const { loading, setLoading } = useLoading();
const loginStore = useLoginStore();
const errorMessage = ref('');
const captchaImgBase64 = ref('');
const loginConfig = useStorage('login-config', { const loginConfig = useStorage('login-config', {
rememberMe: true, rememberMe: true,
username: 'admin', // username: 'admin', //
@ -106,59 +86,56 @@
// username: !debug ? '' : 'admin', // // username: !debug ? '' : 'admin', //
// password: !debug ? '' : 'admin123', // // password: !debug ? '' : 'admin123', //
}); });
const formData = reactive({
const data = reactive({
//
form: {
username: loginConfig.value.username, username: loginConfig.value.username,
password: loginConfig.value.password, password: loginConfig.value.password,
captcha: '', captcha: '',
uuid: '', uuid: '',
}); } as LoginReq,
const rules = computed((): Record<string, FieldRule[]> => { //
rules: computed((): Record<string, FieldRule[]> => {
return { return {
username: [ username: [{ required: true, message: t('login.form.error.required.username') }],
{ required: true, message: t('login.form.error.required.username') } password: [{ required: true, message: t('login.form.error.required.password') }],
], captcha: [{ required: true, message: t('login.form.error.required.captcha') }],
password: [
{ required: true, message: t('login.form.error.required.password') }
],
captcha: [
{ required: true, message: t('login.form.error.required.captcha') }
],
} }
}),
}); });
const { form, rules } = toRefs(data);
// /**
const getCaptcha = async () => { * 获取验证码
const { data } = await loginStore.getImgCaptcha() */
formData.uuid = data.uuid const getCaptcha = () => {
captchaImgBase64.value = data.img loginStore.getImgCaptcha().then((res) => {
} form.value.uuid = res.data.uuid;
onMounted(() => { captchaImgBase64.value = res.data.img;
getCaptcha(); });
})
//
const setRememberMe = (value: boolean) => {
loginConfig.value.rememberMe = value;
}; };
getCaptcha();
// /**
const handleLogin = async ({ * 登录
errors, *
values, * @param errors 表单验证错误
}: { * @param values 表单数据
*/
const handleLogin = ({ errors, values, }: {
errors: Record<string, ValidatedError> | undefined; errors: Record<string, ValidatedError> | undefined;
values: Record<string, any>; values: Record<string, any>;
}) => { }) => {
if (loading.value) return; if (loading.value) return;
if (!errors) { if (!errors) {
setLoading(true); loading.value = true;
try { loginStore.login({
await loginStore.login({
username: values.username, username: values.username,
password: encryptByRsa(values.password) || '', password: encryptByRsa(values.password) || '',
captcha: values.captcha, captcha: values.captcha,
uuid: values.uuid uuid: values.uuid
}); }).then(() => {
const { redirect, ...othersQuery } = router.currentRoute.value.query; const { redirect, ...othersQuery } = router.currentRoute.value.query;
router.push({ router.push({
name: (redirect as string) || 'Workplace', name: (redirect as string) || 'Workplace',
@ -166,21 +143,32 @@
...othersQuery, ...othersQuery,
}, },
}); });
Message.success(t('login.form.login.success'));
const { rememberMe } = loginConfig.value; const { rememberMe } = loginConfig.value;
const { username } = values; const { username } = values;
loginConfig.value.username = rememberMe ? username : ''; loginConfig.value.username = rememberMe ? username : '';
} catch (err) { proxy.$message.success(t('login.form.login.success'));
await getCaptcha(); }).catch(() => {
} finally { getCaptcha();
setLoading(false); }).finally(() => {
} loading.value = false;
});
} }
}; };
/**
* 记住我
*
* @param value 是否记住我
*/
const setRememberMe = (value: boolean) => {
loginConfig.value.rememberMe = value;
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.login-form { .login-form {
margin-top: 32px;
&-wrapper { &-wrapper {
width: 320px; width: 320px;
} }
@ -198,12 +186,6 @@
line-height: 24px; line-height: 24px;
} }
&-error-msg {
height: 32px;
color: rgb(var(--red-6));
line-height: 32px;
}
&-captcha img { &-captcha img {
width: 111px; width: 111px;
height: 36px; height: 36px;

View File

@ -1,10 +1,7 @@
<template> <template>
<div class="container"> <div class="container">
<div class="logo"> <div class="logo">
<img <img src="/logo.svg" alt="logo" />
alt="logo"
src="/logo.svg"
/>
<div class="logo-text">{{ $t('title') }}</div> <div class="logo-text">{{ $t('title') }}</div>
</div> </div>
<LoginBanner /> <LoginBanner />
@ -67,9 +64,7 @@
font-size: 20px; font-size: 20px;
} }
} }
</style>
<style lang="less" scoped>
@media (max-width: @screen-lg) { @media (max-width: @screen-lg) {
.container { .container {
.banner { .banner {