fix:添加查询是否注册,页面问题修复
This commit is contained in:
@@ -228,6 +228,17 @@ const local: any = {
|
|||||||
birthDate: 'Birth Date',
|
birthDate: 'Birth Date',
|
||||||
birthDatePlaceholder: 'Please select birth date',
|
birthDatePlaceholder: 'Please select birth date',
|
||||||
birthDateRequired: 'Please select birth date',
|
birthDateRequired: 'Please select birth date',
|
||||||
|
usernameLengthLimit:"Username is too short",
|
||||||
|
usernameExists:"The username is already registered",
|
||||||
|
usernameRequired:"The username cannot be empty",
|
||||||
|
phoneInvalid:"The mobile phone number is incorrect",
|
||||||
|
phoneExists:"The mobile phone number has been registered",
|
||||||
|
emailInvalid:"The email is incorrect",
|
||||||
|
emailExists:"The email has been registered",
|
||||||
|
emailRequired:"The email cannot be empty",
|
||||||
|
codeRequired:"The code cannot be empty",
|
||||||
|
passwordRequired:"The password cannot be empty",
|
||||||
|
passwordLength:"The password is too short",
|
||||||
},
|
},
|
||||||
resetPwd: {
|
resetPwd: {
|
||||||
title: 'Reset Password'
|
title: 'Reset Password'
|
||||||
|
|||||||
@@ -228,6 +228,17 @@ const local:any = {
|
|||||||
birthDate: '出生日期',
|
birthDate: '出生日期',
|
||||||
birthDatePlaceholder: '请选择出生日期',
|
birthDatePlaceholder: '请选择出生日期',
|
||||||
birthDateRequired: '请选择出生日期',
|
birthDateRequired: '请选择出生日期',
|
||||||
|
usernameLengthLimit:"用户名太短",
|
||||||
|
usernameExists:"用户名已经注册",
|
||||||
|
usernameRequired:"用户名不能为空",
|
||||||
|
phoneInvalid:"手机号格式不正确",
|
||||||
|
phoneExists:"手机号已经注册",
|
||||||
|
emailInvalid:"邮箱格式不正确",
|
||||||
|
emailExists:"邮箱已经注册",
|
||||||
|
emailRequired:"邮箱不能为空",
|
||||||
|
codeRequired:"验证码不能为空",
|
||||||
|
passwordRequired:"密码不能为空",
|
||||||
|
passwordLength:"密码太短",
|
||||||
},
|
},
|
||||||
resetPwd: {
|
resetPwd: {
|
||||||
title: '重置密码'
|
title: '重置密码'
|
||||||
|
|||||||
@@ -21,7 +21,13 @@ export function sendCaptcha(body:Api.Auth.EmailCaptcha){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
//验证注册
|
//验证注册
|
||||||
|
export function doCheckUserRepeat(body:Api.Auth.CheckBody){
|
||||||
|
return request<boolean>({
|
||||||
|
url:'/u/user/checkRepeat',
|
||||||
|
method:'post',
|
||||||
|
data:body
|
||||||
|
})
|
||||||
|
}
|
||||||
//添加注册
|
//添加注册
|
||||||
export function fetchRegister(body: Api.Auth.RegisterBody) {
|
export function fetchRegister(body: Api.Auth.RegisterBody) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { localStg } from '@/utils/storage';
|
|||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import { useRouteStore } from '../route';
|
import { useRouteStore } from '../route';
|
||||||
import { clearAuthStorage, emptyInfo, getToken } from './shared';
|
import { clearAuthStorage, emptyInfo, getToken } from './shared';
|
||||||
import {sendCaptcha} from "@/service/api/auth";
|
import {doCheckUserRepeat, sendCaptcha} from "@/service/api/auth";
|
||||||
|
|
||||||
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
@@ -122,6 +122,16 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//check User
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户信息是否已存在
|
||||||
|
*/
|
||||||
|
async function checkUserRepeat(checkForm:Api.Auth.CheckBody) {
|
||||||
|
const { data, error } = await doCheckUserRepeat(checkForm);
|
||||||
|
return { exists: data, error };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register new user
|
* Register new user
|
||||||
*/
|
*/
|
||||||
@@ -163,5 +173,6 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
refreshUserInfo,
|
refreshUserInfo,
|
||||||
register,
|
register,
|
||||||
captcha,
|
captcha,
|
||||||
|
checkUserRepeat,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
5
src/typings/api.d.ts
vendored
5
src/typings/api.d.ts
vendored
@@ -152,6 +152,11 @@ declare namespace Api {
|
|||||||
interface EmailCaptcha{
|
interface EmailCaptcha{
|
||||||
email:string;
|
email:string;
|
||||||
}
|
}
|
||||||
|
interface CheckBody{
|
||||||
|
username?: string;
|
||||||
|
email?: string;
|
||||||
|
phonenumber?:string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
1
src/typings/auto-imports.d.ts
vendored
1
src/typings/auto-imports.d.ts
vendored
@@ -53,6 +53,7 @@ declare global {
|
|||||||
const doAddDict: typeof import('../service/api/dict')['doAddDict']
|
const doAddDict: typeof import('../service/api/dict')['doAddDict']
|
||||||
const doAddMenu: typeof import('../service/api/menu')['doAddMenu']
|
const doAddMenu: typeof import('../service/api/menu')['doAddMenu']
|
||||||
const doAddPost: typeof import('../service/api/post')['doAddPost']
|
const doAddPost: typeof import('../service/api/post')['doAddPost']
|
||||||
|
const doCheckUserRepeat: typeof import('../service/api/auth')['doCheckUserRepeat']
|
||||||
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
||||||
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
||||||
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, reactive, ref} from 'vue';
|
import {computed, reactive, ref} from 'vue';
|
||||||
import {useI18n} from 'vue-i18n'; // 添加这行
|
import {useI18n} from 'vue-i18n';
|
||||||
import {useAuthStore} from '@/store/modules/auth';
|
import {useAuthStore} from '@/store/modules/auth';
|
||||||
import {useRouterPush} from '@/hooks/common/router';
|
import {useRouterPush} from '@/hooks/common/router';
|
||||||
import {useAntdForm, useFormRules} from '@/hooks/common/form';
|
import {useFormRules} from '@/hooks/common/form';
|
||||||
import {useCaptcha} from '@/hooks/business/captcha';
|
import {useCaptcha} from '@/hooks/business/captcha';
|
||||||
import {useWindowSize} from '@vueuse/core';
|
import {useWindowSize} from '@vueuse/core';
|
||||||
import {registerTerms} from '@/views/_builtin/login/modules/terms';
|
import {registerTerms} from '@/views/_builtin/login/modules/terms';
|
||||||
@@ -12,13 +12,15 @@ import type {Rule} from 'ant-design-vue/es/form';
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
// 添加两个表单引用
|
||||||
|
const basicFormRef = ref();
|
||||||
|
const securityFormRef = ref();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Register'
|
name: 'Register'
|
||||||
});
|
});
|
||||||
|
|
||||||
const { toggleLoginModule } = useRouterPush();
|
const { toggleLoginModule } = useRouterPush();
|
||||||
const { formRef, validate } = useAntdForm();
|
|
||||||
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
||||||
|
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
@@ -64,7 +66,6 @@ interface BasicFormModel {
|
|||||||
birthDate: string;
|
birthDate: string;
|
||||||
gender: string;
|
gender: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
email: string;
|
|
||||||
address: string;
|
address: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +75,6 @@ const basicModel = reactive<BasicFormModel>({
|
|||||||
birthDate: '',
|
birthDate: '',
|
||||||
gender: '',
|
gender: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
|
||||||
address: ''
|
address: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,21 +95,78 @@ const securityModel = reactive<SecurityFormModel>({
|
|||||||
|
|
||||||
// 第一步表单验证规则
|
// 第一步表单验证规则
|
||||||
const basicRules = computed<Record<string, Rule | Rule[]>>(() => {
|
const basicRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||||
const { formRules } = useFormRules();
|
const validateUsername = async (_rule: Rule, value: string) => {
|
||||||
|
if (value && (value.length < 4 || value.length > 20)) {
|
||||||
|
return Promise.reject(t('page.login.register.usernameLengthLimit'));
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ username: value });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.usernameExists'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePhone = async (_rule: Rule, value: string) => {
|
||||||
|
if (!value) return Promise.resolve();
|
||||||
|
|
||||||
|
const phonePattern = /^1[3-9]\d{9}$/;
|
||||||
|
|
||||||
|
if (!phonePattern.test(value)) {
|
||||||
|
return Promise.reject(t('page.login.register.phoneInvalid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ phonenumber: value });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.phoneExists'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
username: formRules.username,
|
username: [
|
||||||
email: formRules.email,
|
{ required: true, message: t('page.login.register.usernameRequired'), trigger: 'change' },
|
||||||
|
{ validator: validateUsername, trigger: 'blur' }
|
||||||
|
],
|
||||||
|
phone: [{ validator: validatePhone, trigger: 'blur' }],
|
||||||
birthDate: [{ required: true, message: t('page.login.register.birthDateRequired') }],
|
birthDate: [{ required: true, message: t('page.login.register.birthDateRequired') }],
|
||||||
phone: [{ pattern: /^1[3-9]\d{9}$/, message: t('form.phone.invalid'), trigger: 'blur' }]
|
fullName: []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// 第三步表单验证规则
|
// 第三步表单验证规则
|
||||||
const securityRules = computed<Record<string, Rule | Rule[]>>(() => {
|
const securityRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||||
const { formRules, createConfirmPwdRule } = useFormRules();
|
const { createConfirmPwdRule } = useFormRules();
|
||||||
|
|
||||||
|
const validateEmail = async (_rule: Rule, value: string) => {
|
||||||
|
if (!value) {
|
||||||
|
return Promise.reject(t('page.login.register.emailRequired'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
|
||||||
|
|
||||||
|
if (!emailPattern.test(value)) {
|
||||||
|
return Promise.reject(t('page.login.register.emailInvalid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ email: value });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.emailExists'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: formRules.code,
|
email: [
|
||||||
password: formRules.pwd,
|
{ required: true, message: t('page.login.register.emailRequired'), trigger: 'change' },
|
||||||
|
{ validator: validateEmail, trigger: 'blur' }
|
||||||
|
],
|
||||||
|
code: [{ required: true, message: t('page.login.register.codeRequired') }],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: t('page.login.register.passwordRequired') },
|
||||||
|
{ min: 6, message: t('page.login.register.passwordLength') }
|
||||||
|
],
|
||||||
confirmPassword: createConfirmPwdRule(securityModel.password)
|
confirmPassword: createConfirmPwdRule(securityModel.password)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -122,10 +179,10 @@ const terms = computed(() => {
|
|||||||
|
|
||||||
// 步骤控制函数
|
// 步骤控制函数
|
||||||
async function nextStep() {
|
async function nextStep() {
|
||||||
|
try {
|
||||||
if (currentStep.value === 0) {
|
if (currentStep.value === 0) {
|
||||||
await validate();
|
// 验证第一步表单
|
||||||
// 复制电话号码到第三步
|
await basicFormRef.value?.validate();
|
||||||
securityModel.email = basicModel.email;
|
|
||||||
}
|
}
|
||||||
if (currentStep.value === 1) {
|
if (currentStep.value === 1) {
|
||||||
if (!agreeTerms.value) {
|
if (!agreeTerms.value) {
|
||||||
@@ -133,23 +190,28 @@ async function nextStep() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 验证通过后增加步骤
|
||||||
currentStep.value += 1;
|
currentStep.value += 1;
|
||||||
|
} catch (error) {
|
||||||
|
// 验证失败时不增加步骤
|
||||||
|
console.error('Validation failed:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//返回
|
||||||
function prevStep() {
|
function prevStep() {
|
||||||
currentStep.value -= 1;
|
currentStep.value -= 1;
|
||||||
}
|
}
|
||||||
//注册按钮
|
//注册按钮
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
await validate();
|
await securityFormRef.value?.validate();
|
||||||
|
|
||||||
// 整合表单数据
|
// 整合表单数据
|
||||||
model.username = basicModel.username;
|
model.username = basicModel.username;
|
||||||
model.password = securityModel.password;
|
model.password = securityModel.password;
|
||||||
model.email = securityModel.email;
|
model.email = securityModel.email; // 使用第三步的 email
|
||||||
model.fullName = basicModel.fullName;
|
model.fullName = basicModel.fullName;
|
||||||
model.gender = basicModel.gender; // 直接使用 gender 值
|
model.gender = basicModel.gender;
|
||||||
model.phone = basicModel.phone;
|
model.phone = basicModel.phone;
|
||||||
model.address = basicModel.address;
|
model.address = basicModel.address;
|
||||||
model.code = securityModel.code;
|
model.code = securityModel.code;
|
||||||
@@ -157,7 +219,7 @@ async function handleSubmit() {
|
|||||||
const success = await authStore.register({
|
const success = await authStore.register({
|
||||||
...model,
|
...model,
|
||||||
age: dayjs().diff(dayjs(basicModel.birthDate), 'year'),
|
age: dayjs().diff(dayjs(basicModel.birthDate), 'year'),
|
||||||
sex: model.gender, // 直接使用 gender 值,不需要转换
|
sex: model.gender,
|
||||||
phonenumber: model.phone,
|
phonenumber: model.phone,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -175,6 +237,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div class="register-container">
|
||||||
<ASteps
|
<ASteps
|
||||||
v-if="showSteps"
|
v-if="showSteps"
|
||||||
:current="currentStep"
|
:current="currentStep"
|
||||||
@@ -200,9 +263,9 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
|
|
||||||
<div class="step-content">
|
<div class="step-content">
|
||||||
<!-- 第一步:基本信息 -->
|
<!-- 第一步:基本信息 -->
|
||||||
<div v-if="currentStep === 0">
|
<div v-show="currentStep === 0">
|
||||||
<AForm
|
<AForm
|
||||||
ref="formRef"
|
ref="basicFormRef"
|
||||||
:model="basicModel"
|
:model="basicModel"
|
||||||
:rules="basicRules"
|
:rules="basicRules"
|
||||||
:label-wrap="true"
|
:label-wrap="true"
|
||||||
@@ -243,11 +306,6 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
<AInput v-model:value="basicModel.phone" />
|
<AInput v-model:value="basicModel.phone" />
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</ACol>
|
</ACol>
|
||||||
<ACol :lg="24" :span="24">
|
|
||||||
<AFormItem name="email" :label="t('page.login.register.email')">
|
|
||||||
<AInput v-model:value="basicModel.email" />
|
|
||||||
</AFormItem>
|
|
||||||
</ACol>
|
|
||||||
<ACol :lg="24" :span="24">
|
<ACol :lg="24" :span="24">
|
||||||
<AFormItem name="address" :label="t('page.login.register.address')">
|
<AFormItem name="address" :label="t('page.login.register.address')">
|
||||||
<ATextarea v-model:value="basicModel.address" :rows="2" />
|
<ATextarea v-model:value="basicModel.address" :rows="2" />
|
||||||
@@ -268,7 +326,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 第二步:协议 -->
|
<!-- 第二步:协议 -->
|
||||||
<div v-if="currentStep === 1">
|
<div v-show="currentStep === 1">
|
||||||
<ATextarea
|
<ATextarea
|
||||||
:value="terms"
|
:value="terms"
|
||||||
:rows="12"
|
:rows="12"
|
||||||
@@ -296,9 +354,9 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 第三步:安全信息 -->
|
<!-- 第三步:安全信息 -->
|
||||||
<div v-if="currentStep === 2">
|
<div v-show="currentStep === 2">
|
||||||
<AForm
|
<AForm
|
||||||
ref="formRef"
|
ref="securityFormRef"
|
||||||
:model="securityModel"
|
:model="securityModel"
|
||||||
:rules="securityRules"
|
:rules="securityRules"
|
||||||
:label-wrap="true"
|
:label-wrap="true"
|
||||||
@@ -353,9 +411,22 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</AForm>
|
</AForm>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.register-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
:deep(.ant-form) {
|
:deep(.ant-form) {
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
|
|||||||
Reference in New Issue
Block a user