DCFronted/src/components/register_module.vue
2025-06-04 23:50:46 +08:00

422 lines
9.1 KiB
Vue

<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 captcha-container">
<label for="captcha">验证码</label>
<div class="captcha-wrapper">
<input
type="text"
id="captcha"
v-model="captcha"
placeholder="请输入验证码"
@blur="validateCaptcha"
:class="{ 'error': captchaError }"
/>
<img
v-if="captchaImage"
:src="captchaImage"
alt="验证码"
class="captcha-image"
@click="refreshCaptcha"
/>
</div>
<span class="error-message" v-if="captchaError">{{ captchaError }}</span>
</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, getCaptcha } from "@/api/login.js";
const router = useRouter()
const username = ref('')
const password = ref('')
const confirmPassword = ref('')
const captcha = ref('')
const captchaImage = ref('')
const captchaToken = ref('')
// 定义 emit
const emit = defineEmits(['login'])
// 错误信息
const usernameError = ref('')
const passwordError = ref('')
const confirmPasswordError = ref('')
const captchaError = 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 validateCaptcha = () => {
if (!captcha.value) {
captchaError.value = '请输入验证码'
return false
}
if (captcha.value.length !== 4) {
captchaError.value = '验证码长度不正确'
return false
}
captchaError.value = ''
return true
}
// 计算表单是否有效
const isFormValid = computed(() => {
return !usernameError.value &&
!passwordError.value &&
!confirmPasswordError.value &&
!captchaError.value &&
username.value &&
password.value &&
confirmPassword.value &&
captcha.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(() => {
refreshCaptcha()
})
const handleRegister = async () => {
try {
// 验证表单
if (!validateUsername() || !validatePassword() || !validateConfirmPassword() || !validateCaptcha()) {
return
}
// 发送注册请求
await userRegister(
username.value,
password.value,
captchaToken.value,
captcha.value
)
alert('注册成功')
// 切换到登录模块
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>
<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;
}
.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>