foreign-admin-ui/src/views/user/Register.vue

208 lines
6.9 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="user-card">
<UserHeader />
<UserText :user-text="userText" />
<UserTabs v-model="activeTab" :tab-list="tabList" />
<el-form class="user-form" ref="registerFormRef" :model="registerForm" :rules="registerRules">
<Transition name="form-switch" mode="out-in">
<el-form-item class="captcha-item" v-if="activeTab === 'email'" key="form-email-item" prop="email">
<el-input v-model="registerForm.email" placeholder="请输入邮箱" clearable size="large" />
<el-button type="primary" class="captcha-btn" @click="handleSendCode" :disabled="emailIsCounting">{{
emailIsCounting ? `${emailCountdown}s后重新获取` : '发送验证码' }}</el-button>
</el-form-item>
<el-form-item class="phone-item captcha-item" prop="phone" v-else-if="activeTab === 'phone'"
key="form-phone-item">
<el-select v-model="registerForm.countryCode" :teleported="false" value-key="code" placeholder="国家"
size="large">
<el-option v-for="item in countryOptions" :key="item.code" :label="item.code" :value="item.code">
<div class="country-option">
<span class="country-name">{{ item.name }}</span>
<span class="country-code">{{ item.code }}</span>
</div>
</el-option>
</el-select>
<el-input v-model="registerForm.phone" placeholder="请输入手机号" clearable size="large" />
<el-button type="primary" class="captcha-btn" @click="handleSendCode" :disabled="phoneIsCounting">{{
phoneIsCounting ? `${phoneCountdown}s后重新获取` : '发送验证码' }}</el-button>
</el-form-item>
</Transition>
<UserCaptcha v-model="registerForm.code" />
<el-form-item label="设置密码(6-12位密码包含特殊符号以及大小写)" label-position="top" prop="password">
<el-input placeholder="请输入密码" clearable show-password size="large" type="password"
v-model="registerForm.password" />
</el-form-item>
<el-form-item label="邀请链接/邀请码(选填)" label-position="top" prop="inviteCode">
<el-input placeholder="请输入邀请链接/邀请码" clearable size="large" type="text" v-model="registerForm.inviteCode" />
</el-form-item>
<el-form-item>
<el-checkbox label="同意注册协议">我已阅读并同意 隐私条例、 退款政策、 AMLCTF政策、<br> 执行政策 和 网站条款和条件</el-checkbox>
</el-form-item>
<el-form-item class="form-submit">
<el-button type="primary" class="form-btn" @click="handleRegister">注册</el-button>
</el-form-item>
<router-link to="/user/login" class="to-login">已有账号?立即登录</router-link>
</el-form>
</div>
</template>
<script setup lang="ts">
// type类型
import type { FormInstance, FormRules } from 'element-plus'
// 组件
import UserHeader from './components/Header.vue'
import UserText from './components/Text.vue'
import UserTabs from './components/Tabs.vue'
import UserCaptcha from './components/Captcha.vue'
//公共方法/store/配置文件
import { useUserStore } from '@/stores/modules/user'
import { md5Encrypt } from '@/utils/crypto'
import { sendCaptcha, initCaptchaState, clearCaptchaTimer } from '@/utils/sendCaptcha'
//用户校验规则
import { countryOptions } from '@/views/user/config/mock'
import { passwordRules, emailRules, phoneRules, codeRules } from './config/rules'
//store实例
const userStore = useUserStore()
// UserText 实例
const userText = ref({
backText: '',
title: '注册',
text: '',
});
//tabs 实例
const tabList = ref([
{ label: '邮箱', name: 'email' },
{ label: '手机', name: 'phone' },
])
const activeTab = ref<string>('email')
// 注册表单实例
const registerFormRef = ref<FormInstance>()
const registerForm = ref({
email: '',
countryCode: '+86',
phone: '',
password: '',
code: '',
inviteCode: ''
})
const registerRules = ref<FormRules>({
email: emailRules().email,
phone: phoneRules(registerForm.value).phone,
password: passwordRules(registerForm.value).password,
code: codeRules().code,
})
//初始化验证码倒计时状态
const emailCaptchaState = initCaptchaState('email'); // 邮箱专属
const phoneCaptchaState = initCaptchaState('phone'); // 手机专属
// 邮箱验证码状态
const { isCounting: emailIsCounting, countdown: emailCountdown } = emailCaptchaState
// 手机验证码状态
const { isCounting: phoneIsCounting, countdown: phoneCountdown } = phoneCaptchaState
//方法
// 定义发送验证码接口
const sendCodeApi = async () => {
// 发送验证码参数
const sendParams = {
email: registerForm.value.email,
mobile: registerForm.value.phone,
reg_type: activeTab.value === 'email' ? 1 : 2,
type:'resetPass_code'
}
return userStore.sendCode(sendParams)
}
//发送验证码
const handleSendCode = async () => {
if (!registerFormRef.value) return
try {
await registerFormRef.value.validateField(activeTab.value)
} catch (error) {
console.error('字段校验失败:', error)
return
}
// 确定类型、接收方、对应的倒计时状态和发送函数
const type: string = activeTab.value === 'phone' ? 'phone' : 'email';
const receiver = type === 'phone' ? registerForm.value.phone : registerForm.value.email;
const currentCaptchaState = type === 'phone' ? phoneCaptchaState : emailCaptchaState;
const sendFunc = type === 'phone' ? "sendPhoneCaptcha" : "sendEmailCaptcha";
// 调用封装的发送函数(传正确的函数,而非字符串)
await sendCaptcha(
type,
receiver,
currentCaptchaState, // 只更新当前类型的倒计时状态
() => sendCodeApi() // 传入返回Promise的函数
);
}
//注册
const handleRegister = async () => {
if (!registerFormRef.value) return;
try {
// 提交时再次验证(显示错误提示)
await registerFormRef.value.validate();
// 注册参数
const registerParams = {
email: registerForm.value.email,
mobile: registerForm.value.phone,
reg_type: activeTab.value === 'email' ? 1 : 2,
invite_code: registerForm.value.inviteCode,
code: registerForm.value.code,
password: registerForm.value.password
};
// 注册逻辑
await userStore.register(registerParams);
} catch (error) {
console.error('表单校验失败:', error);
}
}
// 组件卸载时清除定时器(关键:防止内存泄漏)
onUnmounted(() => {
clearCaptchaTimer(emailCaptchaState);
clearCaptchaTimer(phoneCaptchaState);
});
</script>
<style scoped lang="scss">
.user-form {
.phone-item,
.captcha-item {
:deep(.el-form-item__content) {
flex-wrap: nowrap;
}
:deep(.el-select-dropdown__item) {
padding: 0 16px 0 16px;
}
.el-select {
width: 180px !important;
}
}
.to-login {
display: flex;
justify-content: center;
text-decoration: none;
color: #409eff;
margin-top: 24px;
}
}
</style>