flnxi-Wu/app/admin/_utils/validators.ts
WuYongJie e4dcb6260a
Some checks failed
CI Check / check (push) Has been cancelled
feat: Admin页面重构 & UI三层架构系统
- 创建统一UI三层架构系统(基础层、颜色层、组合层)
- 拆分Admin页面为独立Tab组件(MonitorTab、UsersTab、DepartmentsTab等)
- 提取公共逻辑到Hooks(useToast、useDataFetch、useUserOperations等)
- 提取工具函数(validators、formatters、api等)
- 创建统一弹窗组件(Modal)和useModal Hook
- 添加错误边界和统一状态组件
- 完善类型定义和可访问性支持
- 更新文档(优化记录、优化计划、更新日志)
2025-11-22 15:17:10 +08:00

171 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 表单验证工具函数
* 统一管理各种表单验证逻辑
*/
/**
* 验证结果接口
*/
export interface ValidationResult {
valid: boolean
error?: string
}
/**
* 验证字符串是否非空(去除空白字符后)
* @param value - 要验证的值
* @param fieldName - 字段名称,用于错误消息
* @returns 验证结果
*/
export function validateNotEmpty(value: string, fieldName: string = '字段'): ValidationResult {
const trimmed = value.trim()
if (!trimmed) {
return {
valid: false,
error: `${fieldName}不能为空`,
}
}
return { valid: true }
}
/**
* 验证部门名称
* @param name - 部门名称
* @returns 验证结果
*/
export function validateDepartmentName(name: string): ValidationResult {
return validateNotEmpty(name, '部门名称')
}
/**
* 验证用户邮箱
* @param email - 邮箱地址
* @returns 验证结果
*/
export function validateEmail(email: string): ValidationResult {
if (!email) {
return {
valid: false,
error: '邮箱不能为空',
}
}
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailPattern.test(email)) {
return {
valid: false,
error: '请输入有效的邮箱地址',
}
}
return { valid: true }
}
/**
* 验证字段键名(必须符合标识符规则)
* @param key - 字段键名
* @param index - 字段索引(可选,用于错误消息)
* @returns 验证结果
*/
export function validateFieldKey(key: string, index?: number): ValidationResult {
const trimmed = key.trim()
if (!trimmed) {
return {
valid: false,
error: index !== undefined ? `字段 ${index + 1} 的键名不能为空` : '字段键名不能为空',
}
}
// 键名必须以字母开头,只能包含字母、数字和下划线
const keyPattern = /^[a-zA-Z][a-zA-Z0-9_]*$/
if (!keyPattern.test(trimmed)) {
return {
valid: false,
error:
index !== undefined
? `字段 ${index + 1} 的键名需以字母开头,并仅包含字母、数字或下划线`
: '字段键名需以字母开头,并仅包含字母、数字或下划线',
}
}
return { valid: true }
}
/**
* 验证字段键名是否唯一
* @param keys - 所有字段键名数组
* @param currentIndex - 当前字段索引(可选)
* @returns 验证结果,如果发现重复则返回第一个重复的索引
*/
export function validateUniqueKeys(keys: string[], currentIndex?: number): ValidationResult {
const seenKeys = new Set<string>()
for (let i = 0; i < keys.length; i++) {
const trimmedKey = keys[i].trim()
if (!trimmedKey) {
continue // 空键名由 validateFieldKey 处理
}
if (seenKeys.has(trimmedKey)) {
return {
valid: false,
error: `字段键名 "${trimmedKey}" 已重复,请重新命名`,
}
}
seenKeys.add(trimmedKey)
}
return { valid: true }
}
/**
* 验证模板名称
* @param name - 模板名称
* @returns 验证结果
*/
export function validateTemplateName(name: string): ValidationResult {
return validateNotEmpty(name, '模板名称')
}
/**
* 验证密码(可选)
* @param password - 密码
* @param minLength - 最小长度,默认 0(不验证长度)
* @returns 验证结果
*/
export function validatePassword(password: string, minLength: number = 0): ValidationResult {
if (!password) {
return {
valid: false,
error: '密码不能为空',
}
}
if (minLength > 0 && password.length < minLength) {
return {
valid: false,
error: `密码长度至少为 ${minLength} 个字符`,
}
}
return { valid: true }
}
/**
* 组合多个验证结果
* @param results - 验证结果数组
* @returns 第一个失败的验证结果,或成功结果
*/
export function combineValidationResults(...results: ValidationResult[]): ValidationResult {
for (const result of results) {
if (!result.valid) {
return result
}
}
return { valid: true }
}