1 changed files with 104 additions and 0 deletions
@ -0,0 +1,104 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { clientRegisterSchema, type RegisterInput } from 'shared/auth-schema' |
||||
|
|
||||
|
const props = defineProps<{ |
||||
|
captchaSvg: string |
||||
|
captchaToken: string |
||||
|
}>() |
||||
|
|
||||
|
const emit = defineEmits<{ |
||||
|
'refresh-captcha': [] |
||||
|
success: [] |
||||
|
error: [message: string] |
||||
|
}>() |
||||
|
|
||||
|
const loading = ref(false) |
||||
|
const formRef = ref() |
||||
|
|
||||
|
const state = reactive<RegisterInput>({ |
||||
|
username: '', |
||||
|
password: '', |
||||
|
confirmPassword: '', |
||||
|
captchaText: '', |
||||
|
}) |
||||
|
|
||||
|
const password = computed(() => state.password) |
||||
|
|
||||
|
async function onSubmit() { |
||||
|
if (loading.value) return |
||||
|
loading.value = true |
||||
|
try { |
||||
|
const res = await $fetch<{ code: number; message: string; data: { id?: number; username?: string; field?: string } | null }>( |
||||
|
'/api/auth/register', |
||||
|
{ |
||||
|
method: 'POST', |
||||
|
body: { |
||||
|
username: state.username, |
||||
|
password: state.password, |
||||
|
confirmPassword: state.confirmPassword, |
||||
|
captchaToken: props.captchaToken, |
||||
|
captchaText: state.captchaText, |
||||
|
}, |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
if (res.code !== 0) { |
||||
|
const field = res.data && 'field' in (res.data || {}) ? (res.data as { field: string }).field : undefined |
||||
|
if (field && formRef.value) { |
||||
|
formRef.value.setFieldError(field, res.message) |
||||
|
} else { |
||||
|
emit('error', res.message) |
||||
|
} |
||||
|
// Auto-refresh captcha on captcha-related errors |
||||
|
if (res.message.includes('验证码')) { |
||||
|
emit('refresh-captcha') |
||||
|
state.captchaText = '' |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
emit('success') |
||||
|
} catch { |
||||
|
emit('error', '注册失败,请稍后重试') |
||||
|
} finally { |
||||
|
loading.value = false |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<UForm ref="formRef" :state="state" :schema="clientRegisterSchema" @submit="onSubmit"> |
||||
|
<UFormField name="username" label="用户名" required class="mb-4"> |
||||
|
<UInput v-model="state.username" placeholder="请输入用户名" :disabled="loading" /> |
||||
|
</UFormField> |
||||
|
|
||||
|
<PasswordInput |
||||
|
v-model="state.password" |
||||
|
label="密码" |
||||
|
placeholder="至少8个字符" |
||||
|
:disabled="loading" |
||||
|
class="mb-4" |
||||
|
/> |
||||
|
<PasswordStrength :password="password" /> |
||||
|
|
||||
|
<PasswordInput |
||||
|
v-model="state.confirmPassword" |
||||
|
label="确认密码" |
||||
|
placeholder="请再次输入密码" |
||||
|
:disabled="loading" |
||||
|
class="mb-4 mt-2" |
||||
|
/> |
||||
|
|
||||
|
<CaptchaField |
||||
|
v-model="state.captchaText" |
||||
|
:svg="captchaSvg" |
||||
|
:loading="loading" |
||||
|
class="mb-4" |
||||
|
@refresh="emit('refresh-captcha')" |
||||
|
/> |
||||
|
|
||||
|
<UButton type="submit" block :loading="loading" class="mt-6"> |
||||
|
{{ loading ? '注册中...' : '注册' }} |
||||
|
</UButton> |
||||
|
</UForm> |
||||
|
</template> |
||||
Loading…
Reference in new issue