feat: form validator (#569)
* feat: form validator * fix: max can equal min * feat: adjust input validation rule * feat: improve field validation * feat: optimize field validation * feat: improve field validation * fix: percent validation Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
68d35cf597
commit
2282ec1a2d
@ -5,6 +5,7 @@ import React, { useEffect } from 'react';
|
||||
import { useCompile, useComponent, useFormBlockContext } from '..';
|
||||
import { CollectionFieldProvider } from './CollectionFieldProvider';
|
||||
import { useCollectionField } from './hooks';
|
||||
import { concat } from 'lodash';
|
||||
|
||||
// TODO: 初步适配
|
||||
const InternalField: React.FC = (props) => {
|
||||
@ -38,8 +39,9 @@ const InternalField: React.FC = (props) => {
|
||||
setFieldProps('title', uiSchema.title);
|
||||
setFieldProps('description', uiSchema.description);
|
||||
setFieldProps('initialValue', uiSchema.default);
|
||||
if (!field.validator && uiSchema['x-validator']) {
|
||||
field.validator = uiSchema['x-validator'];
|
||||
if (!field.validator && (uiSchema['x-validator'] || fieldSchema['x-validator'])) {
|
||||
const concatSchema = concat([], uiSchema['x-validator'] || [], fieldSchema['x-validator'] || [])
|
||||
field.validator = concatSchema;
|
||||
}
|
||||
if (fieldSchema['x-disabled'] === true) {
|
||||
field.disabled = true;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
|
||||
export const input: IField = {
|
||||
name: 'input',
|
||||
@ -29,4 +30,110 @@ export const input: IField = {
|
||||
schema['x-component-props']['ellipsis'] = true;
|
||||
}
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
max: {
|
||||
type: 'number',
|
||||
title: '{{ t("Max length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.min').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Max length must greater than min length')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
min: {
|
||||
type: 'number',
|
||||
title: '{{ t("Min length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.max'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Min length must less than max length')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
len: {
|
||||
type: 'number',
|
||||
title: '{{ t("Length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
title: '{{ t("Format") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
'x-component-props': {
|
||||
allowClear: true,
|
||||
},
|
||||
enum: [{
|
||||
label: '{{ t("url") }}',
|
||||
value: 'url',
|
||||
}, {
|
||||
label: '{{ t("email") }}',
|
||||
value: 'email',
|
||||
}, {
|
||||
label: '{{ t("ipv6") }}',
|
||||
value: 'ipv6',
|
||||
}, {
|
||||
label: '{{ t("ipv4") }}',
|
||||
value: 'ipv4',
|
||||
}, {
|
||||
label: '{{ t("number") }}',
|
||||
value: 'number',
|
||||
}, {
|
||||
label: '{{ t("integer") }}',
|
||||
value: 'integer',
|
||||
}, {
|
||||
label: '{{ t("idcard") }}',
|
||||
value: 'idcard',
|
||||
}, {
|
||||
label: '{{ t("qq") }}',
|
||||
value: 'qq',
|
||||
}, {
|
||||
label: '{{ t("phone") }}',
|
||||
value: 'phone',
|
||||
}, {
|
||||
label: '{{ t("money") }}',
|
||||
value: 'money',
|
||||
}, {
|
||||
label: '{{ t("zh") }}',
|
||||
value: 'zh',
|
||||
}, {
|
||||
label: '{{ t("date") }}',
|
||||
value: 'date',
|
||||
}, {
|
||||
label: '{{ t("zip") }}',
|
||||
value: 'zip',
|
||||
}]
|
||||
},
|
||||
pattern: {
|
||||
type: 'string',
|
||||
title: '{{ t("Regular expression") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {
|
||||
prefix: '/',
|
||||
suffix: '/',
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,13 @@
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
import { registerValidateFormats } from '@formily/core';
|
||||
import { ISchema } from '@formily/react';
|
||||
|
||||
registerValidateFormats({
|
||||
odd: /^-?\d*[13579]$/,
|
||||
even: /^-?\d*[02468]$/
|
||||
});
|
||||
|
||||
export const integer: IField = {
|
||||
name: 'integer',
|
||||
@ -28,4 +36,65 @@ export const integer: IField = {
|
||||
filterable: {
|
||||
operators: operators.number,
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
maximum: {
|
||||
type: 'number',
|
||||
title: '{{ t("Maximum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.minimum').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Maximum must greater than minimum')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
minimum: {
|
||||
type: 'number',
|
||||
title: '{{ t("Minimum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.maximum'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Minimum must less than maximum')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
title: '{{ t("Format") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
'x-component-props': {
|
||||
allowClear: true,
|
||||
},
|
||||
enum: [{
|
||||
label: '{{ t("Odd") }}',
|
||||
value: 'odd',
|
||||
}, {
|
||||
label: '{{ t("Even") }}',
|
||||
value: 'even',
|
||||
}]
|
||||
},
|
||||
pattern: {
|
||||
type: 'string',
|
||||
title: '{{ t("Regular expression") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {
|
||||
prefix: '/',
|
||||
suffix: '/',
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n'
|
||||
|
||||
export const markdown: IField = {
|
||||
name: 'markdown',
|
||||
@ -25,4 +26,41 @@ export const markdown: IField = {
|
||||
schema['x-component-props']['ellipsis'] = true;
|
||||
}
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
max: {
|
||||
type: 'number',
|
||||
title: '{{ t("Max length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.min').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Max length must greater than min length')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
min: {
|
||||
type: 'number',
|
||||
title: '{{ t("Min length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.max'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Min length must less than max length')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { registerValidateRules } from '@formily/core';
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
|
||||
export const number: IField = {
|
||||
name: 'number',
|
||||
@ -42,4 +45,62 @@ export const number: IField = {
|
||||
filterable: {
|
||||
operators: operators.number,
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
maximum: {
|
||||
type: 'number',
|
||||
title: '{{ t("Maximum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.minimum').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Maximum must greater than minimum')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
minimum: {
|
||||
type: 'number',
|
||||
title: '{{ t("Minimum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-reactions': {
|
||||
dependencies: ['.maximum'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Minimum must less than maximum')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
title: '{{ t("Format") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
'x-component-props': {
|
||||
allowClear: true,
|
||||
},
|
||||
enum: [{
|
||||
label: '{{ t("Integer") }}',
|
||||
value: 'integer',
|
||||
}, {
|
||||
label: '{{ t("Odd") }}',
|
||||
value: 'odd',
|
||||
}, {
|
||||
label: '{{ t("Even") }}',
|
||||
value: 'even',
|
||||
}]
|
||||
},
|
||||
pattern: {
|
||||
type: 'string',
|
||||
title: '{{ t("Regular expression") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {
|
||||
prefix: '/',
|
||||
suffix: '/',
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
|
||||
export const password: IField = {
|
||||
name: 'password',
|
||||
@ -19,4 +21,41 @@ export const password: IField = {
|
||||
properties: {
|
||||
...defaultProps,
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
max: {
|
||||
type: 'number',
|
||||
title: '{{ t("Max length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.min').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Max length must greater than min length')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
min: {
|
||||
type: 'number',
|
||||
title: '{{ t("Min length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.max'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Min length must less than max length')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,51 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps, operators } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
import { registerValidateFormats, registerValidateRules, registerValidateLocale } from '@formily/core';
|
||||
|
||||
registerValidateRules({
|
||||
percentMode(value, rule) {
|
||||
const { maxValue, minValue } = rule;
|
||||
|
||||
if (maxValue) {
|
||||
if (value > maxValue) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: `${i18n.t('The field value cannot be greater than ')}${maxValue * 100}%`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minValue) {
|
||||
if (value < minValue) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: `${i18n.t('The field value cannot be less than ')}${minValue * 100}%`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
percentFormats(value, rule) {
|
||||
const { percentFormat } = rule;
|
||||
|
||||
if (value && percentFormat === 'Integer' && /^-?[1-9]\d*$/.test((value * 100).toString()) === false) {
|
||||
return {
|
||||
type: 'error',
|
||||
message: `${i18n.t('The field value is not an integer number')}`,
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
// registerValidateFormats({
|
||||
// percentInteger: /^(\d+)(.\d{0,2})?$/,
|
||||
// });
|
||||
|
||||
export const percent: IField = {
|
||||
name: 'percent',
|
||||
@ -43,4 +89,62 @@ export const percent: IField = {
|
||||
filterable: {
|
||||
operators: operators.number,
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
maxValue: {
|
||||
type: 'number',
|
||||
title: '{{ t("Maximum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Percent',
|
||||
'x-component-props': {
|
||||
addonAfter: '%',
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.minimum').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Maximum must greater than minimum')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
minValue: {
|
||||
type: 'number',
|
||||
title: '{{ t("Minimum") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Percent',
|
||||
'x-component-props': {
|
||||
addonAfter: '%',
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.maximum'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Minimum must less than maximum')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
percentFormat: {
|
||||
type: 'string',
|
||||
title: '{{ t("Format") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
'x-component-props': {
|
||||
allowClear: true,
|
||||
},
|
||||
enum: [{
|
||||
label: '{{ t("Integer") }}',
|
||||
value: 'Integer',
|
||||
}]
|
||||
},
|
||||
pattern: {
|
||||
type: 'string',
|
||||
title: '{{ t("Regular expression") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {
|
||||
prefix: '/',
|
||||
suffix: '/',
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { ISchema } from '@formily/react';
|
||||
import { defaultProps } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
|
||||
export const richText: IField = {
|
||||
name: 'richText',
|
||||
@ -26,4 +27,41 @@ export const richText: IField = {
|
||||
schema['x-component-props']['ellipsis'] = true;
|
||||
}
|
||||
},
|
||||
validateSchema(fieldSchema, formItemStyle) {
|
||||
return {
|
||||
max: {
|
||||
type: 'number',
|
||||
title: '{{ t("Max length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.min').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Max length must greater than min length')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
min: {
|
||||
type: 'number',
|
||||
title: '{{ t("Min length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.max'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Min length must less than max length')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { defaultProps } from './properties';
|
||||
import { IField } from './types';
|
||||
import { i18n } from '../../i18n';
|
||||
|
||||
export const textarea: IField = {
|
||||
name: 'textarea',
|
||||
@ -26,4 +27,41 @@ export const textarea: IField = {
|
||||
schema['x-component-props']['ellipsis'] = true;
|
||||
}
|
||||
},
|
||||
validateSchema(fieldSchema) {
|
||||
return {
|
||||
max: {
|
||||
type: 'number',
|
||||
title: '{{ t("Max length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': `{{(field) => {
|
||||
const targetValue = field.query('.min').value();
|
||||
field.selfErrors =
|
||||
!!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Max length must greater than min length')}' : ''
|
||||
}}}`,
|
||||
},
|
||||
min: {
|
||||
type: 'number',
|
||||
title: '{{ t("Min length") }}',
|
||||
minimum: 0,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'InputNumber',
|
||||
'x-component-props': {
|
||||
precision: 0
|
||||
},
|
||||
'x-reactions': {
|
||||
dependencies: ['.max'],
|
||||
fulfill: {
|
||||
state: {
|
||||
selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Min length must less than max length')}' : ''}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -549,4 +549,5 @@ export default {
|
||||
"Field component": "Field component",
|
||||
"Subtable": "Subtable",
|
||||
"Subform": "Subform",
|
||||
"Regular expression": "Pattern",
|
||||
}
|
||||
|
@ -236,6 +236,25 @@ export default {
|
||||
"Default is the ID field": "默认为 ID 字段",
|
||||
"Set default sorting rules": "设置排序规则",
|
||||
|
||||
"Set validation rules": "设置验证规则",
|
||||
"Max length": "最大长度",
|
||||
"Min length": "最小长度",
|
||||
"Maximum": "最大值",
|
||||
"Minimum": "最小值",
|
||||
"Max length must greater than min length": "最大长度必须大于最小长度",
|
||||
"Min length must less than max length": "最小长度必须小于最大长度",
|
||||
"Maximum must greater than minimum": "最大值必须大于最小值",
|
||||
"Minimum must less than maximum": "最小值必须小于最大值",
|
||||
"Validation rule": "验证规则",
|
||||
"Add validation rule": "新增验证规则",
|
||||
"Format": "格式",
|
||||
"Regular expression": "正则表达式",
|
||||
"Error message": "错误消息",
|
||||
"Length": "长度",
|
||||
"The field value cannot be greater than ": "数值不能大于",
|
||||
"The field value cannot be less than ": "数值不能小于",
|
||||
"The field value is not an integer number": "数字不是整数",
|
||||
|
||||
"is before": "早于",
|
||||
"is after": "晚于",
|
||||
"is on or after": "不早于",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { FormItem as Item } from '@formily/antd';
|
||||
import { ArrayCollapse, FormItem as Item, FormLayout } from '@formily/antd';
|
||||
import { Field } from '@formily/core';
|
||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
@ -11,6 +11,7 @@ import { useCollection, useCollectionManager } from '../../../collection-manager
|
||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||
import { BlockItem } from '../block-item';
|
||||
import { HTMLEncode } from '../input/shared';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
const divWrap = (schema: ISchema) => {
|
||||
return {
|
||||
@ -59,6 +60,7 @@ FormItem.Designer = (props) => {
|
||||
const compile = useCompile();
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
const interfaceConfig = getInterface(collectionField?.interface);
|
||||
const validateSchema = interfaceConfig?.['validateSchema']?.(fieldSchema);
|
||||
const originalTitle = collectionField?.uiSchema?.title;
|
||||
const targetFields = collectionField?.target ? getCollectionFields(collectionField.target) : [];
|
||||
const isSubFormAssocitionField = field.address.segments.includes('__form_grid');
|
||||
@ -81,6 +83,7 @@ FormItem.Designer = (props) => {
|
||||
if (fieldSchema['x-read-pretty'] === true) {
|
||||
readOnlyMode = 'read-pretty';
|
||||
}
|
||||
|
||||
return (
|
||||
<GeneralSchemaDesigner>
|
||||
{collectionField && (
|
||||
@ -201,6 +204,126 @@ FormItem.Designer = (props) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{validateSchema && (
|
||||
<SchemaSettings.ModalItem
|
||||
title={t('Set validation rules')}
|
||||
components={{ ArrayCollapse, FormLayout }}
|
||||
schema={{
|
||||
type: 'object',
|
||||
title: t('Set validation rules'),
|
||||
properties: {
|
||||
rules: {
|
||||
type: 'array',
|
||||
default: fieldSchema?.['x-validator'],
|
||||
'x-component': 'ArrayCollapse',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component-props': {
|
||||
accordion: true,
|
||||
},
|
||||
maxItems: 3,
|
||||
items: {
|
||||
type: 'object',
|
||||
'x-component': 'ArrayCollapse.CollapsePanel',
|
||||
'x-component-props': {
|
||||
header: '{{ t("Validation rule") }}',
|
||||
},
|
||||
properties: {
|
||||
index: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayCollapse.Index',
|
||||
},
|
||||
layout: {
|
||||
type: 'void',
|
||||
'x-component': 'FormLayout',
|
||||
'x-component-props': {
|
||||
labelStyle: {
|
||||
marginTop: '6px',
|
||||
},
|
||||
labelCol: 8,
|
||||
wrapperCol: 16,
|
||||
},
|
||||
properties: {
|
||||
...validateSchema,
|
||||
message: {
|
||||
type: 'string',
|
||||
title: '{{ t("Error message") }}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {
|
||||
autoSize: {
|
||||
minRows: 2,
|
||||
maxRows: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayCollapse.Remove',
|
||||
},
|
||||
moveUp: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayCollapse.MoveUp',
|
||||
},
|
||||
moveDown: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayCollapse.MoveDown',
|
||||
},
|
||||
}
|
||||
},
|
||||
properties: {
|
||||
add: {
|
||||
type: 'void',
|
||||
title: '{{ t("Add validation rule") }}',
|
||||
'x-component': 'ArrayCollapse.Addition',
|
||||
'x-reactions': {
|
||||
dependencies: ['rules'],
|
||||
fulfill: {
|
||||
state: {
|
||||
disabled: '{{$deps[0].length >= 3}}'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
} as ISchema}
|
||||
onSubmit={(v) => {
|
||||
const rules = [];
|
||||
for (const rule of v.rules) {
|
||||
rules.push(_.pickBy(rule, _.identity))
|
||||
}
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
// return;
|
||||
// if (['number'].includes(collectionField?.interface) && collectionField?.uiSchema?.['x-component-props']?.['stringMode'] === true) {
|
||||
// rules['numberStringMode'] = true;
|
||||
// }
|
||||
if (['percent'].includes(collectionField?.interface)) {
|
||||
for (const rule of rules) {
|
||||
if (!!rule.maxValue || !!rule.minValue) {
|
||||
rule['percentMode'] = true;
|
||||
}
|
||||
|
||||
if (rule.percentFormat) {
|
||||
rule['percentFormats'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
const concatValidator = _.concat([], collectionField?.uiSchema?.['x-validator'] || [], rules)
|
||||
field.validator = concatValidator;
|
||||
fieldSchema['x-validator'] = rules;
|
||||
schema['x-validator'] = rules;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{form && !isSubFormAssocitionField && ['o2o', 'oho', 'obo', 'o2m'].includes(collectionField?.interface) && (
|
||||
<SchemaSettings.SelectItem
|
||||
title={t('Field component')}
|
||||
|
@ -3,6 +3,12 @@ import { connect, mapReadPretty } from '@formily/react';
|
||||
import { InputNumber as AntdNumber } from 'antd';
|
||||
import { ReadPretty } from './ReadPretty';
|
||||
|
||||
export const InputNumber = connect(AntdNumber, mapReadPretty(ReadPretty));
|
||||
export const InputNumber = connect((props) => {
|
||||
const { onChange, ...others } = props;
|
||||
const handleChange = (v) => {
|
||||
onChange(parseFloat(v));
|
||||
}
|
||||
return (<AntdNumber onChange={handleChange} {...others} />);
|
||||
}, mapReadPretty(ReadPretty));
|
||||
|
||||
export default InputNumber;
|
||||
|
@ -12,10 +12,10 @@ export const Percent = connect(
|
||||
<InputNumber
|
||||
{...props}
|
||||
addonAfter="%"
|
||||
value={math.round(value * 100, 9)}
|
||||
value={value ? math.round(value * 100, 9) : null}
|
||||
onChange={(v: any) => {
|
||||
if (onChange) {
|
||||
onChange(math.round(v / 100, 9));
|
||||
onChange(v ? math.round(v / 100, 9) : null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -23,7 +23,6 @@ const useTableColumns = () => {
|
||||
const field = useField<ArrayField>();
|
||||
const schema = useFieldSchema();
|
||||
const { exists, render } = useSchemaInitializer(schema['x-initializer']);
|
||||
// console.log('useTableColumns', exists);
|
||||
const columns = schema
|
||||
.reduceProperties((buf, s) => {
|
||||
if (isColumnComponent(s)) {
|
||||
@ -38,7 +37,6 @@ const useTableColumns = () => {
|
||||
}
|
||||
}, []);
|
||||
const dataIndex = collectionFields?.length > 0 ? collectionFields[0].name : s.name;
|
||||
console.log('useTableColumns', s.name, s, field.value);
|
||||
return {
|
||||
title: <RecursionField name={s.name} schema={s} onlyRenderSelf />,
|
||||
dataIndex,
|
||||
@ -48,7 +46,6 @@ const useTableColumns = () => {
|
||||
render: (v, record) => {
|
||||
const index = field.value?.indexOf(record);
|
||||
// console.log((Date.now() - start) / 1000);
|
||||
console.log('useTableColumns.index', index, record);
|
||||
return (
|
||||
<RecordIndexProvider index={index}>
|
||||
<RecordProvider record={record}>
|
||||
|
Loading…
Reference in New Issue
Block a user