|
|
@ -19,6 +19,7 @@ definePageMeta({ |
|
|
type RegisterFormState = { |
|
|
type RegisterFormState = { |
|
|
username: string |
|
|
username: string |
|
|
password: string |
|
|
password: string |
|
|
|
|
|
captchaAnswer: string |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/ |
|
|
const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/ |
|
|
@ -26,6 +27,25 @@ const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/ |
|
|
const state = reactive<RegisterFormState>({ |
|
|
const state = reactive<RegisterFormState>({ |
|
|
username: '', |
|
|
username: '', |
|
|
password: '', |
|
|
password: '', |
|
|
|
|
|
captchaAnswer: '', |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const captchaIdRef = ref('') |
|
|
|
|
|
const captchaImageSrc = ref('') |
|
|
|
|
|
|
|
|
|
|
|
async function refreshCaptcha() { |
|
|
|
|
|
state.captchaAnswer = '' |
|
|
|
|
|
captchaImageSrc.value = '' |
|
|
|
|
|
const res = await fetchData<{ captchaId: string; imageSvg: string }>('/api/auth/captcha', { |
|
|
|
|
|
method: 'GET', |
|
|
|
|
|
notify: false, |
|
|
|
|
|
}) |
|
|
|
|
|
captchaIdRef.value = res.captchaId |
|
|
|
|
|
captchaImageSrc.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(res.imageSvg)}` |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
|
|
void refreshCaptcha() |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
const loading = ref(false) |
|
|
const loading = ref(false) |
|
|
@ -49,6 +69,10 @@ const validate = (formState: RegisterFormState): FormError[] => { |
|
|
errors.push({ name: 'password', message: '密码至少 6 位' }) |
|
|
errors.push({ name: 'password', message: '密码至少 6 位' }) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!formState.captchaAnswer?.trim()) { |
|
|
|
|
|
errors.push({ name: 'captchaAnswer', message: '请输入验证码' }) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return errors |
|
|
return errors |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -60,7 +84,12 @@ const onSubmit = async (_event: FormSubmitEvent<RegisterFormState>) => { |
|
|
try { |
|
|
try { |
|
|
await fetchData<unknown>('/api/auth/register', { |
|
|
await fetchData<unknown>('/api/auth/register', { |
|
|
method: 'POST', |
|
|
method: 'POST', |
|
|
body: { username: state.username, password: state.password }, |
|
|
body: { |
|
|
|
|
|
username: state.username, |
|
|
|
|
|
password: state.password, |
|
|
|
|
|
captchaId: captchaIdRef.value, |
|
|
|
|
|
captchaAnswer: state.captchaAnswer, |
|
|
|
|
|
}, |
|
|
notify: false, |
|
|
notify: false, |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
@ -75,6 +104,11 @@ const onSubmit = async (_event: FormSubmitEvent<RegisterFormState>) => { |
|
|
} catch (error: unknown) { |
|
|
} catch (error: unknown) { |
|
|
resultType.value = 'error' |
|
|
resultType.value = 'error' |
|
|
resultMessage.value = getApiErrorMessage(error) |
|
|
resultMessage.value = getApiErrorMessage(error) |
|
|
|
|
|
try { |
|
|
|
|
|
await refreshCaptcha() |
|
|
|
|
|
} catch { |
|
|
|
|
|
/* ignore captcha refresh errors */ |
|
|
|
|
|
} |
|
|
} finally { |
|
|
} finally { |
|
|
loading.value = false |
|
|
loading.value = false |
|
|
} |
|
|
} |
|
|
@ -119,6 +153,26 @@ const onSubmit = async (_event: FormSubmitEvent<RegisterFormState>) => { |
|
|
/> |
|
|
/> |
|
|
</UFormField> |
|
|
</UFormField> |
|
|
|
|
|
|
|
|
|
|
|
<UFormField label="验证码" name="captchaAnswer" required> |
|
|
|
|
|
<div class="flex flex-wrap gap-2 items-center"> |
|
|
|
|
|
<img |
|
|
|
|
|
v-if="captchaImageSrc" |
|
|
|
|
|
:src="captchaImageSrc" |
|
|
|
|
|
alt="验证码" |
|
|
|
|
|
class="h-10 rounded border border-default bg-elevated shrink-0" |
|
|
|
|
|
/> |
|
|
|
|
|
<UInput |
|
|
|
|
|
v-model="state.captchaAnswer" |
|
|
|
|
|
placeholder="请输入图中字符" |
|
|
|
|
|
class="flex-1 min-w-[8rem]" |
|
|
|
|
|
autocomplete="off" |
|
|
|
|
|
/> |
|
|
|
|
|
<UButton type="button" color="neutral" variant="outline" class="shrink-0" @click="refreshCaptcha"> |
|
|
|
|
|
换一张 |
|
|
|
|
|
</UButton> |
|
|
|
|
|
</div> |
|
|
|
|
|
</UFormField> |
|
|
|
|
|
|
|
|
<UButton type="submit" block :loading="loading"> |
|
|
<UButton type="submit" block :loading="loading"> |
|
|
立即注册 |
|
|
立即注册 |
|
|
</UButton> |
|
|
</UButton> |
|
|
|