diff --git a/src/services/index.js b/src/services/index.js index 65d9069..a15deb8 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -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)) +} diff --git a/src/views/login/lockme.vue b/src/views/login/lockme.vue index 9d3ee76..b4419f0 100644 --- a/src/views/login/lockme.vue +++ b/src/views/login/lockme.vue @@ -5,23 +5,29 @@

{{ userData.name }}

- - - + + + + + + {{ isCountingDown ? `${countdown}s后重新获取` : '获取验证码' }} + - - - 切换账户 - +
+ + + 切换账户 + + + + 登录 + +
{{ currentTime.time }}
@@ -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 } - }, + } }) @@ -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; diff --git a/src/views/login/login.vue b/src/views/login/login.vue index 24d9d2e..c39b8e8 100644 --- a/src/views/login/login.vue +++ b/src/views/login/login.vue @@ -26,6 +26,17 @@ + + + + + + + {{ isCountingDown ? `${countdown}s后重新获取` : '获取验证码' }} + +
@@ -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 } - }, + } } @@ -225,6 +293,14 @@ export default { } } } + + // 倒计时按钮样式 + .ant-btn:disabled { + background-color: #f5f5f5; + border-color: #d9d9d9; + color: #999; + cursor: not-allowed; + } } } .copyright-info { diff --git a/vite.config.ts b/vite.config.ts index 223d3b6..816bbbd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -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({