Browse Source

验证码逻辑

milestone-20260128-日常优化1.0
ZhangYong 1 month ago
parent
commit
75c3b4da8a
  1. 2
      src/components/locales/lang/en.js
  2. 2
      src/components/locales/lang/zh-CN.js
  3. 5
      src/util/http.js
  4. 100
      src/views/login.vue

2
src/components/locales/lang/en.js

@ -185,6 +185,8 @@ export default {
// Message Group // Message Group
elmessage: { elmessage: {
// Common // Common
accountEmpty: "Account cannot be empty",
passwordEmpty: "Password cannot be empty",
checkRefundgolds: "Refund gold cannot be empty", checkRefundgolds: "Refund gold cannot be empty",
checkPermanentGold: "Permanent gold cannot be empty", checkPermanentGold: "Permanent gold cannot be empty",
loginSuccess: "Login successful", loginSuccess: "Login successful",

2
src/components/locales/lang/zh-CN.js

@ -185,6 +185,8 @@ export default {
// 提示信息组 // 提示信息组
elmessage: { elmessage: {
// 通用 // 通用
accountEmpty: "账号不能为空",
passwordEmpty: "密码不能为空",
checkRefundgolds: "退款金币总数不能为0", checkRefundgolds: "退款金币总数不能为0",
checkPermanentGold: "永久金币不能为空", checkPermanentGold: "永久金币不能为空",
loginSuccess: "登录成功", loginSuccess: "登录成功",

5
src/util/http.js

@ -1,14 +1,15 @@
import request from './request' import request from './request'
export default function(options) { export default function(options) {
const { method = 'post', url, data = {}, params = {}, headers = {} } = options
const { method = 'post', url, data = {}, params = {}, headers = {}, responseType } = options
return request({ return request({
method, method,
url, url,
data, data,
params, params,
headers
headers,
responseType
}) })
.then(({ status, data, statusText }) => { .then(({ status, data, statusText }) => {
if (status === 200) { if (status === 200) {

100
src/views/login.vue

@ -1,5 +1,5 @@
<script setup> <script setup>
import {onMounted, ref} from 'vue'
import {onMounted, ref,onUnmounted} from 'vue'
import {ElMessage} from 'element-plus' import {ElMessage} from 'element-plus'
import request from '@/util/http' import request from '@/util/http'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
@ -34,20 +34,74 @@ function getMachineId() {
} }
} }
const form = ref({account: null, password: '', token: '', machineId: machineId1.value, code: '', uuid: ''})
const form = ref({account: null, password: '', token: '', machineId: machineId1.value, captcha: '', uuid: ''})
const formRef = ref(null)
const rules = {
account: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
],
captcha: [
{ required: true, message: '请输入验证码', trigger: 'blur' }
]
}
const captchaUrl = ref('') const captchaUrl = ref('')
const isCaptchaCooldown = ref(false)
let captchaCooldownTimer = null
let cooldownStartTime = 0 //
const COOLDOWN_TOTAL = 5 * 1000 // 5
//
const startCaptchaCooldown = () => {
isCaptchaCooldown.value = true
cooldownStartTime = Date.now()
captchaCooldownTimer = setTimeout(() => {
isCaptchaCooldown.value = false //
cooldownStartTime = 0 //
}, COOLDOWN_TOTAL)
}
const getCaptchaRemainingSeconds = () => {
if (!isCaptchaCooldown.value || cooldownStartTime === 0) {
return 0
}
const elapsed = Date.now() - cooldownStartTime
const remainingMs = Math.max(COOLDOWN_TOTAL - elapsed, 0)
const remainingSeconds = Math.ceil(remainingMs / 1000)
return remainingSeconds
}
const clearCaptchaCooldown = () => {
if (captchaCooldownTimer) {
clearTimeout(captchaCooldownTimer)
captchaCooldownTimer = null
}
isCaptchaCooldown.value = false
cooldownStartTime = 0
}
// //
const getCaptcha = async () => { const getCaptcha = async () => {
if (isCaptchaCooldown.value) {
ElMessage.warning('验证码获取太频繁,请' + getCaptchaRemainingSeconds() + '秒后再试')
return
}
try { try {
let uuid = Date.now()
localStorage.setItem('uuid', uuid)
const res = await request({ const res = await request({
url: '/admin/captchaImage',
method: 'get'
url: '/captcha' + '?uuid=' + uuid,
method: 'get',
responseType: 'blob',
}) })
if (res.code === 200) {
captchaUrl.value = "data:image/gif;base64," + res.img
form.value.uuid = res.uuid
if (captchaUrl.value) {
URL.revokeObjectURL(captchaUrl.value);
} }
captchaUrl.value = URL.createObjectURL(res);
startCaptchaCooldown()
} catch (error) { } catch (error) {
console.error('获取验证码失败', error) console.error('获取验证码失败', error)
} }
@ -59,6 +113,12 @@ const adminRoleId = ref(null)
const adminStore = useAdminStore() const adminStore = useAdminStore()
// //
const login = async function () { const login = async function () {
if (!formRef.value) return
try {
await formRef.value.validate()
} catch (err) {
return
}
if(loading.value) { if(loading.value) {
console.log('正在登录,请稍后') console.log('正在登录,请稍后')
@ -68,11 +128,15 @@ const login = async function () {
loading.value = true loading.value = true
try { try {
let params = {
...form.value,
uuid: localStorage.getItem('uuid')
}
const result = await request({ const result = await request({
url: '/admin/login', url: '/admin/login',
data: form.value
data: params
}) })
console.log('传给后端的参数', form.value)
console.log('传给后端的参数', params)
if (result.code === 200) { if (result.code === 200) {
// token // token
@ -114,16 +178,14 @@ const login = async function () {
} else { } else {
form.value.password = '' form.value.password = ''
form.value.account = '' form.value.account = ''
form.value.code = ''
form.value.captcha = ''
ElMessage.error(result.msg) ElMessage.error(result.msg)
loading.value = false //loading loading.value = false //loading
getCaptcha()
} }
} catch (error) { } catch (error) {
console.log('请求失败', error) console.log('请求失败', error)
ElMessage.error('登录失败,请检查账号密码') ElMessage.error('登录失败,请检查账号密码')
loading.value = false // loading loading.value = false // loading
getCaptcha()
} }
} }
// //
@ -184,6 +246,10 @@ onMounted(() => {
getCaptcha() getCaptcha()
}) })
onUnmounted(() => {
clearCaptchaCooldown()
})
</script> </script>
<template> <template>
<el-row class="login-page"> <el-row class="login-page">
@ -192,7 +258,7 @@ onMounted(() => {
</el-col> </el-col>
<el-col :span="6" :offset="3" class="form"> <el-col :span="6" :offset="3" class="form">
<!-- 登录表单 --> <!-- 登录表单 -->
<el-form :model="form" size="large" autocomplete="off">
<el-form :model="form" :rules="rules" ref="formRef" size="large" autocomplete="off">
<el-form-item> <el-form-item>
<h1 style="color: #409eff">熵盾管理系统 V1.0</h1> <h1 style="color: #409eff">熵盾管理系统 V1.0</h1>
</el-form-item> </el-form-item>
@ -207,15 +273,15 @@ onMounted(() => {
required required
/> />
</el-form-item> </el-form-item>
<el-form-item prop="code" required>
<el-form-item prop="captcha" required>
<el-row :gutter="20" style="width: 100%"> <el-row :gutter="20" style="width: 100%">
<el-col :span="16"> <el-col :span="16">
<el-input v-model="form.code" placeholder="请输入验证码" @keyup.enter="login"></el-input>
<el-input v-model="form.captcha" placeholder="请输入验证码" @keyup.enter="login"></el-input>
</el-col> </el-col>
<el-col :span="8" style="display: flex; align-items: center; justify-content: center;"> <el-col :span="8" style="display: flex; align-items: center; justify-content: center;">
<img v-if="captchaUrl" :src="captchaUrl" @click="getCaptcha" style="width: 100%; height: 40px; cursor: pointer; border-radius: 4px;" alt="验证码" title="点击刷新验证码" /> <img v-if="captchaUrl" :src="captchaUrl" @click="getCaptcha" style="width: 100%; height: 40px; cursor: pointer; border-radius: 4px;" alt="验证码" title="点击刷新验证码" />
<div v-else class="failed">
<img src="@/assets/images/loadingFaild.png" @click="getCaptcha">
<div v-else @click="getCaptcha" class="failed">
<img src="@/assets/images/loadingFaild.png" >
<text>点击刷新二维码</text> <text>点击刷新二维码</text>
</div> </div>
</el-col> </el-col>

Loading…
Cancel
Save