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