feat: update

This commit is contained in:
2025-11-06 16:37:01 +08:00
parent c0d54b8513
commit 855f289579
59 changed files with 3398 additions and 572 deletions

111
schemas/auth.ts Normal file
View File

@@ -0,0 +1,111 @@
/**
* 认证相关的 Zod 验证 Schema
*/
import { z } from 'zod';
/**
* 登录表单 Schema
*/
export const loginSchema = z.object({
email: z.string().min(1, '请输入邮箱').email('请输入有效的邮箱地址'),
password: z.string().min(6, '密码至少6个字符').max(20, '密码最多20个字符'),
rememberMe: z.boolean().optional(),
});
/**
* 注册表单 Schema
*/
export const registerSchema = z
.object({
username: z
.string()
.min(3, '用户名至少3个字符')
.max(20, '用户名最多20个字符')
.regex(/^[a-zA-Z0-9_]+$/, '用户名只能包含字母、数字和下划线'),
email: z.string().min(1, '请输入邮箱').email('请输入有效的邮箱地址'),
password: z
.string()
.min(6, '密码至少6个字符')
.max(20, '密码最多20个字符')
.regex(/[A-Z]/, '密码必须包含至少一个大写字母')
.regex(/[a-z]/, '密码必须包含至少一个小写字母')
.regex(/[0-9]/, '密码必须包含至少一个数字'),
confirmPassword: z.string().min(1, '请确认密码'),
agreeToTerms: z.boolean().refine((val) => val === true, {
message: '请同意服务条款',
}),
})
.refine((data) => data.password === data.confirmPassword, {
message: '两次输入的密码不一致',
path: ['confirmPassword'],
});
/**
* 忘记密码 Schema
*/
export const forgotPasswordSchema = z.object({
email: z.string().min(1, '请输入邮箱').email('请输入有效的邮箱地址'),
});
/**
* 重置密码 Schema
*/
export const resetPasswordSchema = z
.object({
code: z
.string()
.min(6, '验证码为6位')
.max(6, '验证码为6位')
.regex(/^\d{6}$/, '验证码必须是6位数字'),
password: z.string().min(6, '密码至少6个字符').max(20, '密码最多20个字符'),
confirmPassword: z.string().min(1, '请确认密码'),
})
.refine((data) => data.password === data.confirmPassword, {
message: '两次输入的密码不一致',
path: ['confirmPassword'],
});
/**
* 修改密码 Schema
*/
export const changePasswordSchema = z
.object({
oldPassword: z.string().min(1, '请输入当前密码'),
newPassword: z.string().min(6, '新密码至少6个字符').max(20, '新密码最多20个字符'),
confirmPassword: z.string().min(1, '请确认新密码'),
})
.refine((data) => data.newPassword === data.confirmPassword, {
message: '两次输入的密码不一致',
path: ['confirmPassword'],
})
.refine((data) => data.oldPassword !== data.newPassword, {
message: '新密码不能与当前密码相同',
path: ['newPassword'],
});
/**
* 手机号登录 Schema
*/
export const phoneLoginSchema = z.object({
phone: z
.string()
.min(11, '请输入11位手机号')
.max(11, '请输入11位手机号')
.regex(/^1[3-9]\d{9}$/, '请输入有效的手机号'),
code: z
.string()
.min(6, '验证码为6位')
.max(6, '验证码为6位')
.regex(/^\d{6}$/, '验证码必须是6位数字'),
});
/**
* TypeScript 类型推断
*/
export type LoginFormData = z.infer<typeof loginSchema>;
export type RegisterFormData = z.infer<typeof registerSchema>;
export type ForgotPasswordFormData = z.infer<typeof forgotPasswordSchema>;
export type ResetPasswordFormData = z.infer<typeof resetPasswordSchema>;
export type ChangePasswordFormData = z.infer<typeof changePasswordSchema>;
export type PhoneLoginFormData = z.infer<typeof phoneLoginSchema>;

36
schemas/index.ts Normal file
View File

@@ -0,0 +1,36 @@
/**
* Schemas 模块统一导出
*/
// Auth Schemas
export {
loginSchema,
registerSchema,
forgotPasswordSchema,
resetPasswordSchema,
changePasswordSchema,
phoneLoginSchema,
} from './auth';
export type {
LoginFormData,
RegisterFormData,
ForgotPasswordFormData,
ResetPasswordFormData,
ChangePasswordFormData,
PhoneLoginFormData,
} from './auth';
// User Schemas
export {
userSchema,
updateUserSchema,
bindPhoneSchema,
bindEmailSchema,
} from './user';
export type {
UserFormData,
UpdateUserFormData,
BindPhoneFormData,
BindEmailFormData,
} from './user';

68
schemas/user.ts Normal file
View File

@@ -0,0 +1,68 @@
/**
* 用户相关的 Zod 验证 Schema
*/
import { z } from 'zod';
/**
* 用户信息 Schema
*/
export const userSchema = z.object({
id: z.string(),
username: z.string(),
email: z.string().email(),
avatar: z.string().url().optional(),
nickname: z.string().optional(),
phone: z.string().optional(),
createdAt: z.string().optional(),
});
/**
* 更新用户资料 Schema
*/
export const updateProfileSchema = z.object({
nickname: z.string().min(2, '昵称至少2个字符').max(20, '昵称最多20个字符').optional(),
avatar: z.string().url('请输入有效的头像URL').optional(),
phone: z
.string()
.regex(/^1[3-9]\d{9}$/, '请输入有效的手机号')
.optional()
.or(z.literal('')),
bio: z.string().max(200, '个人简介最多200个字符').optional(),
});
/**
* 绑定手机号 Schema
*/
export const bindPhoneSchema = z.object({
phone: z
.string()
.min(11, '请输入11位手机号')
.max(11, '请输入11位手机号')
.regex(/^1[3-9]\d{9}$/, '请输入有效的手机号'),
code: z
.string()
.min(6, '验证码为6位')
.max(6, '验证码为6位')
.regex(/^\d{6}$/, '验证码必须是6位数字'),
});
/**
* 绑定邮箱 Schema
*/
export const bindEmailSchema = z.object({
email: z.string().min(1, '请输入邮箱').email('请输入有效的邮箱地址'),
code: z
.string()
.min(6, '验证码为6位')
.max(6, '验证码为6位')
.regex(/^\d{6}$/, '验证码必须是6位数字'),
});
/**
* TypeScript 类型推断
*/
export type User = z.infer<typeof userSchema>;
export type UpdateProfileFormData = z.infer<typeof updateProfileSchema>;
export type BindPhoneFormData = z.infer<typeof bindPhoneSchema>;
export type BindEmailFormData = z.infer<typeof bindEmailSchema>;