DCFronted/src/components/register_module.vue
2025-05-26 20:35:34 +08:00

358 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="login-form">
<div>注册</div>
<form class="login-form-container" @submit.prevent="handleRegister">
<div class="input-container">
<label for="username">QQ号</label>
<input type="text" id="username" v-model="username" placeholder="请输入QQ号" @blur="validateUsername"
:class="{ 'error': usernameError }" />
<span class="error-message" v-if="usernameError">{{ usernameError }}</span>
</div>
<div class="input-container">
<label for="password">密码</label>
<input type="password" id="password" v-model="password" placeholder="请输入密码" @blur="validatePassword"
:class="{ 'error': passwordError }" />
<span class="error-message" v-if="passwordError">{{ passwordError }}</span>
</div>
<div class="input-container">
<label for="confirmPassword">再次输入密码</label>
<input type="password" id="confirmPassword" v-model="confirmPassword" placeholder="请输入密码"
@blur="validateConfirmPassword" :class="{ 'error': confirmPasswordError }" />
<span class="error-message" v-if="confirmPasswordError">{{ confirmPasswordError }}</span>
</div>
<div class="input-container">
<!-- 人机验证 -->
<div id="VAPTCHAContainer" style="width: 100%; height: 36px;">
<div class="VAPTCHA-init-main">
<div class="VAPTCHA-init-loading">
<a href="/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px"
height="60px" viewBox="0 0 24 30"
style="enable-background: new 0 0 50 50; width: 14px; height: 14px; vertical-align: middle"
xml:space="preserve">
<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"
repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0s" dur="0.6s"
repeatCount="indefinite"></animate>
</rect>
<rect x="10" y="5.22656" width="4" height="20.5469" fill="#CCCCCC">
<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>
<div class="login-button">
<button type="submit" :disabled="!isFormValid">注册</button>
</div>
<div class="register-link">
<a @click.prevent="$emit('login')">返回登陆</a>
</div>
</form>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { userRegister } from "@/api/login.js";
const router = useRouter()
const VAPTCHAObj = ref(null)
const username = ref('')
const password = ref('')
const confirmPassword = ref('')
// 定义 emit
const emit = defineEmits(['login'])
// 错误信息
const usernameError = ref('')
const passwordError = ref('')
const confirmPasswordError = ref('')
// 表单验证规则
const validateUsername = () => {
if (!username.value) {
usernameError.value = '请输入QQ号码'
return false
}
// 只允许纯数字
if (!/^\d+$/.test(username.value)) {
usernameError.value = 'QQ号只能包含数字'
return false
}
usernameError.value = ''
return true
}
const validatePassword = () => {
if (!password.value) {
passwordError.value = '请输入密码'
return false
}
if (password.value.length < 6) {
passwordError.value = '密码长度不能小于6个字符'
return false
}
passwordError.value = ''
return true
}
const validateConfirmPassword = () => {
if (!confirmPassword.value) {
confirmPasswordError.value = '请再次输入密码'
return false
}
if (confirmPassword.value !== password.value) {
confirmPasswordError.value = '两次输入的密码不一致'
return false
}
confirmPasswordError.value = ''
return true
}
const isVaptchaVerified = ref(false)
// 计算表单是否有效
const isFormValid = computed(() => {
return !usernameError.value &&
!passwordError.value &&
!confirmPasswordError.value &&
username.value &&
password.value &&
confirmPassword.value &&
VAPTCHAObj.value && // 确保人机验证已初始化
isVaptchaVerified.value // 确保人机验证已通过
})
// 添加人机验证状态
onMounted(() => {
window.vaptcha({
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 () => {
// 验证表单
if (!validateUsername() || !validatePassword() || !validateConfirmPassword()) {
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(
registerData.qq_code,
registerData.password,
registerData.server,
registerData.token
)
alert('注册成功')
// 切换到登录模块
emit('login')
}
</script>
<style scoped>
.login-form {
width: 340px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
box-shadow: 0 4px 32px rgba(0, 0, 0, 0.10);
padding: 36px 32px 28px 32px;
display: flex;
flex-direction: column;
align-items: center;
}
.login-form>div:first-child {
font-size: 26px;
font-weight: bold;
color: #222;
margin-bottom: 28px;
letter-spacing: 2px;
}
.login-form-container {
width: 100%;
display: flex;
flex-direction: column;
gap: 18px;
}
.input-container {
display: flex;
flex-direction: column;
gap: 6px;
}
.input-container label {
font-size: 14px;
color: #666;
margin-bottom: 2px;
}
.input-container input {
height: 40px;
border: 1px solid #d0d7de;
border-radius: 6px;
padding: 0 12px;
font-size: 15px;
background: #f7fbfd;
transition: border 0.2s;
}
.input-container input:focus {
border: 1.5px solid #409eff;
outline: none;
background: #fff;
}
.input-container input.error {
border-color: #f56c6c;
}
.error-message {
color: #f56c6c;
font-size: 12px;
margin-top: 2px;
}
.login-button {
margin-top: 10px;
}
.login-button button {
width: 100%;
height: 42px;
background: linear-gradient(90deg, #409eff 0%, #6dd5fa 100%);
color: #fff;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.10);
transition: background 0.2s;
}
.login-button button:hover:not(:disabled) {
background: linear-gradient(90deg, #66b1ff 0%, #6dd5fa 100%);
}
.login-button button:disabled {
background: #a0cfff;
cursor: not-allowed;
}
.register-link {
margin-top: 12px;
text-align: right;
}
.register-link a {
color: #409eff;
font-size: 14px;
text-decoration: none;
cursor: pointer;
transition: color 0.2s;
}
.register-link a:hover {
color: #1a73e8;
text-decoration: underline;
}
/* VAPTCHA 相关样式 */
.VAPTCHA-init-main {
display: table;
width: 100%;
height: 100%;
background-color: #f7fbfd;
border-radius: 6px;
border: 1px solid #d0d7de;
}
.VAPTCHA-init-loading {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.VAPTCHA-init-loading>a {
display: inline-block;
width: 18px;
height: 18px;
border: none;
}
.VAPTCHA-init-loading .VAPTCHA-text {
font-family: sans-serif;
font-size: 12px;
color: #666;
vertical-align: middle;
}
</style>