57 lines
2.3 KiB
TypeScript
57 lines
2.3 KiB
TypeScript
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
|
|
}
|