修改登陆api
This commit is contained in:
parent
4f5e971cb6
commit
60667511b4
@ -5,7 +5,6 @@
|
|||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
<script src="https://v-cn.vaptcha.com/v3.js"></script>
|
|
||||||
<title>红色警戒3数据分析中心</title>
|
<title>红色警戒3数据分析中心</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -50,39 +50,45 @@ import { loginSuccess } from '../utils/jwt';
|
|||||||
// }
|
// }
|
||||||
// )
|
// )
|
||||||
|
|
||||||
export const userLogin = async (username, password, server, token) => {
|
// 获取验证码
|
||||||
|
export const getCaptcha = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axiosInstance.get('/captcha');
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
export const userLogin = async (username, password, token, captcha) => {
|
||||||
try {
|
try {
|
||||||
// console.log('登录请求参数:', { username, password, server, token }); // 保留此调试日志以备将来使用,或按需移除
|
|
||||||
const response = await axiosInstance.post('/user/login', {
|
const response = await axiosInstance.post('/user/login', {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
server,
|
token,
|
||||||
token
|
captcha
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data.access_token) {
|
if (response.data.access_token) {
|
||||||
loginSuccess(response.data.access_token, username); // 使用 username 作为 userId
|
loginSuccess(response.data.access_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 错误将由响应拦截器统一处理和记录,这里可以直接抛出
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userRegister = async (qq_code, password, server, token) => {
|
// 用户注册
|
||||||
|
export const userRegister = async (qq_code, password, token, captcha) => {
|
||||||
try {
|
try {
|
||||||
const requestData = {
|
const response = await axiosInstance.post('/user/register', {
|
||||||
qq_code,
|
qq_code,
|
||||||
password,
|
password,
|
||||||
server,
|
token,
|
||||||
token
|
captcha
|
||||||
};
|
});
|
||||||
// console.log('注册请求参数:', requestData); // 保留此调试日志以备将来使用,或按需移除
|
|
||||||
|
|
||||||
const response = await axiosInstance.post('/user/register', requestData);
|
|
||||||
// console.log('注册响应数据:', response.data); // 保留此调试日志以备将来使用,或按需移除
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -26,40 +26,26 @@
|
|||||||
/>
|
/>
|
||||||
<span class="error-message" v-if="passwordError">{{ passwordError }}</span>
|
<span class="error-message" v-if="passwordError">{{ passwordError }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-container">
|
<div class="input-container captcha-container">
|
||||||
<!-- 人机验证 -->
|
<label for="captcha">验证码</label>
|
||||||
<div id="VAPTCHAContainer" style="width: 100%; height: 36px;">
|
<div class="captcha-wrapper">
|
||||||
<div class="VAPTCHA-init-main">
|
<input
|
||||||
<div class="VAPTCHA-init-loading">
|
type="text"
|
||||||
<a href="/" target="_blank">
|
id="captcha"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px"
|
v-model="captcha"
|
||||||
height="60px" viewBox="0 0 24 30"
|
placeholder="请输入验证码"
|
||||||
style="enable-background: new 0 0 50 50; width: 14px; height: 14px; vertical-align: middle"
|
@blur="validateCaptcha"
|
||||||
xml:space="preserve">
|
:class="{ 'error': captchaError }"
|
||||||
<rect x="0" y="9.22656" width="4" height="12.5469" fill="#CCCCCC">
|
/>
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0s" dur="0.6s"
|
<img
|
||||||
repeatCount="indefinite"></animate>
|
v-if="captchaImage"
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0s" dur="0.6s"
|
:src="captchaImage"
|
||||||
repeatCount="indefinite"></animate>
|
alt="验证码"
|
||||||
</rect>
|
class="captcha-image"
|
||||||
<rect x="10" y="5.22656" width="4" height="20.5469" fill="#CCCCCC">
|
@click="refreshCaptcha"
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.15s" dur="0.6s"
|
/>
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.15s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
</rect>
|
|
||||||
<rect x="20" y="8.77344" width="4" height="13.4531" fill="#CCCCCC">
|
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.3s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.3s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
</rect>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<span class="VAPTCHA-text">Vaptcha Initializing...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span class="error-message" v-if="captchaError">{{ captchaError }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-button">
|
<div class="login-button">
|
||||||
<button type="submit" :disabled="!isFormValid">登录</button>
|
<button type="submit" :disabled="!isFormValid">登录</button>
|
||||||
@ -74,18 +60,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { userLogin } from '../api/login'
|
import { userLogin, getCaptcha } from '../api/login'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const VAPTCHAObj = ref(null)
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
|
const captcha = ref('')
|
||||||
|
const captchaImage = ref('')
|
||||||
|
const captchaToken = ref('')
|
||||||
|
|
||||||
// 错误信息
|
// 错误信息
|
||||||
const usernameError = ref('')
|
const usernameError = ref('')
|
||||||
const passwordError = ref('')
|
const passwordError = ref('')
|
||||||
|
const captchaError = ref('')
|
||||||
const isVaptchaVerified = ref(false)
|
|
||||||
|
|
||||||
const validateUsername = () => {
|
const validateUsername = () => {
|
||||||
if (!username.value) {
|
if (!username.value) {
|
||||||
@ -121,40 +108,43 @@ const validatePassword = () => {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const validateCaptcha = () => {
|
||||||
|
if (!captcha.value) {
|
||||||
|
captchaError.value = '请输入验证码'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (captcha.value.length !== 4) {
|
||||||
|
captchaError.value = '验证码长度不正确'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
captchaError.value = ''
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const isFormValid = computed(() => {
|
const isFormValid = computed(() => {
|
||||||
return !usernameError.value &&
|
return !usernameError.value &&
|
||||||
!passwordError.value &&
|
!passwordError.value &&
|
||||||
|
!captchaError.value &&
|
||||||
username.value &&
|
username.value &&
|
||||||
password.value &&
|
password.value &&
|
||||||
VAPTCHAObj.value && // 确保人机验证已初始化
|
captcha.value
|
||||||
isVaptchaVerified.value // 确保人机验证已通过
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshCaptcha = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getCaptcha()
|
||||||
|
// 直接使用API返回的img(base64格式的验证码图片)
|
||||||
|
captchaImage.value = `data:image/png;base64,${response.img}`
|
||||||
|
captchaToken.value = response.token
|
||||||
|
captcha.value = '' // 清空验证码输入
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取验证码失败:', error)
|
||||||
|
alert('获取验证码失败,请刷新页面重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.vaptcha({
|
refreshCaptcha()
|
||||||
vid: '6828264bdc0ff12924d9bfe3',
|
|
||||||
mode: 'click',
|
|
||||||
scene: 1,
|
|
||||||
container: '#VAPTCHAContainer',
|
|
||||||
area: 'auto'
|
|
||||||
}).then(function (obj) {
|
|
||||||
VAPTCHAObj.value = obj
|
|
||||||
obj.render()
|
|
||||||
// 监听验证成功事件
|
|
||||||
obj.listen('pass', function () {
|
|
||||||
isVaptchaVerified.value = true
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听验证失败事件
|
|
||||||
obj.listen('fail', function () {
|
|
||||||
isVaptchaVerified.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听关闭事件
|
|
||||||
obj.listen('close', function () {
|
|
||||||
isVaptchaVerified.value = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
@ -163,58 +153,37 @@ const handleLogin = async () => {
|
|||||||
if (!validateForm()) {
|
if (!validateForm()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 验证人机验证
|
|
||||||
if (!VAPTCHAObj.value) {
|
|
||||||
alert('请完成人机验证')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const serverToken = await VAPTCHAObj.value.getServerToken()
|
|
||||||
console.log('获取到的 serverToken:', serverToken)
|
|
||||||
|
|
||||||
if (!serverToken || !serverToken.token || !serverToken.server) {
|
|
||||||
alert('获取验证token失败,请重新验证')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const registerData = {
|
|
||||||
username: username.value,
|
|
||||||
password: password.value,
|
|
||||||
server: serverToken.server,
|
|
||||||
token: serverToken.token
|
|
||||||
}
|
|
||||||
// 调用登录 API
|
// 调用登录 API
|
||||||
const response = await userLogin(
|
const response = await userLogin(
|
||||||
registerData.username,
|
username.value,
|
||||||
registerData.password,
|
password.value,
|
||||||
registerData.server,
|
captchaToken.value,
|
||||||
registerData.token
|
captcha.value
|
||||||
)
|
)
|
||||||
|
|
||||||
// 登录成功,跳转到首页
|
// 登录成功,跳转到首页
|
||||||
if (response.access_token) {
|
if (response.access_token) {
|
||||||
// 存储 token 和用户ID (QQ号)
|
|
||||||
localStorage.setItem('access_token', response.access_token)
|
localStorage.setItem('access_token', response.access_token)
|
||||||
localStorage.setItem('user_id', username.value) // username.value 是用户输入的QQ号
|
localStorage.setItem('user_id', username.value)
|
||||||
router.push('/')
|
router.push('/')
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('登录失败:未获取到访问令牌')
|
throw new Error('登录失败:未获取到访问令牌')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('登录失败:', error)
|
console.error('登录失败:', error)
|
||||||
if (error.response && error.response.status === 401) {
|
if (error.response && error.response.status === 401) {
|
||||||
alert('错误的用户名或密码,或未注册')
|
alert('错误的用户名或密码')
|
||||||
} else {
|
} else {
|
||||||
alert(error.response?.data?.message || error.message || '登录失败,请稍后重试')
|
alert(error.response?.data?.message || error.message || '登录失败,请稍后重试')
|
||||||
}
|
}
|
||||||
|
// 登录失败时刷新验证码
|
||||||
|
refreshCaptcha()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const validateForm = () => {
|
const validateForm = () => {
|
||||||
if (!username.value || !password.value) {
|
return validateUsername() && validatePassword() && validateCaptcha()
|
||||||
alert('请输入用户名和密码')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -351,5 +320,98 @@ const validateForm = () => {
|
|||||||
.input-container input.error {
|
.input-container input.error {
|
||||||
border-color: #f56c6c;
|
border-color: #f56c6c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.captcha-container {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
flex: 1;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #f7fbfd;
|
||||||
|
transition: border 0.2s;
|
||||||
|
width: calc(100% - 120px); /* 减去验证码图片的宽度和间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input:focus {
|
||||||
|
border: 1.5px solid #409eff;
|
||||||
|
outline: none;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 110px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端适配 */
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.login-form {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 340px;
|
||||||
|
padding: 24px 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container input,
|
||||||
|
.captcha-wrapper input {
|
||||||
|
height: 38px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button button {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 超小屏幕适配 */
|
||||||
|
@media screen and (max-width: 320px) {
|
||||||
|
.login-form {
|
||||||
|
padding: 20px 16px 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
width: calc(100% - 90px);
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -20,40 +20,26 @@
|
|||||||
@blur="validateConfirmPassword" :class="{ 'error': confirmPasswordError }" />
|
@blur="validateConfirmPassword" :class="{ 'error': confirmPasswordError }" />
|
||||||
<span class="error-message" v-if="confirmPasswordError">{{ confirmPasswordError }}</span>
|
<span class="error-message" v-if="confirmPasswordError">{{ confirmPasswordError }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-container">
|
<div class="input-container captcha-container">
|
||||||
<!-- 人机验证 -->
|
<label for="captcha">验证码</label>
|
||||||
<div id="VAPTCHAContainer" style="width: 100%; height: 36px;">
|
<div class="captcha-wrapper">
|
||||||
<div class="VAPTCHA-init-main">
|
<input
|
||||||
<div class="VAPTCHA-init-loading">
|
type="text"
|
||||||
<a href="/" target="_blank">
|
id="captcha"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px"
|
v-model="captcha"
|
||||||
height="60px" viewBox="0 0 24 30"
|
placeholder="请输入验证码"
|
||||||
style="enable-background: new 0 0 50 50; width: 14px; height: 14px; vertical-align: middle"
|
@blur="validateCaptcha"
|
||||||
xml:space="preserve">
|
:class="{ 'error': captchaError }"
|
||||||
<rect x="0" y="9.22656" width="4" height="12.5469" fill="#CCCCCC">
|
/>
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0s" dur="0.6s"
|
<img
|
||||||
repeatCount="indefinite"></animate>
|
v-if="captchaImage"
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0s" dur="0.6s"
|
:src="captchaImage"
|
||||||
repeatCount="indefinite"></animate>
|
alt="验证码"
|
||||||
</rect>
|
class="captcha-image"
|
||||||
<rect x="10" y="5.22656" width="4" height="20.5469" fill="#CCCCCC">
|
@click="refreshCaptcha"
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.15s" dur="0.6s"
|
/>
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.15s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
</rect>
|
|
||||||
<rect x="20" y="8.77344" width="4" height="13.4531" fill="#CCCCCC">
|
|
||||||
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.3s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.3s" dur="0.6s"
|
|
||||||
repeatCount="indefinite"></animate>
|
|
||||||
</rect>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<span class="VAPTCHA-text">Vaptcha Initializing...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span class="error-message" v-if="captchaError">{{ captchaError }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-button">
|
<div class="login-button">
|
||||||
<button type="submit" :disabled="!isFormValid">注册</button>
|
<button type="submit" :disabled="!isFormValid">注册</button>
|
||||||
@ -68,13 +54,15 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { userRegister } from "@/api/login.js";
|
import { userRegister, getCaptcha } from "@/api/login.js";
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const VAPTCHAObj = ref(null)
|
|
||||||
const username = ref('')
|
const username = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
const confirmPassword = ref('')
|
const confirmPassword = ref('')
|
||||||
|
const captcha = ref('')
|
||||||
|
const captchaImage = ref('')
|
||||||
|
const captchaToken = ref('')
|
||||||
|
|
||||||
// 定义 emit
|
// 定义 emit
|
||||||
const emit = defineEmits(['login'])
|
const emit = defineEmits(['login'])
|
||||||
@ -83,8 +71,7 @@ const emit = defineEmits(['login'])
|
|||||||
const usernameError = ref('')
|
const usernameError = ref('')
|
||||||
const passwordError = ref('')
|
const passwordError = ref('')
|
||||||
const confirmPasswordError = ref('')
|
const confirmPasswordError = ref('')
|
||||||
|
const captchaError = ref('')
|
||||||
|
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const validateUsername = () => {
|
const validateUsername = () => {
|
||||||
@ -126,92 +113,76 @@ const validateConfirmPassword = () => {
|
|||||||
confirmPasswordError.value = ''
|
confirmPasswordError.value = ''
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const isVaptchaVerified = ref(false)
|
|
||||||
|
const validateCaptcha = () => {
|
||||||
|
if (!captcha.value) {
|
||||||
|
captchaError.value = '请输入验证码'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (captcha.value.length !== 4) {
|
||||||
|
captchaError.value = '验证码长度不正确'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
captchaError.value = ''
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 计算表单是否有效
|
// 计算表单是否有效
|
||||||
const isFormValid = computed(() => {
|
const isFormValid = computed(() => {
|
||||||
return !usernameError.value &&
|
return !usernameError.value &&
|
||||||
!passwordError.value &&
|
!passwordError.value &&
|
||||||
!confirmPasswordError.value &&
|
!confirmPasswordError.value &&
|
||||||
|
!captchaError.value &&
|
||||||
username.value &&
|
username.value &&
|
||||||
password.value &&
|
password.value &&
|
||||||
confirmPassword.value &&
|
confirmPassword.value &&
|
||||||
VAPTCHAObj.value && // 确保人机验证已初始化
|
captcha.value
|
||||||
isVaptchaVerified.value // 确保人机验证已通过
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshCaptcha = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getCaptcha()
|
||||||
|
captchaImage.value = `data:image/png;base64,${response.img}`
|
||||||
|
captchaToken.value = response.token
|
||||||
|
captcha.value = '' // 清空验证码输入
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取验证码失败:', error)
|
||||||
|
alert('获取验证码失败,请刷新页面重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 添加人机验证状态
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.vaptcha({
|
refreshCaptcha()
|
||||||
vid: '6828264bdc0ff12924d9bfe3',
|
|
||||||
mode: 'click',
|
|
||||||
scene: 2,
|
|
||||||
container: '#VAPTCHAContainer',
|
|
||||||
area: 'auto'
|
|
||||||
}).then(function (obj) {
|
|
||||||
VAPTCHAObj.value = obj
|
|
||||||
obj.render()
|
|
||||||
|
|
||||||
// 监听验证成功事件
|
|
||||||
obj.listen('pass', function () {
|
|
||||||
isVaptchaVerified.value = true
|
|
||||||
console.log('验证通过')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听验证失败事件
|
|
||||||
obj.listen('fail', function () {
|
|
||||||
isVaptchaVerified.value = false
|
|
||||||
console.log('验证失败')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听关闭事件
|
|
||||||
obj.listen('close', function () {
|
|
||||||
isVaptchaVerified.value = false
|
|
||||||
console.log('验证关闭')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleRegister = async () => {
|
const handleRegister = async () => {
|
||||||
|
try {
|
||||||
// 验证表单
|
// 验证表单
|
||||||
if (!validateUsername() || !validatePassword() || !validateConfirmPassword()) {
|
if (!validateUsername() || !validatePassword() || !validateConfirmPassword() || !validateCaptcha()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 验证人机验证
|
|
||||||
if (!isVaptchaVerified.value || !VAPTCHAObj.value) {
|
|
||||||
alert('请完成人机验证')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取验证token
|
|
||||||
const serverToken = await VAPTCHAObj.value.getServerToken()
|
|
||||||
console.log('获取到的 serverToken:', serverToken)
|
|
||||||
|
|
||||||
if (!serverToken || !serverToken.token || !serverToken.server) {
|
|
||||||
alert('获取验证token失败,请重新验证')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造注册请求参数
|
|
||||||
const registerData = {
|
|
||||||
qq_code: username.value,
|
|
||||||
password: password.value,
|
|
||||||
server: serverToken.server,
|
|
||||||
token: serverToken.token
|
|
||||||
}
|
|
||||||
console.log('注册请求参数:', registerData)
|
|
||||||
|
|
||||||
// 发送注册请求
|
// 发送注册请求
|
||||||
await userRegister(
|
await userRegister(
|
||||||
registerData.qq_code,
|
username.value,
|
||||||
registerData.password,
|
password.value,
|
||||||
registerData.server,
|
captchaToken.value,
|
||||||
registerData.token
|
captcha.value
|
||||||
)
|
)
|
||||||
|
|
||||||
alert('注册成功')
|
alert('注册成功')
|
||||||
// 切换到登录模块
|
// 切换到登录模块
|
||||||
emit('login')
|
emit('login')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('注册失败:', error)
|
||||||
|
if (error.response && error.response.status === 400) {
|
||||||
|
alert('该QQ号已被注册')
|
||||||
|
} else {
|
||||||
|
alert(error.response?.data?.message || error.message || '注册失败,请稍后重试')
|
||||||
|
}
|
||||||
|
// 注册失败时刷新验证码
|
||||||
|
refreshCaptcha()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -355,4 +326,97 @@ const handleRegister = async () => {
|
|||||||
color: #666;
|
color: #666;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.captcha-container {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
flex: 1;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #f7fbfd;
|
||||||
|
transition: border 0.2s;
|
||||||
|
width: calc(100% - 120px); /* 减去验证码图片的宽度和间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input:focus {
|
||||||
|
border: 1.5px solid #409eff;
|
||||||
|
outline: none;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 110px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 1px solid #d0d7de;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端适配 */
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.login-form {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 340px;
|
||||||
|
padding: 24px 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container input,
|
||||||
|
.captcha-wrapper input {
|
||||||
|
height: 38px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button button {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 超小屏幕适配 */
|
||||||
|
@media screen and (max-width: 320px) {
|
||||||
|
.login-form {
|
||||||
|
padding: 20px 16px 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-wrapper input {
|
||||||
|
width: calc(100% - 90px);
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-image {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
x
Reference in New Issue
Block a user