-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: 重构登录页面 UI 以适配多因子认证、第三方登录等场景
- Loading branch information
Showing
13 changed files
with
659 additions
and
397 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
continew-admin-ui/src/views/login/components/account-login.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
<template> | ||
<a-form | ||
ref="formRef" | ||
:model="form" | ||
:rules="rules" | ||
layout="vertical" | ||
size="large" | ||
class="login-form" | ||
@submit="handleLogin" | ||
> | ||
<a-form-item field="username" hide-label> | ||
<a-input | ||
v-model="form.username" | ||
:placeholder="$t('login.account.placeholder.username')" | ||
:max-length="64" | ||
allow-clear | ||
/> | ||
</a-form-item> | ||
<a-form-item field="password" hide-label> | ||
<a-input-password | ||
v-model="form.password" | ||
:placeholder="$t('login.account.placeholder.password')" | ||
:max-length="32" | ||
/> | ||
</a-form-item> | ||
<a-form-item field="captcha" hide-label> | ||
<a-input | ||
v-model="form.captcha" | ||
:placeholder="$t('login.account.placeholder.captcha')" | ||
:max-length="4" | ||
allow-clear | ||
style="flex: 1 1" | ||
/> | ||
<img | ||
:src="captchaImgBase64" | ||
:alt="$t('login.captcha')" | ||
class="captcha" | ||
@click="getCaptcha" | ||
/> | ||
</a-form-item> | ||
<div class="remember-me"> | ||
<a-checkbox | ||
:model-value="loginConfig.rememberMe" | ||
@change="setRememberMe as any" | ||
> | ||
{{ $t('login.rememberMe') }} | ||
</a-checkbox> | ||
</div> | ||
<a-button class="btn" :loading="loading" type="primary" html-type="submit" | ||
>{{ $t('login.button') }} | ||
</a-button> | ||
</a-form> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { getCurrentInstance, ref, toRefs, reactive } from 'vue'; | ||
import { useI18n } from 'vue-i18n'; | ||
import { useStorage } from '@vueuse/core'; | ||
import { useLoginStore } from '@/store'; | ||
import { LoginReq } from '@/api/auth/login'; | ||
import { ValidatedError } from '@arco-design/web-vue'; | ||
import { encryptByRsa } from '@/utils/encrypt'; | ||
import { useRouter } from 'vue-router'; | ||
const { proxy } = getCurrentInstance() as any; | ||
const { t } = useI18n(); | ||
const router = useRouter(); | ||
const loginStore = useLoginStore(); | ||
const loading = ref(false); | ||
const captchaImgBase64 = ref(); | ||
const loginConfig = useStorage('login-config', { | ||
rememberMe: true, | ||
username: 'admin', // 演示默认值 | ||
password: 'admin123', // 演示默认值 | ||
// username: debug ? 'admin' : '', // 演示默认值 | ||
// password: debug ? 'admin123' : '', // 演示默认值 | ||
}); | ||
const data = reactive({ | ||
form: { | ||
username: loginConfig.value.username, | ||
password: loginConfig.value.password, | ||
captcha: '', | ||
uuid: '', | ||
} as LoginReq, | ||
rules: { | ||
username: [ | ||
{ required: true, message: t('login.account.error.required.username') }, | ||
], | ||
password: [ | ||
{ required: true, message: t('login.account.error.required.password') }, | ||
], | ||
captcha: [ | ||
{ required: true, message: t('login.account.error.required.captcha') }, | ||
], | ||
}, | ||
}); | ||
const { form, rules } = toRefs(data); | ||
/** | ||
* 获取验证码 | ||
*/ | ||
const getCaptcha = () => { | ||
loginStore.getImgCaptcha().then((res) => { | ||
form.value.uuid = res.data.uuid; | ||
captchaImgBase64.value = res.data.img; | ||
}); | ||
}; | ||
getCaptcha(); | ||
/** | ||
* 登录 | ||
* | ||
* @param errors 表单验证错误 | ||
* @param values 表单数据 | ||
*/ | ||
const handleLogin = ({ | ||
errors, | ||
values, | ||
}: { | ||
errors: Record<string, ValidatedError> | undefined; | ||
values: Record<string, any>; | ||
}) => { | ||
if (loading.value) return; | ||
if (!errors) { | ||
loading.value = true; | ||
loginStore | ||
.login({ | ||
username: values.username, | ||
password: encryptByRsa(values.password) || '', | ||
captcha: values.captcha, | ||
uuid: values.uuid, | ||
}) | ||
.then(() => { | ||
const { redirect, ...othersQuery } = router.currentRoute.value.query; | ||
router.push({ | ||
name: (redirect as string) || 'Workplace', | ||
query: { | ||
...othersQuery, | ||
}, | ||
}); | ||
const { rememberMe } = loginConfig.value; | ||
const { username } = values; | ||
loginConfig.value.username = rememberMe ? username : ''; | ||
proxy.$notification.success(t('login.success')); | ||
}) | ||
.catch(() => { | ||
getCaptcha(); | ||
form.value.captcha = ''; | ||
}) | ||
.finally(() => { | ||
loading.value = false; | ||
}); | ||
} | ||
}; | ||
/** | ||
* 记住我 | ||
* | ||
* @param value 是否记住我 | ||
*/ | ||
const setRememberMe = (value: boolean) => { | ||
loginConfig.value.rememberMe = value; | ||
}; | ||
</script> | ||
|
||
<style lang="less" scoped> | ||
.login-form { | ||
box-sizing: border-box; | ||
padding: 0 5px; | ||
margin-top: 16px; | ||
.arco-input-wrapper, | ||
:deep(.arco-select-view-single) { | ||
background-color: var(--color-bg-white); | ||
border: 1px solid var(--color-border-3); | ||
height: 40px; | ||
border-radius: 4px; | ||
font-size: 13px; | ||
} | ||
.arco-input-wrapper.arco-input-error { | ||
background-color: var(--color-danger-light-1); | ||
border-color: var(--color-danger-light-4); | ||
} | ||
.captcha { | ||
width: 111px; | ||
height: 36px; | ||
margin: 0 0 0 5px; | ||
cursor: pointer; | ||
} | ||
.remember-me { | ||
display: flex; | ||
justify-content: space-between; | ||
.arco-checkbox { | ||
padding-left: 0; | ||
} | ||
} | ||
.btn { | ||
border-radius: 4px; | ||
box-shadow: 0 0 0 1px #05f, 0 2px 1px rgba(0, 0, 0, 0.15); | ||
font-size: 14px; | ||
font-weight: 500; | ||
height: 40px; | ||
line-height: 22px; | ||
margin: 20px 0 12px; | ||
width: 100%; | ||
} | ||
} | ||
</style> |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.