Merge branch 'NyaDoo/master'

This commit is contained in:
fawney19
2026-01-28 00:10:00 +08:00
5 changed files with 55 additions and 9 deletions

View File

@@ -135,7 +135,14 @@
required required
disable-autofill disable-autofill
:disabled="isLoading" :disabled="isLoading"
:class="usernameError ? 'border-destructive' : ''"
/> />
<p
v-if="usernameError"
class="text-xs text-destructive"
>
{{ usernameError }}
</p>
</div> </div>
<!-- Password --> <!-- Password -->
@@ -367,6 +374,17 @@ const sendCodeButtonText = computed(() => {
return '发送验证码' return '发送验证码'
}) })
// 用户名验证
const usernameRegex = /^[a-zA-Z0-9_.\-]+$/
const usernameError = computed(() => {
const username = formData.value.username.trim()
if (!username) return ''
if (username.length < 3) return '用户名长度至少为3个字符'
if (username.length > 30) return '用户名长度不能超过30个字符'
if (!usernameRegex.test(username)) return '用户名只能包含字母、数字、下划线、连字符和点号'
return ''
})
const canSubmit = computed(() => { const canSubmit = computed(() => {
// 基本信息:用户名和密码必填 // 基本信息:用户名和密码必填
const hasBasicInfo = const hasBasicInfo =
@@ -376,6 +394,9 @@ const canSubmit = computed(() => {
if (!hasBasicInfo) return false if (!hasBasicInfo) return false
// 用户名格式验证
if (usernameError.value) return false
// 如果需要邮箱验证,邮箱和验证都必须完成 // 如果需要邮箱验证,邮箱和验证都必须完成
if (props.requireEmailVerification) { if (props.requireEmailVerification) {
if (!formData.value.email || !emailVerified.value) { if (!formData.value.email || !emailVerified.value) {

View File

@@ -53,7 +53,20 @@
data-form-type="other" data-form-type="other"
required required
class="h-10" class="h-10"
:class="usernameError ? 'border-destructive' : ''"
/> />
<p
v-if="usernameError"
class="text-xs text-destructive"
>
{{ usernameError }}
</p>
<p
v-else
class="text-xs text-muted-foreground"
>
3-30个字符允许字母数字下划线连字符和点号
</p>
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
@@ -468,13 +481,25 @@ const { isEditMode, handleDialogUpdate, handleCancel } = useFormDialog({
resetForm, resetForm,
}) })
// 用户名验证
const usernameRegex = /^[a-zA-Z0-9_.\-]+$/
const usernameError = computed(() => {
const username = form.value.username.trim()
if (!username) return ''
if (username.length < 3) return '用户名长度至少为3个字符'
if (username.length > 30) return '用户名长度不能超过30个字符'
if (!usernameRegex.test(username)) return '用户名只能包含字母、数字、下划线、连字符和点号'
return ''
})
// 表单验证 // 表单验证
const isFormValid = computed(() => { const isFormValid = computed(() => {
const hasUsername = form.value.username.trim().length > 0 const hasUsername = form.value.username.trim().length > 0
const usernameValid = !usernameError.value
const hasPassword = isEditMode.value || form.value.password.length >= 6 const hasPassword = isEditMode.value || form.value.password.length >= 6
// 编辑模式下如果填写了密码,必须确认密码一致 // 编辑模式下如果填写了密码,必须确认密码一致
const passwordConfirmed = !isEditMode.value || form.value.password.length === 0 || form.value.password === form.value.confirmPassword const passwordConfirmed = !isEditMode.value || form.value.password.length === 0 || form.value.password === form.value.confirmPassword
return hasUsername && hasPassword && passwordConfirmed return hasUsername && usernameValid && hasPassword && passwordConfirmed
}) })
// 加载访问控制选项 // 加载访问控制选项

View File

@@ -136,7 +136,7 @@ class UsernameValidator:
MIN_LENGTH = 3 MIN_LENGTH = 3
MAX_LENGTH = 30 MAX_LENGTH = 30
USERNAME_REGEX = re.compile(r"^[a-zA-Z0-9_-]+$") USERNAME_REGEX = re.compile(r"^[a-zA-Z0-9_.\-]+$")
@classmethod @classmethod
def validate(cls, username: str) -> tuple[bool, Optional[str]]: def validate(cls, username: str) -> tuple[bool, Optional[str]]:
@@ -159,7 +159,7 @@ class UsernameValidator:
return False, f"用户名长度不能超过{cls.MAX_LENGTH}个字符" return False, f"用户名长度不能超过{cls.MAX_LENGTH}个字符"
if not cls.USERNAME_REGEX.match(username): if not cls.USERNAME_REGEX.match(username):
return False, "用户名只能包含字母、数字、下划线连字符" return False, "用户名只能包含字母、数字、下划线连字符和点号"
# 检查保留用户名 # 检查保留用户名
reserved_names = [ reserved_names = [

View File

@@ -320,8 +320,8 @@ class UpdateUserRequest(BaseModel):
if v is None: if v is None:
return v return v
if not re.match(r"^[a-zA-Z0-9_-]+$", v): if not re.match(r"^[a-zA-Z0-9_.\-]+$", v):
raise ValueError("用户名只能包含字母、数字、下划线连字符") raise ValueError("用户名只能包含字母、数字、下划线连字符和点号")
return v return v

View File

@@ -103,8 +103,8 @@ class RegisterRequest(BaseModel):
v = v.strip() v = v.strip()
if not v: if not v:
raise ValueError("用户名不能为空") raise ValueError("用户名不能为空")
if not re.match(r"^[a-zA-Z0-9_-]+$", v): if not re.match(r"^[a-zA-Z0-9_.\-]+$", v):
raise ValueError("用户名只能包含字母、数字、下划线和短横线") raise ValueError("用户名只能包含字母、数字、下划线、连字符和点号")
return v return v
@classmethod @classmethod
@@ -279,8 +279,8 @@ class CreateUserRequest(BaseModel):
v = v.strip() v = v.strip()
if not v: if not v:
raise ValueError("用户名不能为空") raise ValueError("用户名不能为空")
if not re.match(r"^[a-zA-Z0-9_-]+$", v): if not re.match(r"^[a-zA-Z0-9_.\-]+$", v):
raise ValueError("用户名只能包含字母、数字、下划线和短横线") raise ValueError("用户名只能包含字母、数字、下划线、连字符和点号")
return v return v
@classmethod @classmethod