d-render
Version:
基于 Element Plus 二次封装的数据驱动渲染组件库 - 表单、搜索表单、表格配置化渲染
131 lines (126 loc) • 4.87 kB
text/typescript
// 可以转换的validateType
import {
createValidators
} from './form-validator'
import type { TValidator } from './form-validator'
import type { IAnyObject, TFormConfig, IRenderConfig, ICustomValidator } from '@d-render/shared'
import type { FormItemRule } from 'element-plus'
import { defaultLocale, translate, type Translator } from '../locale'
const fallbackT: Translator = (path, option) => translate(path, option, defaultLocale)
const isInputType = (config: TFormConfig) => {
if (config.triggerType === 'input') { return true }
if (config.triggerType === 'select') { return false }
// 兼容老的未设置triggerType的表单数据验证
return ['input', 'textarea', 'number', 'numberRange', 'table', 'password', undefined].includes(config.type)
}
export interface RequiredRule {
type?: string
required?: boolean
message?: string
[propname: string]: unknown
}
// 获取单字段规则
export const getRulesByFieldConfig = (
config: TFormConfig,
otherValue: unknown,
dependOnValues: IAnyObject,
outDependOnValues: IAnyObject,
t: Translator = fallbackT
) => {
const rules = [] as FormItemRule[]
const validatorMap: Record<string, TValidator> = createValidators(t)
if (config.required) { // 必填
const defaultMessage = isInputType(config)
? t('dr.form.requiredInput', { label: config.label ?? '' })
: t('dr.form.requiredSelect', { label: config.label ?? '' })
const requiredMessage = config.requiredErrorMessage || defaultMessage
const requiredRule = { required: true, message: requiredMessage, ...config.requiredRuleConfig as IAnyObject } as FormItemRule
if (config.requiredType) {
requiredRule.type = config.requiredType
}
rules.push(requiredRule)
// 双值验证
if (config.type === 'dateRange' && config.otherKey) { // 日期范围
const validator:TValidator = (rule, value, cb) => {
if (value) {
if (otherValue) {
cb()
} else {
cb(new Error(t('dr.form.requiredEndTime', { message: requiredMessage })))
}
} else {
cb()
}
}
const otherRules = { validator }
rules.push(otherRules)
}
}
if (typeof config.customRequiredRule === 'function') {
const CRR = config.customRequiredRule(config as IRenderConfig, otherValue as IAnyObject, dependOnValues, outDependOnValues)
rules.push(CRR)
}
// 提取公共函数
const pushValidatorFunction = (validator: TValidator, type?: string) => {
const message = config.validateValueErrorMessage as string
const rule: { validator: TValidator, trigger: string, message?: string } = {
validator,
trigger: type || 'blur'
}
if (message) {
rule.message = message
}
return rule
}
if (config.validateValue && validatorMap[config.validateValue]) { // 内置值类型校验
const validator = validatorMap[config.validateValue] as TValidator
if (validator) {
rules.push(pushValidatorFunction(validator))
}
}
// 正则校验
if (config.regexpValidate) {
try {
const reg = new RegExp(config.regexpValidate as string)
const rule = {
pattern: reg,
message: config.regexpValidateErrorMessage || t('dr.form.regexpFail', { pattern: reg.toString() }),
trigger: 'blur'
}
rules.push(rule)
} catch (e: unknown) { console.log((e as Error).message) }
}
// 远程校验值是否已经存在
if (config.validateExistRemote) {
// @ts-ignore Promise<void> === void
const validator: TValidator = async (rule, value, callback) => {
const { data } = await config.validateExistRemote!(value, dependOnValues, outDependOnValues)
if (data) { // data 为真值是校验失败
callback(new Error(config.validateExistRemoteErrorMessage || rule.message as string || t('dr.form.alreadyExists')))
} else {
callback()
}
}
rules.push(pushValidatorFunction(validator))
}
// 自定义验证器
if (config.customValidators) {
const customRules = (
config.customValidators as Array<ICustomValidator>
).map(customValidator => {
// @ts-ignore Promise<void> === void
const validator: TValidator = async (rule, value, callback) => {
const { data, message } = await customValidator(value, dependOnValues, outDependOnValues)
if (!data) { // data 为假值是校验失败
const errorMessage = customValidator.message || message || rule.message as string
callback(new Error(errorMessage))
} else {
callback()
}
}
return pushValidatorFunction(validator, customValidator.type)
})
rules.push(...customRules)
}
return rules
}