import { isValidEmail, type WidgetFormField } from '../types/widget' /** Validate a widget form field with the same value normalization and bounds * used by backend/app/api/widget_chat.py before accepting a form submission. */ export function validateWidgetFormField(field: WidgetFormField, value: unknown): string | null { const label = field.label || field.name const valueString = value === null || value === undefined ? '' : String(value).trim() if (field.required && valueString === '') { return `${label} 为必填项` } if (valueString === '') return null if (field.type === 'email' && !isValidEmail(valueString)) { return '请输入有效的邮箱地址' } if (field.type === 'tel') { const digits = valueString.replace(/\D/g, '') if (digits.length < 7 || digits.length > 15) return '请输入有效的电话号码' } if (field.type === 'text' || field.type === 'textarea') { const valueLength = [...valueString].length if (field.minLength != null && valueLength < field.minLength) { return `${label} 至少需要 ${field.minLength} 个字符` } // Match the server's text-field contract: maxLength=0 disables the bound. if (field.maxLength && valueLength > field.maxLength) { return `${label} 不能超过 ${field.maxLength} 个字符` } } if (field.type === 'number') { const numberPattern = /^[+-]?(?:(?:\d(?:_?\d)*(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:e[+-]?\d(?:_?\d)*)?|inf(?:inity)?|nan)$/i if (!numberPattern.test(valueString)) return `${label} 必须是有效数字` const specialNumber = /^[+-]?(?:inf(?:inity)?|nan)$/i.test(valueString) const lowerValue = valueString.toLowerCase() const numberValue = specialNumber ? lowerValue.endsWith('nan') ? Number.NaN : valueString.startsWith('-') ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY : Number(valueString.replace(/_/g, '')) const minimum = field.minLength === undefined ? 0 : field.minLength const maximum = field.maxLength === undefined ? null : field.maxLength if (minimum !== null && numberValue < minimum) { return `${label} 不能小于 ${minimum}` } if (maximum !== null && numberValue > maximum) { return `${label} 不能大于 ${maximum}` } } return null }