fix: 登录、锁屏加验证码
parent
0f9f99063e
commit
96dd695a72
|
@ -76,3 +76,6 @@ export function updateSystemConfigs(params) {
|
|||
export function testLinkApi(category) {
|
||||
return request.get('/sms/v1/configs/test', { params: { category } })
|
||||
}
|
||||
export function getVertifyCode(params) {
|
||||
return request.post('/sms/v1/users/code', wrapperParams(params))
|
||||
}
|
||||
|
|
|
@ -5,23 +5,29 @@
|
|||
<p class="account">{{ userData.name }}</p>
|
||||
<a-form :model="loginForm" ref="loginFormRef" @keyup.enter.prevent="handleLogin" @submit.prevent>
|
||||
<a-form-item name="password" :rules="[{ ...required, message: '请输入密码' }]">
|
||||
<a-input-password v-model:value="loginForm.password" placeholder="请输入密码">
|
||||
<template #addonAfter>
|
||||
<a-button class="text-white login-btn" @click="handleLogin()" :loading="loading">
|
||||
<template #icon>
|
||||
<ArrowRightOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input-password>
|
||||
<a-input-password v-model:value="loginForm.password" placeholder="请输入密码"></a-input-password>
|
||||
</a-form-item>
|
||||
<a-form-item name="verify" :rules="[{ ...required, message: '请输入验证码' }]">
|
||||
<a-input v-model:value="loginForm.verify" placeholder="请输入验证码" style="width: 65%; vertical-align: middle"></a-input>
|
||||
<a-button style="height: 32px; width: 33%; margin-left: 2%" @click="getVertify" :loading="verifyLoading" :disabled="isCountingDown">
|
||||
{{ isCountingDown ? `${countdown}s后重新获取` : '获取验证码' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button class="switch-button" type="text" @click="switchUser()">
|
||||
<template #icon>
|
||||
<LeftOutlined />
|
||||
</template>
|
||||
切换账户
|
||||
</a-button>
|
||||
<div class="button-group">
|
||||
<a-button class="switch-button" type="text" @click="switchUser()">
|
||||
<template #icon>
|
||||
<LeftOutlined />
|
||||
</template>
|
||||
切换账户
|
||||
</a-button>
|
||||
<a-button class="login-btn" type="primary" @click="handleLogin()" :loading="loading">
|
||||
<template #icon>
|
||||
<ArrowRightOutlined />
|
||||
</template>
|
||||
登录
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="date-time">
|
||||
<div class="time">{{ currentTime.time }}</div>
|
||||
|
@ -36,6 +42,7 @@ import { encrypt } from 'utils/crypto'
|
|||
import { useStore } from 'vuex'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { login } from 'services'
|
||||
import { getVertifyCode } from '@/services'
|
||||
import { computed, defineComponent, onMounted, onUnmounted, reactive, ref, toRefs } from 'vue'
|
||||
import setLoginData from './tools'
|
||||
import { required } from '@/validate'
|
||||
|
@ -47,23 +54,52 @@ export default defineComponent({
|
|||
const state = reactive({
|
||||
loginForm: {
|
||||
password: '',
|
||||
verify: ''
|
||||
},
|
||||
loading: false,
|
||||
verifyLoading: false,
|
||||
countdown: 0,
|
||||
isCountingDown: false
|
||||
})
|
||||
let timer: any = 0
|
||||
let countdownTimer: any = null
|
||||
const store = useStore()
|
||||
const userData = computed(() => store.getters.userData || {})
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
state.countdown = 60
|
||||
state.isCountingDown = true
|
||||
countdownTimer = setInterval(() => {
|
||||
state.countdown--
|
||||
if (state.countdown <= 0) {
|
||||
clearInterval(countdownTimer)
|
||||
state.isCountingDown = false
|
||||
state.countdown = 0
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重置倒计时
|
||||
const resetCountdown = () => {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
state.isCountingDown = false
|
||||
state.countdown = 0
|
||||
}
|
||||
// 当前时间设置
|
||||
const currentTime = ref({
|
||||
time: '',
|
||||
date: '',
|
||||
date: ''
|
||||
})
|
||||
function setTimer() {
|
||||
const getTime = () => {
|
||||
const time = dayjs()
|
||||
currentTime.value = {
|
||||
time: time.format('HH:mm:ss'),
|
||||
date: `${time.format('MM月DD日')}, ${time.format('dddd')}`,
|
||||
date: `${time.format('MM月DD日')}, ${time.format('dddd')}`
|
||||
}
|
||||
}
|
||||
getTime()
|
||||
|
@ -73,7 +109,7 @@ export default defineComponent({
|
|||
}
|
||||
let lockData = {
|
||||
isLock: false,
|
||||
path: '',
|
||||
path: ''
|
||||
}
|
||||
onMounted(() => {
|
||||
const lockDataItem = localStorage.getItem('lockData')
|
||||
|
@ -83,7 +119,7 @@ export default defineComponent({
|
|||
'lockData',
|
||||
JSON.stringify({
|
||||
...lockData,
|
||||
isLock: true,
|
||||
isLock: true
|
||||
})
|
||||
)
|
||||
setTimer()
|
||||
|
@ -94,6 +130,26 @@ export default defineComponent({
|
|||
function switchUser() {
|
||||
store.dispatch('permission/ResetRoutes')
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
const getVertify = () => {
|
||||
if (state.isCountingDown) return // 如果正在倒计时,不允许重复点击
|
||||
if (!userData.value.account) {
|
||||
return // 如果没有用户账号,直接返回
|
||||
}
|
||||
|
||||
state.verifyLoading = true
|
||||
getVertifyCode({ account: userData.value.account })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
state.verifyLoading = false
|
||||
startCountdown() // 开始倒计时
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.verifyLoading = false
|
||||
})
|
||||
}
|
||||
const loginFormRef = ref()
|
||||
const router = useRouter()
|
||||
async function handleLogin() {
|
||||
|
@ -104,6 +160,7 @@ export default defineComponent({
|
|||
account: userData.value.account,
|
||||
password: encrypt(values.password),
|
||||
isManager: true,
|
||||
code: values.verify
|
||||
})
|
||||
if (res.success) {
|
||||
setLoginData(res.data)
|
||||
|
@ -113,7 +170,7 @@ export default defineComponent({
|
|||
'lockData',
|
||||
JSON.stringify({
|
||||
...lockData,
|
||||
isLock: false,
|
||||
isLock: false
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -130,8 +187,11 @@ export default defineComponent({
|
|||
required,
|
||||
switchUser,
|
||||
handleLogin,
|
||||
getVertify,
|
||||
startCountdown,
|
||||
resetCountdown
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -149,7 +209,7 @@ export default defineComponent({
|
|||
text-align: center;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
width: 350px;
|
||||
margin: -150px 0 0 -150px;
|
||||
.logo {
|
||||
display: inline-block;
|
||||
|
@ -165,15 +225,55 @@ export default defineComponent({
|
|||
color: #fff;
|
||||
margin: 15px 0 25px 0;
|
||||
}
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.login-btn {
|
||||
background: #6b7485;
|
||||
background: #1890ff;
|
||||
border: none;
|
||||
width: 48px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.login-btn:hover {
|
||||
background: #40a9ff;
|
||||
}
|
||||
::v-deep(.ant-input-group-addon) {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
::v-deep(.ant-input) {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
::v-deep(.ant-input-password) {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
::v-deep(.ant-input::placeholder) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
::v-deep(.ant-input-password .ant-input) {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #fff;
|
||||
}
|
||||
::v-deep(.ant-input-password .ant-input::placeholder) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
::v-deep(.ant-btn) {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
::v-deep(.ant-btn:disabled) {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
.date-time {
|
||||
position: absolute;
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
</a-input-password>
|
||||
</a-form-item>
|
||||
</a-tooltip>
|
||||
<a-form-item class="login-form-item" name="verify" :rules="[{ ...required, message: '请输入验证码' }]">
|
||||
<a-input placeholder="请输入验证码" autocomplete="off" v-model:value="loginForm.verify" style="width: 67%; vertical-align: middle">
|
||||
<template #prefix>
|
||||
<LockOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<div class="login-code" v-if="identifyCode"></div>
|
||||
<a-button v-else style="height: 60px; width: 31%; margin-left: 2%" @click="getVertify" :loading="verifyLoading" :disabled="isCountingDown || !loginForm.account.trim()">
|
||||
{{ isCountingDown ? `${countdown}s后重新获取` : '获取验证码' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item class="login-form-item">
|
||||
<div class="operate-region">
|
||||
<span class="remember">
|
||||
|
@ -51,6 +62,7 @@ import { useStore } from 'vuex'
|
|||
import { useRouter, useRoute } from 'vue-router'
|
||||
import setLoginData from './tools'
|
||||
import { required } from '@/validate'
|
||||
import { getVertifyCode } from '@/services'
|
||||
|
||||
export default {
|
||||
components: { UserOutlined, LockOutlined },
|
||||
|
@ -59,14 +71,43 @@ export default {
|
|||
remember: false,
|
||||
loginForm: {
|
||||
account: '',
|
||||
password: '',
|
||||
password: ''
|
||||
},
|
||||
loading: false,
|
||||
capsTooltip: false,
|
||||
verifyLoading: false,
|
||||
countdown: 0,
|
||||
isCountingDown: false
|
||||
})
|
||||
|
||||
const store = useStore()
|
||||
const configs = computed(() => store.getters.pageConfig)
|
||||
const loginFormRef = ref(null)
|
||||
let countdownTimer = null
|
||||
|
||||
// 开始倒计时
|
||||
const startCountdown = () => {
|
||||
state.countdown = 60
|
||||
state.isCountingDown = true
|
||||
countdownTimer = setInterval(() => {
|
||||
state.countdown--
|
||||
if (state.countdown <= 0) {
|
||||
clearInterval(countdownTimer)
|
||||
state.isCountingDown = false
|
||||
state.countdown = 0
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重置倒计时
|
||||
const resetCountdown = () => {
|
||||
if (countdownTimer) {
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
}
|
||||
state.isCountingDown = false
|
||||
state.countdown = 0
|
||||
}
|
||||
const init = () => {
|
||||
const local = localStorage.getItem('cmcLoginData')
|
||||
if (local) {
|
||||
|
@ -79,12 +120,33 @@ export default {
|
|||
init()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const getVertify = () => {
|
||||
if (state.isCountingDown) return // 如果正在倒计时,不允许重复点击
|
||||
if (!state.loginForm.account.trim()) {
|
||||
// 可以在这里添加提示信息,比如使用 message 组件
|
||||
return // 如果没有输入用户名,直接返回
|
||||
}
|
||||
|
||||
state.verifyLoading = true
|
||||
getVertifyCode({ account: state.loginForm.account })
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
state.verifyLoading = false
|
||||
state.hasVertify = res.data
|
||||
state.identifyCode = res.data
|
||||
startCountdown() // 开始倒计时
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.verifyLoading = false
|
||||
})
|
||||
}
|
||||
function goLogin(data) {
|
||||
setLoginData(data)
|
||||
if (state.remember) {
|
||||
const obj = {
|
||||
account: state.loginForm.account,
|
||||
password: encrypt(state.loginForm.password),
|
||||
password: encrypt(state.loginForm.password)
|
||||
}
|
||||
localStorage.setItem('cmcLoginData', JSON.stringify(obj))
|
||||
} else {
|
||||
|
@ -100,16 +162,19 @@ export default {
|
|||
try {
|
||||
state.loading = true
|
||||
const values = await loginFormRef.value.validate()
|
||||
const { account, password } = values
|
||||
const { account, password, verify } = values
|
||||
const res = await login({
|
||||
account,
|
||||
password: encrypt(password),
|
||||
isManager: true,
|
||||
code: verify
|
||||
})
|
||||
if (res.success) {
|
||||
goLogin(res.data)
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
}
|
||||
state.loading = false
|
||||
}
|
||||
|
||||
|
@ -132,8 +197,11 @@ export default {
|
|||
loginFormRef,
|
||||
handleLogin,
|
||||
checkCapslock,
|
||||
getVertify,
|
||||
startCountdown,
|
||||
resetCountdown
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -225,6 +293,14 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 倒计时按钮样式
|
||||
.ant-btn:disabled {
|
||||
background-color: #f5f5f5;
|
||||
border-color: #d9d9d9;
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
.copyright-info {
|
||||
|
|
|
@ -12,7 +12,7 @@ function resolve(dir: string) {
|
|||
}
|
||||
|
||||
const httpType = 'https://'
|
||||
const proxyUrl = '10.10.33.172:60006' // EFC 3.0 代理地址设置
|
||||
const proxyUrl = '10.10.33.173:60006' // 中车代理地址
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
|
|
Loading…
Reference in New Issue