import { getTemplateWithFields, isBuiltinTemplate } from './template-validator' import { filterVisibleFieldValues, getVisibleTemplateFields, hasFieldValue } from './field-conditions' import { parseValidationRules, validateFieldValue } from './field-validation' import { validateSubmittedTemplateFieldsWithPaidCore } from './license/premium-module-service' type TemplateFieldLike = { key: string label?: string | null type?: string | null required?: boolean | null conditions?: string | null validations?: string | null } export type TemplateFieldValidationResult = | { valid: true templateName?: string templateFields: Record visibleFieldKeys: string[] } | { valid: false error: string errorCode: string details?: Record } export { hasFieldValue } from './field-conditions' function validateSubmittedTemplateFieldsLocally(args: { templateId: string templateName?: string fields: TemplateFieldLike[] templateFields: Record allowUnknownKeys: boolean }): TemplateFieldValidationResult { const { templateId, templateName, fields, templateFields, allowUnknownKeys } = args const fieldMap = new Map(fields.map((field) => [field.key, field])) const visibleFields = getVisibleTemplateFields(fields, templateFields) const visibleTemplateFields = filterVisibleFieldValues(fields, templateFields) if (!allowUnknownKeys) { const unknownKeys = Object.keys(templateFields).filter((key) => !fieldMap.has(key)) if (unknownKeys.length > 0) { return { valid: false, error: `提交了模板中不存在的字段:${unknownKeys.join(', ')}`, errorCode: 'UNKNOWN_TEMPLATE_FIELDS', details: { unknownKeys, templateId, }, } } } const missingRequiredFields = visibleFields .filter((field) => field.required) .filter((field) => !hasFieldValue(visibleTemplateFields[field.key], field.type)) .map((field) => ({ key: field.key, label: field.label || field.key, type: field.type || 'text', })) if (missingRequiredFields.length > 0) { return { valid: false, error: `模板必填字段未填写:${missingRequiredFields.map((field) => field.label).join('、')}`, errorCode: 'TEMPLATE_REQUIRED_FIELDS_MISSING', details: { templateId, missingRequiredFields, }, } } const invalidFields = visibleFields .map((field) => { const result = validateFieldValue( visibleTemplateFields[field.key], field.type || 'text', parseValidationRules(field.validations), field.label || field.key ) return { key: field.key, label: field.label || field.key, type: field.type || 'text', errors: result.errors, } }) .filter((field) => field.errors.length > 0) if (invalidFields.length > 0) { return { valid: false, error: `模板字段填写不符合规则:${invalidFields.map((field) => `${field.label}:${field.errors.join('、')}`).join(';')}`, errorCode: 'TEMPLATE_FIELD_VALIDATION_FAILED', details: { templateId, invalidFields, }, } } return { valid: true, templateName, templateFields: visibleTemplateFields, visibleFieldKeys: visibleFields.map((field) => field.key), } } export async function validateSubmittedTemplateFields(args: { templateId: string | null | undefined templateFields: Record allowUnknownKeys?: boolean }): Promise { const { templateId, templateFields, allowUnknownKeys = true } = args if (!templateId) { return { valid: true, templateFields, visibleFieldKeys: Object.keys(templateFields), } } const template = await getTemplateWithFields(templateId) if (!template) { return { valid: false, error: '模板不存在或不可用', errorCode: 'TEMPLATE_NOT_FOUND', } } const fields = (template.fields || []) as TemplateFieldLike[] const templateName = typeof template.name === 'string' ? template.name : undefined if (!isBuiltinTemplate(templateId)) { return validateSubmittedTemplateFieldsWithPaidCore({ templateId, templateName, fields, templateFields, allowUnknownKeys, }) } return validateSubmittedTemplateFieldsLocally({ templateId, templateName, fields, templateFields, allowUnknownKeys, }) }