You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.2 KiB
122 lines
3.2 KiB
<script setup lang="ts">
|
|
import type { FormError, FormSubmitEvent } from '@nuxt/ui'
|
|
import { request, unwrapApiBody } from '../../utils/http/factory'
|
|
|
|
definePageMeta({
|
|
title: '注册',
|
|
layout: 'not-login',
|
|
})
|
|
|
|
type RegisterFormState = {
|
|
username: string
|
|
password: string
|
|
}
|
|
|
|
const USERNAME_REGEX = /^[a-zA-Z0-9_]{3,20}$/
|
|
|
|
const state = reactive<RegisterFormState>({
|
|
username: '',
|
|
password: '',
|
|
})
|
|
|
|
const loading = ref(false)
|
|
const resultType = ref<'error' | ''>('')
|
|
const resultMessage = ref('')
|
|
|
|
const validate = (formState: RegisterFormState): FormError[] => {
|
|
const errors: FormError[] = []
|
|
|
|
if (!formState.username) {
|
|
errors.push({ name: 'username', message: '请输入用户名' })
|
|
} else if (!USERNAME_REGEX.test(formState.username)) {
|
|
errors.push({ name: 'username', message: '用户名需为 3-20 位字母、数字或下划线' })
|
|
}
|
|
|
|
if (!formState.password) {
|
|
errors.push({ name: 'password', message: '请输入密码' })
|
|
} else if (formState.password.length < 6) {
|
|
errors.push({ name: 'password', message: '密码至少 6 位' })
|
|
}
|
|
|
|
return errors
|
|
}
|
|
|
|
const onSubmit = async (_event: FormSubmitEvent<RegisterFormState>) => {
|
|
resultType.value = ''
|
|
resultMessage.value = ''
|
|
loading.value = true
|
|
|
|
try {
|
|
unwrapApiBody(await request('/api/auth/register', {
|
|
method: 'POST',
|
|
body: {
|
|
username: state.username,
|
|
password: state.password,
|
|
},
|
|
}))
|
|
|
|
await navigateTo('/login')
|
|
} catch (error: unknown) {
|
|
const message = typeof error === 'object' && error !== null && 'statusMessage' in error
|
|
? String(error.statusMessage)
|
|
: '注册失败,请稍后重试'
|
|
|
|
resultType.value = 'error'
|
|
resultMessage.value = message
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="max-w-md mx-auto py-10">
|
|
<UCard>
|
|
<template #header>
|
|
<div class="space-y-1">
|
|
<h1 class="text-xl font-semibold">创建账号</h1>
|
|
<p class="text-sm text-muted">请输入用户名和密码完成注册</p>
|
|
</div>
|
|
</template>
|
|
|
|
<UForm :state="state" :validate="validate" class="space-y-4" @submit="onSubmit">
|
|
<UFormField label="用户名" name="username" required>
|
|
<UInput
|
|
v-model="state.username"
|
|
placeholder="请输入用户名"
|
|
autocomplete="username"
|
|
class="w-full"
|
|
/>
|
|
</UFormField>
|
|
|
|
<UFormField label="密码" name="password" required>
|
|
<UInput
|
|
v-model="state.password"
|
|
type="password"
|
|
placeholder="请输入密码"
|
|
autocomplete="new-password"
|
|
class="w-full"
|
|
/>
|
|
</UFormField>
|
|
|
|
<UButton type="submit" block :loading="loading">
|
|
立即注册
|
|
</UButton>
|
|
</UForm>
|
|
|
|
<UAlert
|
|
v-if="resultType"
|
|
color="error"
|
|
title="操作失败"
|
|
:description="resultMessage"
|
|
class="mt-4"
|
|
/>
|
|
|
|
<div class="mt-4 flex items-center justify-between text-sm">
|
|
<NuxtLink to="/login" class="text-primary hover:underline">
|
|
已有账号,去登录
|
|
</NuxtLink>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
</template>
|
|
|