【优化】登录页代码逻辑、样式优化

pull/60/head
xlzy 2022-11-23 23:33:24 +08:00
parent 0c91118e09
commit 0511e9f877
5 changed files with 258 additions and 437 deletions

View File

@ -8,7 +8,7 @@
<h2>三方登录</h2> <h2>三方登录</h2>
</div> </div>
<a-spin tip="正在登录中..."> <a-spin tip="正在登录中...">
<div style="height: 300px"> <div class="h-[300px]">
<a-skeleton /> <a-skeleton />
</div> </div>
</a-spin> </a-spin>
@ -20,7 +20,6 @@
<script setup name="loginCallback"> <script setup name="loginCallback">
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { nextTick } from 'vue'
import tool from '@/utils/tool' import tool from '@/utils/tool'
import router from '@/router' import router from '@/router'
import thirdApi from '@/api/auth/thirdApi' import thirdApi from '@/api/auth/thirdApi'
@ -31,24 +30,21 @@
onMounted(() => { onMounted(() => {
// url // url
const url = window.location.href const url = new URL(window.location.href)
let parameter = url.split('?')[1] let argLength = 0
if (!parameter) { const params = {}
// 访 url.searchParams.forEach((value, key) => {
window.location.href = '/login' argLength += 1
} params[key] = value
const parameterArray = parameter.split('&') })
// //
if (!parameterArray) { if (argLength < 2) {
window.location.href = '/login' window.location.href = '/login'
return
} }
const parameterObject = {}
// json
for (let i = 0; i < parameterArray.length; i++) {
parameterObject[parameterArray[i].split('=')[0]] = parameterArray[i].split('=')[1]
}
thirdApi thirdApi
.thirdCallback(parameterObject) .thirdCallback(params)
.then((data) => { .then((data) => {
tool.data.set('TOKEN', data) tool.data.set('TOKEN', data)
// //
@ -64,11 +60,9 @@
path: indexMenu path: indexMenu
}) })
message.success('登录成功') message.success('登录成功')
nextTick(() => { dictApi.dictTree().then((dictData) => {
dictApi.dictTree().then((dictData) => { // store
// store tool.data.set('DICT_TYPE_TREE_DATA', dictData)
tool.data.set('DICT_TYPE_TREE_DATA', dictData)
})
}) })
}) })
}) })
@ -79,155 +73,5 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.login_background { @import 'login';
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
/* Safari and Chrome: */
-webkit-animation-name: myfirst;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-delay: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
-webkit-animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}
</style> </style>

View File

@ -0,0 +1,152 @@
.login-icon-gray {
color: rgba(0, 0, 0, 0.25);
}
.login-validCode-img {
border: 1px solid var(--border-color-split);
cursor: pointer;
width: 100%;
height: 40px;
}
.login_background {
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}

View File

