flnxi-Wu/lib/field-validation.ts
WuYongJie 63ec6b7dfb fix: 修复排行榜按钮消失、tag排序和输入框浅色模式问题
1. 排行榜悬浮窗关闭后小按钮消失问题
   - 修复面板居中模式关闭时按钮位置错误
   - 保存并恢复按钮的居中状态

2. 首页tag按钮按素材数量排序
   - 添加按素材数量降序排序逻辑

3. 上传弹窗输入框浅色模式文字不可见
   - 添加 text-slate-900 确保浅色模式下文字可见
   - 添加 placeholder 样式确保占位符正确显示
2025-12-14 21:41:29 +08:00

280 lines
7.1 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.

/**
* 字段验证规则配置和验证逻辑
*
* 支持的验证规则:
* - required: 必填验证
* - maxLength: 最大长度(text/textarea)
* - minLength: 最小长度(text/textarea)
* - min: 最小值(number)
* - max: 最大值(number)
* - pattern: 正则表达式验证
* - customMessage: 自定义错误提示
*/
export interface ValidationRule {
// 必填验证
required?: boolean
requiredMessage?: string
// 长度验证(text/textarea)
minLength?: number
minLengthMessage?: string
maxLength?: number
maxLengthMessage?: string
// 数值范围验证(number)
min?: number
minMessage?: string
max?: number
maxMessage?: string
// 正则表达式验证
pattern?: string
patternMessage?: string
// 通用自定义错误提示
customMessage?: string
}
export interface ValidationResult {
valid: boolean
errors: string[]
}
/**
* 解析验证规则JSON字符串
*/
export function parseValidationRules(validationsJson: string | null | undefined): ValidationRule | null {
if (!validationsJson || validationsJson.trim() === '') {
return null
}
try {
const parsed = JSON.parse(validationsJson)
if (typeof parsed !== 'object' || parsed === null) {
return null
}
return parsed as ValidationRule
} catch {
console.warn('[FieldValidation] Failed to parse validation rules:', validationsJson)
return null
}
}
/**
* 序列化验证规则为JSON字符串
*/
export function serializeValidationRules(rules: ValidationRule | null): string {
if (!rules) {
return ''
}
// 清理空值
const cleanedRules: ValidationRule = {}
if (rules.required) cleanedRules.required = true
if (rules.requiredMessage) cleanedRules.requiredMessage = rules.requiredMessage
if (typeof rules.minLength === 'number' && rules.minLength > 0) {
cleanedRules.minLength = rules.minLength
if (rules.minLengthMessage) cleanedRules.minLengthMessage = rules.minLengthMessage
}
if (typeof rules.maxLength === 'number' && rules.maxLength > 0) {
cleanedRules.maxLength = rules.maxLength
if (rules.maxLengthMessage) cleanedRules.maxLengthMessage = rules.maxLengthMessage
}
if (typeof rules.min === 'number') {
cleanedRules.min = rules.min
if (rules.minMessage) cleanedRules.minMessage = rules.minMessage
}
if (typeof rules.max === 'number') {
cleanedRules.max = rules.max
if (rules.maxMessage) cleanedRules.maxMessage = rules.maxMessage
}
if (rules.pattern) {
cleanedRules.pattern = rules.pattern
if (rules.patternMessage) cleanedRules.patternMessage = rules.patternMessage
}
if (rules.customMessage) cleanedRules.customMessage = rules.customMessage
// 如果没有任何规则,返回空字符串
if (Object.keys(cleanedRules).length === 0) {
return ''
}
return JSON.stringify(cleanedRules)
}
/**
* 验证单个字段值
*/
export function validateFieldValue(
value: unknown,
fieldType: string,
rules: ValidationRule | null,
fieldLabel?: string
): ValidationResult {
const errors: string[] = []
const label = fieldLabel || '此字段'
if (!rules) {
return { valid: true, errors: [] }
}
const stringValue = value === null || value === undefined ? '' : String(value).trim()
const isEmpty = stringValue === ''
// 必填验证
if (rules.required && isEmpty) {
errors.push(rules.requiredMessage || `${label}不能为空`)
// 如果必填且为空,不继续其他验证
return { valid: false, errors }
}
// 如果值为空且非必填,跳过其他验证
if (isEmpty) {
return { valid: true, errors: [] }
}
// 文本长度验证
if (fieldType === 'text' || fieldType === 'textarea') {
if (typeof rules.minLength === 'number' && stringValue.length < rules.minLength) {
errors.push(rules.minLengthMessage || `${label}长度不能少于${rules.minLength}个字符`)
}
if (typeof rules.maxLength === 'number' && stringValue.length > rules.maxLength) {
errors.push(rules.maxLengthMessage || `${label}长度不能超过${rules.maxLength}个字符`)
}
}
// 数值范围验证
if (fieldType === 'number') {
const numValue = parseFloat(stringValue)
if (isNaN(numValue)) {
errors.push(`${label}必须是有效的数字`)
} else {
if (typeof rules.min === 'number' && numValue < rules.min) {
errors.push(rules.minMessage || `${label}不能小于${rules.min}`)
}
if (typeof rules.max === 'number' && numValue > rules.max) {
errors.push(rules.maxMessage || `${label}不能大于${rules.max}`)
}
}
}
// 正则表达式验证
if (rules.pattern) {
try {
const regex = new RegExp(rules.pattern)
if (!regex.test(stringValue)) {
errors.push(rules.patternMessage || `${label}格式不正确`)
}
} catch (e) {
console.warn('[FieldValidation] Invalid regex pattern:', rules.pattern)
}
}
return {
valid: errors.length === 0,
errors
}
}
/**
* 验证多个字段
*/
export function validateFields(
fields: Array<{
key: string
label: string
type: string
validations?: string | null
value: unknown
}>
): Map<string, ValidationResult> {
const results = new Map<string, ValidationResult>()
for (const field of fields) {
const rules = parseValidationRules(field.validations)
const result = validateFieldValue(field.value, field.type, rules, field.label)
results.set(field.key, result)
}
return results
}
/**
* 检查验证规则是否有效(用于保存模板时)
*/
export function validateValidationRules(rules: ValidationRule): { valid: boolean; error?: string } {
// 检查长度规则冲突
if (typeof rules.minLength === 'number' && typeof rules.maxLength === 'number') {
if (rules.minLength > rules.maxLength) {
return { valid: false, error: '最小长度不能大于最大长度' }
}
}
// 检查数值范围规则冲突
if (typeof rules.min === 'number' && typeof rules.max === 'number') {
if (rules.min > rules.max) {
return { valid: false, error: '最小值不能大于最大值' }
}
}
// 检查正则表达式是否有效
if (rules.pattern) {
try {
new RegExp(rules.pattern)
} catch {
return { valid: false, error: '正则表达式格式无效' }
}
}
return { valid: true }
}
/**
* 获取字段类型支持的验证规则
*/
export function getSupportedValidations(fieldType: string): string[] {
const common = ['required']
switch (fieldType) {
case 'text':
case 'textarea':
return [...common, 'minLength', 'maxLength', 'pattern']
case 'number':
return [...common, 'min', 'max']
case 'select':
case 'checkbox':
case 'radio':
return common
case 'date':
return common
case 'file':
case 'image':
return common
default:
return common
}
}
/**
* 默认验证规则
*/
export const DEFAULT_VALIDATION_RULES: ValidationRule = {
required: false,
minLength: undefined,
maxLength: undefined,
min: undefined,
max: undefined,
pattern: undefined,
}