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

272 lines
7.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">
defineOptions({
name: 'Register'
})
// 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'
import { useRoute } from 'vue-router'
//store实例
const userStore = useUserStore()
const route = useRoute()
// 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.countryCode + registerForm.value.phone,
mobile_area: registerForm.value.countryCode,
reg_type: activeTab.value === 'email' ? 1 : 2,
type: 'reg_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.countryCode + registerForm.value.phone
: registerForm.value.email
const currentCaptchaState = type === 'phone' ? phoneCaptchaState : emailCaptchaState
const sendFunc = type === 'phone' ? 'sendPhoneCaptcha' : 'sendEmailCaptcha'
console.log('registerForm.countryCode', registerForm.value.countryCode)
// 调用封装的发送函数(传正确的函数,而非字符串)
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.countryCode + 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)
})
onMounted(() => {
registerForm.value.inviteCode = route.query.invite_code
})
</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>