@ -33,9 +33,14 @@
<a-tab-pane key="userAccount" :tab="$t('login.accountPassword')"> <a-tab-pane key="userAccount" :tab="$t('login.accountPassword')">
<a-form ref="loginForm" :model="ruleForm" :rules="rules"> <a-form ref="loginForm" :model="ruleForm" :rules="rules">
<a-form-item name="account"> <a-form-item name="account">
<a-input v-model:value="ruleForm.account" :placeholder="$t('login.accountPlaceholder')" size="large"> <a-input
v-model:value="ruleForm.account"
:placeholder="$t('login.accountPlaceholder')"
size="large"
@keyup.enter="login"
>
<template #prefix> <template #prefix>
<UserOutlined style="color: rgba(0, 0, 0, 0.25)" /> <UserOutlined class="login-icon-gray" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -45,13 +50,14 @@
:placeholder="$t('login.PWPlaceholder')" :placeholder="$t('login.PWPlaceholder')"
size="large" size="large"
autocomplete="off" autocomplete="off"
@keyup.enter="login"
> >
<template #prefix> <template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)" /> <LockOutlined class="login-icon-gray" />
</template> </template>
</a-input-password> </a-input-password>
</a-form-item> </a-form-item>
<a-form-item name="validCode" v-if="sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true'"> <a-form-item name="validCode" v-if="captchaOpen">
<a-row :gutter="8"> <a-row :gutter="8">
<a-col :span="17"> <a-col :span="17">
<a-input <a-input
@ -60,16 +66,12 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" /> <verified-outlined class="login-icon-gray" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<img <img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
:src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px"
@click="loginCaptcha"
/>
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
@ -78,7 +80,7 @@
<a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}</a> <a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}</a>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="login" <a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
>{{ $t('login.signIn') }} >{{ $t('login.signIn') }}
</a-button> </a-button>
</a-form-item> </a-form-item>
@ -102,12 +104,15 @@
import phoneLoginForm from './phoneLoginForm.vue' import phoneLoginForm from './phoneLoginForm.vue'
import threeLogin from './threeLogin.vue' import threeLogin from './threeLogin.vue'
import smCrypto from '@/utils/smCrypto' import smCrypto from '@/utils/smCrypto'
import { required } from '@/utils/formRules'
export default { export default {
name: 'Login',
components: { components: {
phoneLoginForm, phoneLoginForm,
threeLogin threeLogin
}, },
data() { data() {
return { return {
activeKey: 'userAccount', activeKey: 'userAccount',
@ -121,10 +126,10 @@
autologin: false autologin: false
}, },
rules: { rules: {
account: [{ required: true, message: this.$t('login.accountError'), trigger: 'blur' }], account: [required(this.$t('login.accountError'), 'blur')],
password: [{ required: true, message: this.$t('login.PWError'), trigger: 'blur' }] password: [required(this.$t('login.PWError'), 'blur')]
}, },
islogin: false, loading: false,
config: { config: {
lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG, lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG,
theme: this.$TOOL.data.get('APP_THEME') || 'default' theme: this.$TOOL.data.get('APP_THEME') || 'default'
@ -142,8 +147,8 @@
} }
}, },
computed: { computed: {
sysBaseConfigWatch() { captchaOpen() {
return this.$store.state.global.sysBaseConfig return this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true'
} }
}, },
watch: { watch: {
@ -153,10 +158,6 @@
'config.lang': function (val) { 'config.lang': function (val) {
this.$i18n.locale = val this.$i18n.locale = val
this.$TOOL.data.set('APP_LANG', val) this.$TOOL.data.set('APP_LANG', val)
},
sysBaseConfigWatch(val) {
this.sysBaseConfig = val
this.refreshSwitch()
} }
}, },
created() { created() {
@ -166,27 +167,16 @@
}, },
mounted() { mounted() {
this.refreshSwitch() this.refreshSwitch()
//
document.onkeydown = (e) => {
if (e.defaultPrevented) {
return;
}
const body = document.getElementsByTagName('body')[0];
// match(httpshttpwww)
if (e.keyCode === 13 && e.target.baseURI.match("/login") && e.target === body) {
this.login()
}
}
}, },
methods: { methods: {
// //
refreshSwitch() { refreshSwitch() {
// //
if (this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true') { if (this.captchaOpen) {
// //
this.loginCaptcha() this.loginCaptcha()
// //
this.rules.validCode = [{ required: true, message: this.$t('login.validError'), trigger: 'blur' }] this.rules.validCode = [required(this.$t('login.validError'), 'blur')]
} }
}, },
// //
@ -198,45 +188,40 @@
}, },
// //
async login() { async login() {
const validate = await this.$refs.loginForm.validate().catch(() => {}) this.$refs.loginForm.validate().then(async () => {
if (!validate) return false this.loading = true
const loginData = {
account: this.ruleForm.account,
// SM2使hash
password: smCrypto.doSm2Encrypt(this.ruleForm.password),
validCode: this.ruleForm.validCode,
validCodeReqNo: this.ruleForm.validCodeReqNo
}
// token
try {
const loginToken = await loginApi.login(loginData)
this.$TOOL.data.set('TOKEN', loginToken)
//
const loginUser = await loginApi.getLoginUser()
this.$TOOL.data.set('USER_INFO', loginUser)
this.islogin = true //
const loginData = { const menu = await userCenterApi.userLoginMenu()
account: this.ruleForm.account, const indexMenu = menu[0].children[0].path
// SM2使hash this.$TOOL.data.set('MENU', menu)
password: smCrypto.doSm2Encrypt(this.ruleForm.password), //
validCode: this.ruleForm.validCode, this.$TOOL.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
validCodeReqNo: this.ruleForm.validCodeReqNo this.$message.success('登录成功')
} this.$router.replace({
// token path: indexMenu
const login = await loginApi.login(loginData).finally(() => { })
this.islogin = false dictApi.dictTree().then((data) => {
}) // store
this.$TOOL.data.set('TOKEN', login) this.$TOOL.data.set('DICT_TYPE_TREE_DATA', data)
// })
const loginUser = await loginApi.getLoginUser() } catch (err) {
this.$TOOL.data.set('USER_INFO', loginUser) this.loading = false
}
//
const menu = await userCenterApi.userLoginMenu().catch(() => {
this.islogin = false
return
})
this.islogin = false
const indexMenu = menu[0].children[0].path
this.$TOOL.data.set('MENU', menu)
//
this.$TOOL.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
this.$router.replace({
path: indexMenu
})
this.$message.success('登录成功')
this.$nextTick(() => {
dictApi.dictTree().then((data) => {
// store
this.$TOOL.data.set('DICT_TYPE_TREE_DATA', data)
})
}) })
}, },
configLang(key) { configLang(key) {
@ -246,156 +231,6 @@
} }
</script> </script>
<style lang="less" scoped> <style lang="less">
.login_background { @import 'login';
width: 100%;
height: 100%;
overflow: hidden;
background-size: cover;
background-position: center;
background-image: url(/img/login_background.png);
}
.login_background_front {
width: 450px;
height: 450px;
margin-left: 100px;
margin-top: 15%;
overflow: hidden;
/*position: relative;*/
background-size: cover;
background-position: center;
background-image: url(/img/login_background_front.png);
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
/* Safari and Chrome: */
-webkit-animation-name: myfirst;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-delay: 1s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
-webkit-animation-play-state: running;
}
@keyframes myfirst {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
@-webkit-keyframes myfirst /* Safari and Chrome */ {
0% {
left: 0px;
top: 0px;
}
50% {
left: 50px;
top: 0px;
}
100% {
left: 0px;
top: 0px;
}
}
.login_adv__title h2 {
font-size: 40px;
}
.login_adv__title h4 {
font-size: 18px;
margin-top: 10px;
font-weight: normal;
}
.login_adv__title p {
font-size: 14px;
margin-top: 10px;
line-height: 1.8;
color: rgba(255, 255, 255, 0.6);
}
.login_adv__title div {
margin-top: 10px;
display: flex;
align-items: center;
}
.login_adv__title div span {
margin-right: 15px;
}
.login_adv__title div i {
font-size: 40px;
}
.login_adv__title div i.add {
font-size: 20px;
color: rgba(255, 255, 255, 0.6);
}
/*background-image:linear-gradient(transparent, #000);*/
.login_main {
flex: 1;
overflow: auto;
display: flex;
}
.login-form {
top: 15%;
right: 15%;
position: absolute;
width: 450px;
margin-left: 10%;
margin-top: 20px;
padding: 10px 0;
}
.login-header {
margin-bottom: 20px;
}
.login-header .logo {
display: flex;
align-items: center;
}
.login-header .logo img {
width: 35px;
height: 35px;
vertical-align: bottom;
margin-right: 10px;
}
.login-header .logo label {
font-size: 24px;
}
.login-header h2 {
font-size: 24px;
font-weight: bold;
margin-top: 40px;
}
.login_config {
position: absolute;
top: 20px;
right: 20px;
}
@media (max-width: 1200px) {
.login-form {
width: 340px;
}
}
@media (max-width: 1000px) {
.login_main {
display: block;
}
.login_background_front {
display: none;
}
.login-form {
width: 100%;
padding: 20px 40px;
right: 0 !important;
top: 0 !important;
}
}
</style> </style>

View File

@ -3,7 +3,7 @@
<a-form-item name="phone"> <a-form-item name="phone">
<a-input v-model:value="phoneFormData.phone" :placeholder="$t('login.phonePlaceholder')" size="large"> <a-input v-model:value="phoneFormData.phone" :placeholder="$t('login.phonePlaceholder')" size="large">
<template #prefix> <template #prefix>
<mobile-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mobile-outlined class="text-black text-opacity-25" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -16,21 +16,21 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<mail-outlined style="color: rgba(0, 0, 0, 0.25)" /> <mail-outlined class="text-black text-opacity-25" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
<a-col :span="7"> <a-col :span="7">
<a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn">{{ <a-button size="large" style="width: 100%" @click="getPhoneValidCode" :disabled="state.smsSendBtn">
(!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' {{ (!state.smsSendBtn && $t('login.getSmsCode')) || state.time + ' s' }}
}}</a-button> </a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" style="width: 100%" :loading="islogin" round size="large" @click="submitLogin">{{ <a-button type="primary" style="width: 100%" :loading="loading" round size="large" @click="submitLogin">
$t('login.signIn') {{ $t('login.signIn') }}
}}</a-button> </a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-modal <a-modal
@ -50,7 +50,7 @@
size="large" size="large"
> >
<template #prefix> <template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" /> <verified-outlined class="text-black text-opacity-25" />
</template> </template>
</a-input> </a-input>
</a-col> </a-col>
@ -78,7 +78,7 @@
import dictApi from '@/api/dev/dictApi' import dictApi from '@/api/dev/dictApi'
const phoneLoginFormRef = ref() const phoneLoginFormRef = ref()
const phoneFormData = ref({}) const phoneFormData = ref({})
const islogin = ref(false) const loading = ref(false)
let state = ref({ let state = ref({
time: 60, time: 60,
smsSendBtn: false smsSendBtn: false
@ -109,36 +109,31 @@
// delete phoneFormData.value.phoneValidCode // delete phoneFormData.value.phoneValidCode
phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value phoneFormData.value.validCodeReqNo = phoneValidCodeReqNo.value
islogin.value = true loading.value = true
const token = await loginApi.loginByPhone(phoneFormData.value).finally(() => { try {
islogin.value = false const token = await loginApi.loginByPhone(phoneFormData.value)
}) tool.data.set('TOKEN', token)
//
const loginUser = await loginApi.getLoginUser()
tool.data.set('USER_INFO', loginUser)
tool.data.set('TOKEN', token) //
// const menu = await userCenterApi.userLoginMenu()
const loginUser = await loginApi.getLoginUser() const indexMenu = menu[0].children[0].path
tool.data.set('USER_INFO', loginUser) tool.data.set('MENU', menu)
//
// tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
const menu = await userCenterApi.userLoginMenu().catch(() => { message.success('登录成功')
islogin.value = false router.replace({
return path: indexMenu
}) })
islogin.value = false
const indexMenu = menu[0].children[0].path
tool.data.set('MENU', menu)
//
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
router.replace({
path: indexMenu
})
message.success('登录成功')
nextTick(() => {
dictApi.dictTree().then((data) => { dictApi.dictTree().then((data) => {
// store // store
tool.data.set('DICT_TYPE_TREE_DATA', data) tool.data.set('DICT_TYPE_TREE_DATA', data)
}) })
}) } catch (err) {
loading.value = false
}
} }
// //

View File

@ -1,6 +1,6 @@
<template> <template>
<a-divider>{{ $t('login.signInOther') }}</a-divider> <a-divider>{{ $t('login.signInOther') }}</a-divider>
<div class="login-oauth"> <div class="login-oauth layout-center">
<a-space align="start"> <a-space align="start">
<a @click="getLoginRenderUrl('gitee')"><GiteeIcon /></a> <a @click="getLoginRenderUrl('gitee')"><GiteeIcon /></a>
<a-button type="primary" shape="circle"> <a-button type="primary" shape="circle">
@ -23,9 +23,4 @@
} }
</script> </script>
<style scoped> <style scoped></style>
.login-oauth {
display: flex;
justify-content: center;
}
</style>