296 lines
7.8 KiB
Vue
296 lines
7.8 KiB
Vue
<template>
|
|
<div class="lock-wrapper" @click.stop>
|
|
<div class="lock-center">
|
|
<img class="logo" :src="userData.portrait" />
|
|
<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="请输入密码"></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>
|
|
<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>
|
|
<div class="date">{{ currentTime.date }}</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import dayjs from 'utils/day'
|
|
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'
|
|
import { ArrowRightOutlined, LeftOutlined } from '@ant-design/icons-vue'
|
|
|
|
export default defineComponent({
|
|
components: { ArrowRightOutlined, LeftOutlined },
|
|
setup() {
|
|
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: ''
|
|
})
|
|
function setTimer() {
|
|
const getTime = () => {
|
|
const time = dayjs()
|
|
currentTime.value = {
|
|
time: time.format('HH:mm:ss'),
|
|
date: `${time.format('MM月DD日')}, ${time.format('dddd')}`
|
|
}
|
|
}
|
|
getTime()
|
|
timer = setInterval(() => {
|
|
getTime()
|
|
}, 1000)
|
|
}
|
|
let lockData = {
|
|
isLock: false,
|
|
path: ''
|
|
}
|
|
onMounted(() => {
|
|
const lockDataItem = localStorage.getItem('lockData')
|
|
if (lockDataItem) lockData = JSON.parse(lockDataItem)
|
|
// 处理通过路由进入锁屏
|
|
localStorage.setItem(
|
|
'lockData',
|
|
JSON.stringify({
|
|
...lockData,
|
|
isLock: true
|
|
})
|
|
)
|
|
setTimer()
|
|
})
|
|
onUnmounted(() => {
|
|
clearInterval(timer)
|
|
})
|
|
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() {
|
|
try {
|
|
const values = await loginFormRef.value.validate()
|
|
state.loading = true
|
|
const res = await login({
|
|
account: userData.value.account,
|
|
password: encrypt(values.password),
|
|
isManager: true,
|
|
code: values.verify
|
|
})
|
|
if (res.success) {
|
|
setLoginData(res.data)
|
|
router.replace(lockData.path)
|
|
store.commit('SET_OPERATETIME')
|
|
localStorage.setItem(
|
|
'lockData',
|
|
JSON.stringify({
|
|
...lockData,
|
|
isLock: false
|
|
})
|
|
)
|
|
}
|
|
} catch (error) {
|
|
console.log(error)
|
|
}
|
|
state.loading = false
|
|
}
|
|
return {
|
|
...toRefs(state),
|
|
currentTime,
|
|
userData,
|
|
loginFormRef,
|
|
required,
|
|
switchUser,
|
|
handleLogin,
|
|
getVertify,
|
|
startCountdown,
|
|
resetCountdown
|
|
}
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.lock-wrapper {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: url('/web-common-resource/img/lock_wrapper.jpg') #1c2b36 no-repeat;
|
|
background-size: 100%;
|
|
.lock-center {
|
|
position: absolute;
|
|
text-align: center;
|
|
top: 40%;
|
|
left: 50%;
|
|
width: 350px;
|
|
margin: -150px 0 0 -150px;
|
|
.logo {
|
|
display: inline-block;
|
|
width: 160px;
|
|
height: 160px;
|
|
border-radius: 50%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
overflow: hidden;
|
|
}
|
|
.account {
|
|
font-size: 45px;
|
|
font-weight: 500;
|
|
color: #fff;
|
|
margin: 15px 0 25px 0;
|
|
}
|
|
.button-group {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-top: 20px;
|
|
}
|
|
.login-btn {
|
|
background: #1890ff;
|
|
border: none;
|
|
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;
|
|
left: 30px;
|
|
bottom: 60px;
|
|
color: #fff;
|
|
.time {
|
|
font-size: 80px;
|
|
}
|
|
.date {
|
|
font-size: 50px;
|
|
}
|
|
}
|
|
.switch-button {
|
|
font-size: 14px;
|
|
color: #fff;
|
|
}
|
|
}
|
|
</style>
|