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

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>
</div>
<a-spin tip="正在登录中...">
<div style="height: 300px">
<div class="h-[300px]">
<a-skeleton />
</div>
</a-spin>
@ -20,7 +20,6 @@
<script setup name="loginCallback">
import { message } from 'ant-design-vue'
import { nextTick } from 'vue'
import tool from '@/utils/tool'
import router from '@/router'
import thirdApi from '@/api/auth/thirdApi'
@ -31,24 +30,21 @@
onMounted(() => {
// url
const url = window.location.href
let parameter = url.split('?')[1]
if (!parameter) {
// 访
window.location.href = '/login'
}
const parameterArray = parameter.split('&')
const url = new URL(window.location.href)
let argLength = 0
const params = {}
url.searchParams.forEach((value, key) => {
argLength += 1
params[key] = value
})
//
if (!parameterArray) {
if (argLength < 2) {
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
.thirdCallback(parameterObject)
.thirdCallback(params)
.then((data) => {
tool.data.set('TOKEN', data)
//
@ -64,11 +60,9 @@
path: indexMenu
})
message.success('登录成功')
nextTick(() => {
dictApi.dictTree().then((dictData) => {
// store
tool.data.set('DICT_TYPE_TREE_DATA', dictData)
})
dictApi.dictTree().then((dictData) => {
// store
tool.data.set('DICT_TYPE_TREE_DATA', dictData)
})
})
})
@ -79,155 +73,5 @@
</script>
<style lang="less" scoped>
.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;
/* 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;
}
}
@import 'login';
</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-form ref="loginForm" :model="ruleForm" :rules="rules">
<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>
<UserOutlined style="color: rgba(0, 0, 0, 0.25)" />
<UserOutlined class="login-icon-gray" />
</template>
</a-input>
</a-form-item>
@ -45,13 +50,14 @@
:placeholder="$t('login.PWPlaceholder')"
size="large"
autocomplete="off"
@keyup.enter="login"
>
<template #prefix>
<LockOutlined style="color: rgba(0, 0, 0, 0.25)" />
<LockOutlined class="login-icon-gray" />
</template>
</a-input-password>
</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-col :span="17">
<a-input
@ -60,16 +66,12 @@
size="large"
>
<template #prefix>
<verified-outlined style="color: rgba(0, 0, 0, 0.25)" />
<verified-outlined class="login-icon-gray" />
</template>
</a-input>
</a-col>
<a-col :span="7">
<img
:src="validCodeBase64"
style="border: 1px solid var(--border-color-split); cursor: pointer; width: 100%; height: 40px"
@click="loginCaptcha"
/>
<img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
</a-col>
</a-row>
</a-form-item>
@ -78,7 +80,7 @@
<a href="/findpwd" style="color: #0d84ff">{{ $t('login.forgetPassword') }}</a>
</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') }}
</a-button>
</a-form-item>
@ -102,12 +104,15 @@
import phoneLoginForm from './phoneLoginForm.vue'
import threeLogin from './threeLogin.vue'
import smCrypto from '@/utils/smCrypto'
import { required } from '@/utils/formRules'
export default {
name: 'Login',
components: {
phoneLoginForm,
threeLogin
},
data() {
return {
activeKey: 'userAccount',
@ -121,10 +126,10 @@
autologin: false
},
rules: {
account: [{ required: true, message: this.$t('login.accountError'), trigger: 'blur' }],
password: [{ required: true, message: this.$t('login.PWError'), trigger: 'blur' }]
account: [required(this.$t('login.accountError'), 'blur')],
password: [required(this.$t('login.PWError'), 'blur')]
},
islogin: false,
loading: false,
config: {
lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG,
theme: this.$TOOL.data.get('APP_THEME') || 'default'
@ -142,8 +147,8 @@
}
},
computed: {
sysBaseConfigWatch() {
return this.$store.state.global.sysBaseConfig
captchaOpen() {
return this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true'
}
},
watch: {
@ -153,10 +158,6 @@
'config.lang': function (val) {
this.$i18n.locale = val
this.$TOOL.data.set('APP_LANG', val)
},
sysBaseConfigWatch(val) {
this.sysBaseConfig = val
this.refreshSwitch()
}
},
created() {
@ -166,27 +167,16 @@
},
mounted() {
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: {
//
refreshSwitch() {
//
if (this.sysBaseConfig.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN === 'true') {
if (this.captchaOpen) {
//
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() {
const validate = await this.$refs.loginForm.validate().catch(() => {})
if (!validate) return false
this.$refs.loginForm.validate().then(async () => {
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 = {
account: this.ruleForm.account,
// SM2使hash
password: smCrypto.doSm2Encrypt(this.ruleForm.password),
validCode: this.ruleForm.validCode,
validCodeReqNo: this.ruleForm.validCodeReqNo
}
// token
const login = await loginApi.login(loginData).finally(() => {
this.islogin = false
})
this.$TOOL.data.set('TOKEN', login)
//
const loginUser = await loginApi.getLoginUser()
this.$TOOL.data.set('USER_INFO', loginUser)
//
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)
})
//
const menu = await userCenterApi.userLoginMenu()
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.$message.success('登录成功')
this.$router.replace({
path: indexMenu
})
dictApi.dictTree().then((data) => {
// store
this.$TOOL.data.set('DICT_TYPE_TREE_DATA', data)
})
} catch (err) {
this.loading = false
}
})
},
configLang(key) {
@ -246,156 +231,6 @@
}
</script>
<style lang="less" scoped>
.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;
/* 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 lang="less">
@import 'login';
</style>

View File

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

View File

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