feat: support use select field (#1105)
* feat: add RemoteSelect * feat: match * feat: support use select field * fix: revert no need code * fix: remove console * feat: reuse select * feat: support multiple value and labelInValue * fix: incorrect import * fix: missing title in RemoteSelect * feat: add association-select * fix: edit * feat: support sort * feat: support filter * fix: break * fix: loss of filter data after closing the drawer * fix: multiple not support in select * fix: some bugs in multiple * feat: support select in o2m,o2o * feat: support more association field * feat: improve * fix: remove unused files * feat: make o2m also support pattern * fix: missing value on edit
This commit is contained in:
parent
4a113774bd
commit
0b6fed79d3
@ -10,7 +10,7 @@ import { assign } from './assign';
|
|||||||
|
|
||||||
type FunctionService = (...args: any[]) => Promise<any>;
|
type FunctionService = (...args: any[]) => Promise<any>;
|
||||||
|
|
||||||
type ResourceActionOptions<P = any> = {
|
export type ResourceActionOptions<P = any> = {
|
||||||
resource?: string;
|
resource?: string;
|
||||||
resourceOf?: any;
|
resourceOf?: any;
|
||||||
action?: string;
|
action?: string;
|
||||||
|
@ -47,10 +47,19 @@ export const linkTo: IField = {
|
|||||||
},
|
},
|
||||||
schemaInitialize(schema: ISchema, { readPretty, block }) {
|
schemaInitialize(schema: ISchema, { readPretty, block }) {
|
||||||
if (block === 'Form') {
|
if (block === 'Form') {
|
||||||
schema['properties'] = {
|
if (schema['x-component'] === 'AssociationSelect') {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
Object.assign(schema, {
|
||||||
selector: cloneDeep(recordPickerSelector),
|
type: 'string',
|
||||||
};
|
'x-designer': 'AssociationSelect.Designer',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
schema.type = 'string';
|
||||||
|
schema['properties'] = {
|
||||||
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
|
selector: cloneDeep(recordPickerSelector),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return schema
|
||||||
} else {
|
} else {
|
||||||
if (readPretty) {
|
if (readPretty) {
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { defaultProps, recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
import {
|
||||||
|
defaultProps,
|
||||||
|
recordPickerSelector,
|
||||||
|
recordPickerViewer,
|
||||||
|
relationshipType,
|
||||||
|
reverseFieldProperties,
|
||||||
|
} from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const m2m: IField = {
|
export const m2m: IField = {
|
||||||
@ -47,20 +53,28 @@ export const m2m: IField = {
|
|||||||
},
|
},
|
||||||
schemaInitialize(schema: ISchema, { readPretty, block }) {
|
schemaInitialize(schema: ISchema, { readPretty, block }) {
|
||||||
if (block === 'Form') {
|
if (block === 'Form') {
|
||||||
schema['properties'] = {
|
if (schema['x-component'] === 'AssociationSelect') {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
Object.assign(schema, {
|
||||||
selector: cloneDeep(recordPickerSelector),
|
type: 'string',
|
||||||
};
|
'x-designer': 'AssociationSelect.Designer',
|
||||||
} else {
|
});
|
||||||
if (readPretty) {
|
} else {
|
||||||
|
schema.type = 'string';
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
};
|
|
||||||
} else {
|
|
||||||
schema['properties'] = {
|
|
||||||
selector: cloneDeep(recordPickerSelector),
|
selector: cloneDeep(recordPickerSelector),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
if (readPretty) {
|
||||||
|
schema['properties'] = {
|
||||||
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
schema['properties'] = {
|
||||||
|
selector: cloneDeep(recordPickerSelector),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (['Table', 'Kanban'].includes(block)) {
|
if (['Table', 'Kanban'].includes(block)) {
|
||||||
schema['x-component-props'] = schema['x-component-props'] || {};
|
schema['x-component-props'] = schema['x-component-props'] || {};
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { constraintsProps, recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
import {
|
||||||
|
constraintsProps,
|
||||||
|
recordPickerSelector,
|
||||||
|
recordPickerViewer,
|
||||||
|
relationshipType,
|
||||||
|
reverseFieldProperties,
|
||||||
|
} from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const m2o: IField = {
|
export const m2o: IField = {
|
||||||
@ -44,63 +50,30 @@ export const m2o: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schemaInitialize(schema: ISchema, { field, block, readPretty, action }) {
|
schemaInitialize(schema: ISchema, { block, readPretty }) {
|
||||||
if (block === 'Form' && schema['x-component'] === 'FormField') {
|
if (block === 'Form') {
|
||||||
const association = `${field.collectionName}.${field.name}`;
|
if (schema['x-component'] === 'AssociationSelect') {
|
||||||
schema.type = 'void';
|
Object.assign(schema, {
|
||||||
schema.properties = {
|
type: 'string',
|
||||||
block: {
|
'x-designer': 'AssociationSelect.Designer',
|
||||||
type: 'void',
|
});
|
||||||
'x-decorator': 'FormFieldProvider',
|
} else {
|
||||||
'x-decorator-props': {
|
schema.type = 'string';
|
||||||
collection: field.target,
|
|
||||||
association: association,
|
|
||||||
resource: association,
|
|
||||||
action,
|
|
||||||
fieldName: field.name,
|
|
||||||
readPretty
|
|
||||||
},
|
|
||||||
'x-component': 'CardItem',
|
|
||||||
'x-component-props': {
|
|
||||||
bordered: true,
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
[field.name]: {
|
|
||||||
type: 'object',
|
|
||||||
'x-component': 'FormV2',
|
|
||||||
'x-component-props': {
|
|
||||||
useProps: '{{ useFormFieldProps }}',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
__form_grid: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-initializer': 'FormItemInitializers',
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
schema.type = 'string';
|
|
||||||
if (block === 'Form') {
|
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
selector: cloneDeep(recordPickerSelector),
|
selector: cloneDeep(recordPickerSelector),
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
if (readPretty) {
|
|
||||||
schema['properties'] = {
|
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
schema['properties'] = {
|
|
||||||
selector: cloneDeep(recordPickerSelector),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
if (readPretty) {
|
||||||
|
schema['properties'] = {
|
||||||
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
schema['properties'] = {
|
||||||
|
selector: cloneDeep(recordPickerSelector),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (['Table', 'Kanban'].includes(block)) {
|
if (['Table', 'Kanban'].includes(block)) {
|
||||||
schema['x-component-props'] = schema['x-component-props'] || {};
|
schema['x-component-props'] = schema['x-component-props'] || {};
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { constraintsProps, recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
import {
|
||||||
|
constraintsProps,
|
||||||
|
recordPickerSelector,
|
||||||
|
recordPickerViewer,
|
||||||
|
relationshipType,
|
||||||
|
reverseFieldProperties,
|
||||||
|
} from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const o2m: IField = {
|
export const o2m: IField = {
|
||||||
@ -45,76 +51,72 @@ export const o2m: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
schemaInitialize(schema: ISchema, { field, block, readPretty }) {
|
schemaInitialize(schema: ISchema, { field, block, readPretty }) {
|
||||||
if (block === 'Form' && schema['x-component'] === 'TableField') {
|
if (block === 'Form') {
|
||||||
const association = `${field.collectionName}.${field.name}`;
|
if (schema['x-component'] === 'TableField') {
|
||||||
schema['type'] = 'void';
|
const association = `${field.collectionName}.${field.name}`;
|
||||||
schema['properties'] = {
|
schema['type'] = 'void';
|
||||||
block: {
|
schema['properties'] = {
|
||||||
type: 'void',
|
block: {
|
||||||
'x-decorator': 'TableFieldProvider',
|
type: 'void',
|
||||||
'x-decorator-props': {
|
'x-decorator': 'TableFieldProvider',
|
||||||
collection: field.target,
|
'x-decorator-props': {
|
||||||
association: association,
|
collection: field.target,
|
||||||
resource: association,
|
association: association,
|
||||||
action: 'list',
|
resource: association,
|
||||||
params: {
|
action: 'list',
|
||||||
paginate: false,
|
params: {
|
||||||
|
paginate: false,
|
||||||
|
},
|
||||||
|
showIndex: true,
|
||||||
|
dragSort: false,
|
||||||
|
fieldName: field.name,
|
||||||
},
|
},
|
||||||
showIndex: true,
|
properties: {
|
||||||
dragSort: false,
|
actions: {
|
||||||
fieldName: field.name,
|
type: 'void',
|
||||||
},
|
'x-initializer': 'SubTableActionInitializers',
|
||||||
properties: {
|
'x-component': 'TableField.ActionBar',
|
||||||
actions: {
|
'x-component-props': {},
|
||||||
type: 'void',
|
},
|
||||||
'x-initializer': 'SubTableActionInitializers',
|
[field.name]: {
|
||||||
'x-component': 'TableField.ActionBar',
|
type: 'array',
|
||||||
'x-component-props': {},
|
'x-initializer': 'TableColumnInitializers',
|
||||||
},
|
'x-component': 'TableV2',
|
||||||
[field.name]: {
|
'x-component-props': {
|
||||||
type: 'array',
|
rowSelection: {
|
||||||
'x-initializer': 'TableColumnInitializers',
|
type: 'checkbox',
|
||||||
'x-component': 'TableV2',
|
},
|
||||||
'x-component-props': {
|
useProps: '{{ useTableFieldProps }}',
|
||||||
rowSelection: {
|
|
||||||
type: 'checkbox',
|
|
||||||
},
|
},
|
||||||
useProps: '{{ useTableFieldProps }}',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
};
|
} else if (schema['x-component'] === 'AssociationSelect') {
|
||||||
} else {
|
Object.assign(schema, {
|
||||||
// schema['x-component'] = 'CollectionField';
|
type: 'string',
|
||||||
// schema.type = 'array';
|
'x-designer': 'AssociationSelect.Designer',
|
||||||
|
});
|
||||||
if (block === 'Form') {
|
} else {
|
||||||
|
schema.type = 'string';
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
selector: cloneDeep(recordPickerSelector),
|
selector: cloneDeep(recordPickerSelector),
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
if (readPretty) {
|
|
||||||
schema['properties'] = {
|
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
schema['properties'] = {
|
|
||||||
selector: cloneDeep(recordPickerSelector),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return schema;
|
||||||
}
|
}
|
||||||
// if (readPretty) {
|
|
||||||
// schema['properties'] = {
|
if (readPretty) {
|
||||||
// viewer: cloneDeep(recordPickerViewer),
|
schema['properties'] = {
|
||||||
// };
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
// } else {
|
};
|
||||||
// schema['properties'] = {
|
} else {
|
||||||
// selector: cloneDeep(recordPickerSelector),
|
schema['properties'] = {
|
||||||
// };
|
selector: cloneDeep(recordPickerSelector),
|
||||||
// }
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (['Table', 'Kanban'].includes(block)) {
|
if (['Table', 'Kanban'].includes(block)) {
|
||||||
schema['x-component-props'] = schema['x-component-props'] || {};
|
schema['x-component-props'] = schema['x-component-props'] || {};
|
||||||
schema['x-component-props']['ellipsis'] = true;
|
schema['x-component-props']['ellipsis'] = true;
|
||||||
|
@ -1,65 +1,77 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { constraintsProps, recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
import {
|
||||||
|
constraintsProps,
|
||||||
|
recordPickerSelector,
|
||||||
|
recordPickerViewer,
|
||||||
|
relationshipType,
|
||||||
|
reverseFieldProperties,
|
||||||
|
} from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, action }) => {
|
const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, action }) => {
|
||||||
if (block === 'Form' && schema['x-component'] === 'FormField') {
|
if (block === 'Form') {
|
||||||
const association = `${field.collectionName}.${field.name}`;
|
if (schema['x-component'] === 'FormField') {
|
||||||
schema.type = 'void';
|
const association = `${field.collectionName}.${field.name}`;
|
||||||
schema.properties = {
|
schema.type = 'void';
|
||||||
block: {
|
schema.properties = {
|
||||||
type: 'void',
|
block: {
|
||||||
'x-decorator': 'FormFieldProvider',
|
type: 'void',
|
||||||
'x-decorator-props': {
|
'x-decorator': 'FormFieldProvider',
|
||||||
collection: field.target,
|
'x-decorator-props': {
|
||||||
association: association,
|
collection: field.target,
|
||||||
resource: association,
|
association: association,
|
||||||
action: action,
|
resource: association,
|
||||||
fieldName: field.name,
|
action: action,
|
||||||
readPretty,
|
fieldName: field.name,
|
||||||
},
|
readPretty,
|
||||||
'x-component': 'CardItem',
|
},
|
||||||
'x-component-props': {
|
'x-component': 'CardItem',
|
||||||
bordered: true,
|
'x-component-props': {
|
||||||
},
|
bordered: true,
|
||||||
properties: {
|
},
|
||||||
[field.name]: {
|
properties: {
|
||||||
type: 'object',
|
[field.name]: {
|
||||||
'x-component': 'FormV2',
|
type: 'object',
|
||||||
'x-component-props': {
|
'x-component': 'FormV2',
|
||||||
useProps: '{{ useFormFieldProps }}',
|
'x-component-props': {
|
||||||
},
|
useProps: '{{ useFormFieldProps }}',
|
||||||
properties: {
|
},
|
||||||
__form_grid: {
|
properties: {
|
||||||
type: 'void',
|
__form_grid: {
|
||||||
'x-component': 'Grid',
|
type: 'void',
|
||||||
'x-initializer': 'FormItemInitializers',
|
'x-component': 'Grid',
|
||||||
properties: {},
|
'x-initializer': 'FormItemInitializers',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
};
|
} else if (schema['x-component'] === 'AssociationSelect') {
|
||||||
} else {
|
Object.assign(schema, {
|
||||||
schema.type = 'string';
|
type: 'string',
|
||||||
if (block === 'Form') {
|
'x-designer': 'AssociationSelect.Designer',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
schema.type = 'string';
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
selector: cloneDeep(recordPickerSelector),
|
selector: cloneDeep(recordPickerSelector),
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
if (readPretty) {
|
|
||||||
schema['properties'] = {
|
|
||||||
viewer: cloneDeep(recordPickerViewer),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
schema['properties'] = {
|
|
||||||
selector: cloneDeep(recordPickerSelector),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
schema.type = 'string';
|
||||||
|
if (readPretty) {
|
||||||
|
schema['properties'] = {
|
||||||
|
viewer: cloneDeep(recordPickerViewer),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
schema['properties'] = {
|
||||||
|
selector: cloneDeep(recordPickerSelector),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,692 @@
|
|||||||
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
|
import { ArrayCollapse, ArrayItems, FormLayout } from '@formily/antd';
|
||||||
|
import { Field } from '@formily/core';
|
||||||
|
import { connect, ISchema, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useFormBlockContext, useFilterByTk } from '../../../block-provider';
|
||||||
|
import {
|
||||||
|
useCollectionManager,
|
||||||
|
useCollection,
|
||||||
|
useSortFields,
|
||||||
|
useCollectionFilterOptions,
|
||||||
|
} from '../../../collection-manager';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
|
import { useDesignable, useCompile, useFieldComponentOptions } from '../../hooks';
|
||||||
|
import { RemoteSelect, RemoteSelectProps } from '../remote-select';
|
||||||
|
import { defaultFieldNames } from '../select';
|
||||||
|
import { ReadPretty } from './ReadPretty';
|
||||||
|
import useServiceOptions from './useServiceOptions';
|
||||||
|
|
||||||
|
export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
|
||||||
|
action?: string;
|
||||||
|
multiple?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const divWrap = (schema: ISchema) => {
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
properties: {
|
||||||
|
[schema.name || uid()]: schema,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const InternalAssociationSelect = connect(
|
||||||
|
(props: AssociationSelectProps) => {
|
||||||
|
const { fieldNames, objectValue = true } = props;
|
||||||
|
const service = useServiceOptions(props);
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const collectionField = getField(fieldSchema.name);
|
||||||
|
|
||||||
|
const normalizeValues = useCallback(
|
||||||
|
(obj) => {
|
||||||
|
if (!objectValue && typeof obj === 'object') {
|
||||||
|
return obj[fieldNames.value];
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
[objectValue, fieldNames.value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => {
|
||||||
|
if (props.value === undefined || props.value === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(props.value)) {
|
||||||
|
return props.value.map(normalizeValues);
|
||||||
|
} else {
|
||||||
|
return normalizeValues(props.value);
|
||||||
|
}
|
||||||
|
}, [props.value, normalizeValues]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!field.title) {
|
||||||
|
field.title = collectionField.uiSchema.title;
|
||||||
|
}
|
||||||
|
}, collectionField.title);
|
||||||
|
|
||||||
|
return <RemoteSelect {...props} objectValue={objectValue} value={value} service={service}></RemoteSelect>;
|
||||||
|
},
|
||||||
|
mapProps(
|
||||||
|
{
|
||||||
|
dataSource: 'options',
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
(props, field) => {
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
fieldNames: { ...defaultFieldNames, ...props.fieldNames, ...field.componentProps.fieldNames },
|
||||||
|
suffixIcon: field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffixIcon,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
mapReadPretty(ReadPretty),
|
||||||
|
);
|
||||||
|
|
||||||
|
interface RemoteSelectInterface {
|
||||||
|
(props: any): React.ReactElement;
|
||||||
|
Designer: React.FC;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AssociationSelect = InternalAssociationSelect as unknown as RemoteSelectInterface;
|
||||||
|
|
||||||
|
AssociationSelect.Designer = () => {
|
||||||
|
const { getCollectionFields, getInterface, getCollectionJoinField } = useCollectionManager();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const { form } = useFormBlockContext();
|
||||||
|
const field = useField<Field>();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const tk = useFilterByTk();
|
||||||
|
const {} = useCollection();
|
||||||
|
const { dn, refresh, insertAdjacent } = useDesignable();
|
||||||
|
const compile = useCompile();
|
||||||
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
|
const fieldComponentOptions = useFieldComponentOptions();
|
||||||
|
const isSubFormAssocitionField = field.address.segments.includes('__form_grid');
|
||||||
|
const interfaceConfig = getInterface(collectionField?.interface);
|
||||||
|
const validateSchema = interfaceConfig?.['validateSchema']?.(fieldSchema);
|
||||||
|
const originalTitle = collectionField?.uiSchema?.title;
|
||||||
|
const targetFields = collectionField?.target ? getCollectionFields(collectionField.target) : [];
|
||||||
|
const initialValue = {
|
||||||
|
title: field.title === originalTitle ? undefined : field.title,
|
||||||
|
};
|
||||||
|
const sortFields = useSortFields(collectionField.target);
|
||||||
|
const defaultSort = field.componentProps?.service?.params?.sort || [];
|
||||||
|
const defaultFilter = field.componentProps?.service?.params?.filter || {};
|
||||||
|
const dataSource = useCollectionFilterOptions(collectionField.target);
|
||||||
|
console.log(collectionField?.target, ['CollectionField', 'AssociationSelect'].includes(fieldSchema['x-component']));
|
||||||
|
|
||||||
|
const sort = defaultSort?.map((item: string) => {
|
||||||
|
return item.startsWith('-')
|
||||||
|
? {
|
||||||
|
field: item.substring(1),
|
||||||
|
direction: 'desc',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
field: item,
|
||||||
|
direction: 'asc',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (!field.readPretty) {
|
||||||
|
initialValue['required'] = field.required;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = targetFields
|
||||||
|
.filter((field) => !field?.target && field.type !== 'boolean')
|
||||||
|
.map((field) => ({
|
||||||
|
value: field?.name,
|
||||||
|
label: compile(field?.uiSchema?.title) || field?.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let readOnlyMode = 'editable';
|
||||||
|
if (fieldSchema['x-disabled'] === true) {
|
||||||
|
readOnlyMode = 'readonly';
|
||||||
|
}
|
||||||
|
if (fieldSchema['x-read-pretty'] === true) {
|
||||||
|
readOnlyMode = 'read-pretty';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner>
|
||||||
|
{collectionField && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-field-title"
|
||||||
|
title={t('Edit field title')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit field title'),
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: t('Field title'),
|
||||||
|
default: field?.title,
|
||||||
|
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ title }) => {
|
||||||
|
if (title) {
|
||||||
|
field.title = title;
|
||||||
|
fieldSchema.title = title;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
title: fieldSchema.title,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!field.readPretty && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-description"
|
||||||
|
title={t('Edit description')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit description'),
|
||||||
|
properties: {
|
||||||
|
description: {
|
||||||
|
// title: t('Description'),
|
||||||
|
default: field?.description,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ description }) => {
|
||||||
|
field.description = description;
|
||||||
|
fieldSchema.description = description;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
description: fieldSchema.description,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{field.readPretty && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-tooltip"
|
||||||
|
title={t('Edit tooltip')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit description'),
|
||||||
|
properties: {
|
||||||
|
tooltip: {
|
||||||
|
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ tooltip }) => {
|
||||||
|
field.decoratorProps.tooltip = tooltip;
|
||||||
|
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
||||||
|
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!field.readPretty && (
|
||||||
|
<SchemaSettings.SwitchItem
|
||||||
|
key="required"
|
||||||
|
title={t('Required')}
|
||||||
|
checked={fieldSchema.required as boolean}
|
||||||
|
onChange={(required) => {
|
||||||
|
const schema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
field.required = required;
|
||||||
|
fieldSchema['required'] = required;
|
||||||
|
schema['required'] = required;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{form && !form?.readPretty && 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 && !form?.readPretty && collectionField?.uiSchema?.type && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set default value')}
|
||||||
|
components={{ ArrayCollapse, FormLayout }}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set default value'),
|
||||||
|
properties: {
|
||||||
|
default: {
|
||||||
|
...collectionField.uiSchema,
|
||||||
|
name: 'default',
|
||||||
|
title: t('Default value'),
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
default: fieldSchema.default || collectionField.defaultValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={(v) => {
|
||||||
|
const schema: ISchema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
if (field.value !== v.default) {
|
||||||
|
field.value = v.default;
|
||||||
|
}
|
||||||
|
fieldSchema.default = v.default;
|
||||||
|
schema.default = v.default;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{form && !isSubFormAssocitionField && fieldComponentOptions && (
|
||||||
|
<SchemaSettings.SelectItem
|
||||||
|
title={t('Field component')}
|
||||||
|
options={fieldComponentOptions}
|
||||||
|
value={fieldSchema['x-component']}
|
||||||
|
onChange={(type) => {
|
||||||
|
const schema: ISchema = {
|
||||||
|
name: collectionField.name,
|
||||||
|
type: 'void',
|
||||||
|
required: fieldSchema['required'],
|
||||||
|
description: fieldSchema['description'],
|
||||||
|
default: fieldSchema['default'],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-designer': 'FormItem.Designer',
|
||||||
|
'x-component': type,
|
||||||
|
'x-validator': fieldSchema['x-validator'],
|
||||||
|
'x-collection-field': fieldSchema['x-collection-field'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
'x-component-props': {
|
||||||
|
...collectionField?.uiSchema?.['x-component-props'],
|
||||||
|
...fieldSchema['x-component-props'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
interfaceConfig?.schemaInitialize?.(schema, {
|
||||||
|
field: collectionField,
|
||||||
|
block: 'Form',
|
||||||
|
readPretty: field.readPretty,
|
||||||
|
action: tk ? 'get' : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (type === 'CollectionField') {
|
||||||
|
schema['type'] = 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAdjacent('beforeBegin', divWrap(schema), {
|
||||||
|
onSuccess: () => {
|
||||||
|
dn.remove(null, {
|
||||||
|
removeParentsIfNoChildren: true,
|
||||||
|
breakRemoveOn: {
|
||||||
|
'x-component': 'Grid',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set the data scope')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set the data scope'),
|
||||||
|
properties: {
|
||||||
|
filter: {
|
||||||
|
default: defaultFilter,
|
||||||
|
// title: '数据范围',
|
||||||
|
enum: dataSource,
|
||||||
|
'x-component': 'Filter',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ filter }) => {
|
||||||
|
_.set(field.componentProps, 'service.params.filter', filter);
|
||||||
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': field.componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set default sorting rules')}
|
||||||
|
components={{ ArrayItems }}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set default sorting rules'),
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'array',
|
||||||
|
default: sort,
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.SortHandle',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: 'string',
|
||||||
|
enum: sortFields,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {
|
||||||
|
optionType: 'button',
|
||||||
|
},
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: t('ASC'),
|
||||||
|
value: 'asc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('DESC'),
|
||||||
|
value: 'desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: t('Add sort field'),
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ sort }) => {
|
||||||
|
const sortArr = sort.map((item) => {
|
||||||
|
return item.direction === 'desc' ? `-${item.field}` : item.field;
|
||||||
|
});
|
||||||
|
|
||||||
|
_.set(field.componentProps, 'service.params.sort', sortArr);
|
||||||
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': field.componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{form && !form?.readPretty && fieldSchema?.['x-component-props']?.['pattern-disable'] != true && (
|
||||||
|
<SchemaSettings.SelectItem
|
||||||
|
key="pattern"
|
||||||
|
title={t('Pattern')}
|
||||||
|
options={[
|
||||||
|
{ label: t('Editable'), value: 'editable' },
|
||||||
|
{ label: t('Readonly'), value: 'readonly' },
|
||||||
|
{ label: t('Easy-reading'), value: 'read-pretty' },
|
||||||
|
]}
|
||||||
|
value={readOnlyMode}
|
||||||
|
onChange={(v) => {
|
||||||
|
const schema: ISchema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (v) {
|
||||||
|
case 'readonly': {
|
||||||
|
fieldSchema['x-read-pretty'] = false;
|
||||||
|
fieldSchema['x-disabled'] = true;
|
||||||
|
schema['x-read-pretty'] = false;
|
||||||
|
schema['x-disabled'] = true;
|
||||||
|
field.readPretty = false;
|
||||||
|
field.disabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'read-pretty': {
|
||||||
|
fieldSchema['x-read-pretty'] = true;
|
||||||
|
fieldSchema['x-disabled'] = false;
|
||||||
|
schema['x-read-pretty'] = true;
|
||||||
|
schema['x-disabled'] = false;
|
||||||
|
field.readPretty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
fieldSchema['x-read-pretty'] = false;
|
||||||
|
fieldSchema['x-disabled'] = false;
|
||||||
|
schema['x-read-pretty'] = false;
|
||||||
|
schema['x-disabled'] = false;
|
||||||
|
field.readPretty = false;
|
||||||
|
field.disabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{collectionField?.target && ['CollectionField', 'AssociationSelect'].includes(fieldSchema['x-component']) && (
|
||||||
|
<SchemaSettings.SelectItem
|
||||||
|
key="title-field"
|
||||||
|
title={t('Title field')}
|
||||||
|
options={options}
|
||||||
|
value={field?.componentProps?.fieldNames?.label}
|
||||||
|
onChange={(label) => {
|
||||||
|
const schema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
const fieldNames = {
|
||||||
|
...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
|
||||||
|
...field.componentProps.fieldNames,
|
||||||
|
label,
|
||||||
|
};
|
||||||
|
field.componentProps.fieldNames = fieldNames;
|
||||||
|
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||||
|
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||||
|
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{collectionField && <SchemaSettings.Divider />}
|
||||||
|
<SchemaSettings.Remove
|
||||||
|
key="remove"
|
||||||
|
removeParentsIfNoChildren
|
||||||
|
confirm={{
|
||||||
|
title: t('Delete field'),
|
||||||
|
}}
|
||||||
|
breakRemoveOn={{
|
||||||
|
'x-component': 'Grid',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AssociationSelect;
|
@ -0,0 +1,10 @@
|
|||||||
|
import { observer } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { RemoteSelect } from '../remote-select';
|
||||||
|
import useServiceOptions from './useServiceOptions';
|
||||||
|
|
||||||
|
export const ReadPretty = observer((props: any) => {
|
||||||
|
const service = useServiceOptions(props);
|
||||||
|
|
||||||
|
return <RemoteSelect.ReadPretty {...props} service={service}></RemoteSelect.ReadPretty>;
|
||||||
|
});
|
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
path: /client
|
||||||
|
group:
|
||||||
|
path: /schema-components
|
||||||
|
---
|
||||||
|
|
||||||
|
# RemoteSelect
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
基于 Ant Design 的 [Select](https://ant.design/components/select/#API),相关扩展属性有:
|
||||||
|
|
||||||
|
- `objectValue` 值为 object 类型
|
||||||
|
- `fieldNames` 默认值有区别
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const defaultFieldNames = {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
color: 'color',
|
||||||
|
options: 'children',
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1 @@
|
|||||||
|
export * from './AssociationSelect';
|
@ -0,0 +1,20 @@
|
|||||||
|
import { useFieldSchema } from "@formily/react";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useCollection } from "../../../collection-manager";
|
||||||
|
|
||||||
|
export default function useServiceOptions(props) {
|
||||||
|
const { action = 'list', service } = props
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const collectionField = useMemo(() => {
|
||||||
|
return getField(fieldSchema.name);
|
||||||
|
}, [fieldSchema.name]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
resource: collectionField.target,
|
||||||
|
action,
|
||||||
|
...service,
|
||||||
|
};
|
||||||
|
}, [collectionField.target, action, service]);
|
||||||
|
}
|
@ -6,7 +6,7 @@ import { uid } from '@formily/shared';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useCompile, useDesignable } from '../..';
|
import { useCompile, useDesignable, useFieldComponentOptions } from '../../hooks';
|
||||||
import { useFilterByTk, useFormBlockContext } from '../../../block-provider';
|
import { useFilterByTk, useFormBlockContext } from '../../../block-provider';
|
||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
@ -41,7 +41,9 @@ export const FormItem: any = (props) => {
|
|||||||
__html: HTMLEncode(field.description).split('\n').join('<br/>'),
|
__html: HTMLEncode(field.description).split('\n').join('<br/>'),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : field.description
|
) : (
|
||||||
|
field.description
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
@ -56,13 +58,14 @@ FormItem.Designer = (props) => {
|
|||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { dn, refresh, insertAdjacent, insertBeforeBegin } = useDesignable();
|
const { dn, refresh, insertAdjacent } = useDesignable();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
const interfaceConfig = getInterface(collectionField?.interface);
|
const interfaceConfig = getInterface(collectionField?.interface);
|
||||||
const validateSchema = interfaceConfig?.['validateSchema']?.(fieldSchema);
|
const validateSchema = interfaceConfig?.['validateSchema']?.(fieldSchema);
|
||||||
const originalTitle = collectionField?.uiSchema?.title;
|
const originalTitle = collectionField?.uiSchema?.title;
|
||||||
const targetFields = collectionField?.target ? getCollectionFields(collectionField.target) : [];
|
const targetFields = collectionField?.target ? getCollectionFields(collectionField.target) : [];
|
||||||
|
const fieldComponentOptions = useFieldComponentOptions();
|
||||||
const isSubFormAssocitionField = field.address.segments.includes('__form_grid');
|
const isSubFormAssocitionField = field.address.segments.includes('__form_grid');
|
||||||
const initialValue = {
|
const initialValue = {
|
||||||
title: field.title === originalTitle ? undefined : field.title,
|
title: field.title === originalTitle ? undefined : field.title,
|
||||||
@ -328,62 +331,61 @@ FormItem.Designer = (props) => {
|
|||||||
)}
|
)}
|
||||||
{form && !form?.readPretty && collectionField?.uiSchema?.type && (
|
{form && !form?.readPretty && collectionField?.uiSchema?.type && (
|
||||||
<SchemaSettings.ModalItem
|
<SchemaSettings.ModalItem
|
||||||
title={t('Set default value')}
|
title={t('Set default value')}
|
||||||
components={{ ArrayCollapse, FormLayout }}
|
components={{ ArrayCollapse, FormLayout }}
|
||||||
schema={{
|
schema={
|
||||||
type: 'object',
|
{
|
||||||
title: t('Set default value'),
|
type: 'object',
|
||||||
properties: {
|
title: t('Set default value'),
|
||||||
default: {
|
properties: {
|
||||||
...collectionField.uiSchema,
|
default: {
|
||||||
name: 'default',
|
...collectionField.uiSchema,
|
||||||
title: t('Default value'),
|
name: 'default',
|
||||||
'x-decorator': 'FormItem',
|
title: t('Default value'),
|
||||||
default: fieldSchema.default || collectionField.defaultValue,
|
'x-decorator': 'FormItem',
|
||||||
|
default: fieldSchema.default || collectionField.defaultValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={(v) => {
|
||||||
|
const schema: ISchema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
if (field.value !== v.default) {
|
||||||
|
field.value = v.default;
|
||||||
}
|
}
|
||||||
}
|
fieldSchema.default = v.default;
|
||||||
} as ISchema}
|
schema.default = v.default;
|
||||||
onSubmit={(v) => {
|
dn.emit('patch', {
|
||||||
const schema: ISchema = {
|
schema,
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
});
|
||||||
};
|
refresh();
|
||||||
if (field.value !== v.default) {
|
}}
|
||||||
field.value = v.default;
|
/>
|
||||||
}
|
|
||||||
fieldSchema.default = v.default;
|
|
||||||
schema.default = v.default;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{form && !isSubFormAssocitionField && ['o2o', 'oho', 'obo', 'o2m'].includes(collectionField?.interface) && (
|
{form && !isSubFormAssocitionField && fieldComponentOptions && (
|
||||||
<SchemaSettings.SelectItem
|
<SchemaSettings.SelectItem
|
||||||
title={t('Field component')}
|
title={t('Field component')}
|
||||||
options={
|
options={fieldComponentOptions}
|
||||||
collectionField?.interface === 'o2m'
|
|
||||||
? [
|
|
||||||
{ label: t('Record picker'), value: 'CollectionField' },
|
|
||||||
{ label: t('Subtable'), value: 'TableField' },
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
{ label: t('Record picker'), value: 'CollectionField' },
|
|
||||||
{ label: t('Subform'), value: 'FormField' },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
value={fieldSchema['x-component']}
|
value={fieldSchema['x-component']}
|
||||||
onChange={(v) => {
|
onChange={(type) => {
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
name: collectionField.name,
|
name: collectionField.name,
|
||||||
type: 'void',
|
type: 'void',
|
||||||
// title: compile(collectionField.uiSchema?.title),
|
required: fieldSchema['required'],
|
||||||
|
description: fieldSchema['description'],
|
||||||
|
default: fieldSchema['default'],
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-designer': 'FormItem.Designer',
|
'x-designer': 'FormItem.Designer',
|
||||||
'x-component': v,
|
'x-component': type,
|
||||||
'x-component-props': {},
|
'x-validator': fieldSchema['x-validator'],
|
||||||
'x-collection-field': fieldSchema['x-collection-field'],
|
'x-collection-field': fieldSchema['x-collection-field'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
'x-component-props': {
|
||||||
|
...collectionField?.uiSchema?.['x-component-props'],
|
||||||
|
...fieldSchema['x-component-props'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
interfaceConfig?.schemaInitialize?.(schema, {
|
interfaceConfig?.schemaInitialize?.(schema, {
|
||||||
@ -393,10 +395,6 @@ FormItem.Designer = (props) => {
|
|||||||
action: tk ? 'get' : null,
|
action: tk ? 'get' : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (v === 'CollectionField') {
|
|
||||||
schema['type'] = 'string';
|
|
||||||
}
|
|
||||||
|
|
||||||
insertAdjacent('beforeBegin', divWrap(schema), {
|
insertAdjacent('beforeBegin', divWrap(schema), {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
dn.remove(null, {
|
dn.remove(null, {
|
||||||
|
@ -28,6 +28,8 @@ export * from './radio';
|
|||||||
export * from './record-picker';
|
export * from './record-picker';
|
||||||
export * from './rich-text';
|
export * from './rich-text';
|
||||||
export * from './select';
|
export * from './select';
|
||||||
|
export * from './remote-select';
|
||||||
|
export * from './association-select';
|
||||||
export * from './space';
|
export * from './space';
|
||||||
export * from './table';
|
export * from './table';
|
||||||
export * from './table-v2';
|
export * from './table-v2';
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
import { observer, useField } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { getValues } from './shared';
|
||||||
|
import { Select, defaultFieldNames } from '../select';
|
||||||
|
import { useRequest } from '../../../api-client';
|
||||||
|
|
||||||
|
export const ReadPretty = observer((props: any) => {
|
||||||
|
const fieldNames = { ...defaultFieldNames, ...props.fieldNames };
|
||||||
|
const field = useField<any>();
|
||||||
|
|
||||||
|
const { data } = useRequest(
|
||||||
|
{
|
||||||
|
action: 'list',
|
||||||
|
...props.service,
|
||||||
|
params: {
|
||||||
|
paginate: false,
|
||||||
|
filter: {
|
||||||
|
[fieldNames.value]: {
|
||||||
|
$in: getValues(field.value, fieldNames),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refreshDeps: [props.service, field.value],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return <Select.ReadPretty {...props} options={data?.data}></Select.ReadPretty>;
|
||||||
|
});
|
@ -0,0 +1,89 @@
|
|||||||
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
|
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
||||||
|
import { SelectProps } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
||||||
|
import { defaultFieldNames, Select } from '../select';
|
||||||
|
import { ReadPretty } from './ReadPretty';
|
||||||
|
|
||||||
|
export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
|
||||||
|
objectValue?: boolean;
|
||||||
|
onChange?: (v: any) => void;
|
||||||
|
target: string;
|
||||||
|
wait?: number;
|
||||||
|
service: ResourceActionOptions<P>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InternalRemoteSelect = connect(
|
||||||
|
(props: RemoteSelectProps) => {
|
||||||
|
const { fieldNames, service = {}, wait = 300, ...others } = props;
|
||||||
|
|
||||||
|
const { data, run } = useRequest(
|
||||||
|
{
|
||||||
|
action: 'list',
|
||||||
|
...service,
|
||||||
|
params: {
|
||||||
|
pageSize: 30,
|
||||||
|
...service?.params,
|
||||||
|
// search needs
|
||||||
|
filter: {
|
||||||
|
$and: [service?.params?.filter].filter(Boolean),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
debounceWait: wait,
|
||||||
|
refreshDeps: [service],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSearch = async (search) => {
|
||||||
|
run({
|
||||||
|
filter: {
|
||||||
|
$and: [
|
||||||
|
{
|
||||||
|
[fieldNames.label]: {
|
||||||
|
$includes: search,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
service?.params?.filter,
|
||||||
|
].filter(Boolean),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
autoClearSearchValue
|
||||||
|
filterOption={false}
|
||||||
|
filterSort={null}
|
||||||
|
fieldNames={fieldNames}
|
||||||
|
onSearch={onSearch}
|
||||||
|
{...others}
|
||||||
|
options={data?.data || []}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
mapProps(
|
||||||
|
{
|
||||||
|
dataSource: 'options',
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
(props, field) => {
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
fieldNames: { ...defaultFieldNames, ...props.fieldNames, ...field.componentProps.fieldNames },
|
||||||
|
suffixIcon: field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffixIcon,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
mapReadPretty(ReadPretty),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const RemoteSelect = InternalRemoteSelect as unknown as typeof InternalRemoteSelect & {
|
||||||
|
ReadPretty: typeof ReadPretty;
|
||||||
|
};
|
||||||
|
|
||||||
|
RemoteSelect.ReadPretty = ReadPretty;
|
||||||
|
export default RemoteSelect;
|
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
path: /client
|
||||||
|
group:
|
||||||
|
path: /schema-components
|
||||||
|
---
|
||||||
|
|
||||||
|
# RemoteSelect
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
基于 Ant Design 的 [Select](https://ant.design/components/select/#API),相关扩展属性有:
|
||||||
|
|
||||||
|
- `objectValue` 值为 object 类型
|
||||||
|
- `fieldNames` 默认值有区别
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const defaultFieldNames = {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
color: 'color',
|
||||||
|
options: 'children',
|
||||||
|
};
|
||||||
|
```
|
@ -0,0 +1 @@
|
|||||||
|
export * from './RemoteSelect';
|
@ -0,0 +1,7 @@
|
|||||||
|
import { castArray } from 'lodash';
|
||||||
|
|
||||||
|
export const getValues = (values, fieldNames) => {
|
||||||
|
return castArray(values)
|
||||||
|
.filter(item => item != null)
|
||||||
|
.map((val) => (typeof val === 'object' ? val[fieldNames.value] : val));
|
||||||
|
};
|
@ -7,7 +7,7 @@ import React from 'react';
|
|||||||
import { ReadPretty } from './ReadPretty';
|
import { ReadPretty } from './ReadPretty';
|
||||||
import { defaultFieldNames, getCurrentOptions } from './shared';
|
import { defaultFieldNames, getCurrentOptions } from './shared';
|
||||||
|
|
||||||
type Props = SelectProps<any, any> & { objectValue?: boolean; onChange?: (v: any) => void };
|
type Props = SelectProps<any, any> & { objectValue?: boolean; onChange?: (v: any) => void; multiple: boolean };
|
||||||
|
|
||||||
const isEmptyObject = (val: any) => !isValid(val) || (typeof val === 'object' && Object.keys(val).length === 0);
|
const isEmptyObject = (val: any) => !isValid(val) || (typeof val === 'object' && Object.keys(val).length === 0);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ const ObjectSelect = (props: Props) => {
|
|||||||
value: val[fieldNames.value],
|
value: val[fieldNames.value],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (['tags', 'multiple'].includes(mode)) {
|
if (['tags', 'multiple'].includes(mode) || props.multiple) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
return current.shift();
|
return current.shift();
|
||||||
@ -53,7 +53,7 @@ const ObjectSelect = (props: Props) => {
|
|||||||
options,
|
options,
|
||||||
fieldNames,
|
fieldNames,
|
||||||
);
|
);
|
||||||
if (['tags', 'multiple'].includes(mode)) {
|
if (['tags', 'multiple'].includes(mode) || props.multiple) {
|
||||||
onChange(current);
|
onChange(current);
|
||||||
} else {
|
} else {
|
||||||
onChange(current.shift());
|
onChange(current.shift());
|
||||||
@ -67,11 +67,13 @@ const ObjectSelect = (props: Props) => {
|
|||||||
|
|
||||||
const filterOption = (input, option) => (option?.label ?? '').toLowerCase().includes((input || '').toLowerCase());
|
const filterOption = (input, option) => (option?.label ?? '').toLowerCase().includes((input || '').toLowerCase());
|
||||||
|
|
||||||
export const Select = connect(
|
const InternalSelect = connect(
|
||||||
(props: Props) => {
|
(props: Props) => {
|
||||||
const { objectValue, ...others } = props;
|
const { objectValue, ...others } = props;
|
||||||
|
const mode = props.mode || props.multiple ? 'multiple' : undefined;
|
||||||
|
|
||||||
if (objectValue) {
|
if (objectValue) {
|
||||||
return <ObjectSelect {...others} />;
|
return <ObjectSelect {...others} mode={mode} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<AntdSelect
|
<AntdSelect
|
||||||
@ -80,9 +82,9 @@ export const Select = connect(
|
|||||||
allowClear
|
allowClear
|
||||||
{...others}
|
{...others}
|
||||||
onChange={(changed) => {
|
onChange={(changed) => {
|
||||||
props.onChange(changed === undefined ? null : changed);
|
props.onChange?.(changed === undefined ? null : changed);
|
||||||
}}
|
}}
|
||||||
value={others.value || undefined}
|
mode={mode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -102,4 +104,10 @@ export const Select = connect(
|
|||||||
mapReadPretty(ReadPretty),
|
mapReadPretty(ReadPretty),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const Select = InternalSelect as unknown as typeof InternalSelect & {
|
||||||
|
ReadPretty: typeof ReadPretty;
|
||||||
|
};
|
||||||
|
|
||||||
|
Select.ReadPretty = ReadPretty;
|
||||||
|
|
||||||
export default Select;
|
export default Select;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './Select';
|
export * from './Select';
|
||||||
|
export * from './shared'
|
||||||
|
@ -26,6 +26,7 @@ export const getCurrentOptions = (values, dataSource, fieldNames) => {
|
|||||||
.filter((item) => item != null)
|
.filter((item) => item != null)
|
||||||
.map((val) => (typeof val === 'object' ? val[fieldNames.value] : val));
|
.map((val) => (typeof val === 'object' ? val[fieldNames.value] : val));
|
||||||
const findOptions = (options: any[]) => {
|
const findOptions = (options: any[]) => {
|
||||||
|
if (!options) return []
|
||||||
let current = [];
|
let current = [];
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
const option = options.find((v) => v[fieldNames.value] === value) || { value: value, label: value };
|
const option = options.find((v) => v[fieldNames.value] === value) || { value: value, label: value };
|
||||||
|
@ -5,4 +5,5 @@ export * from './useDesignable';
|
|||||||
export * from './useDesigner';
|
export * from './useDesigner';
|
||||||
export * from './useFieldProps';
|
export * from './useFieldProps';
|
||||||
export * from './useSchemaComponentContext';
|
export * from './useSchemaComponentContext';
|
||||||
|
export * from './useFieldComponentOptions';
|
||||||
|
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
import { useFieldSchema } from "@formily/react";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useCollectionManager, useCollection } from "../../collection-manager";
|
||||||
|
|
||||||
|
export const useFieldComponentOptions = () => {
|
||||||
|
const { getCollectionJoinField } = useCollectionManager();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const fieldComponentOptions = useMemo(() => {
|
||||||
|
if (!collectionField?.interface) return;
|
||||||
|
switch (collectionField.interface) {
|
||||||
|
case 'o2m':
|
||||||
|
return [
|
||||||
|
{ label: t('Record picker'), value: 'CollectionField' },
|
||||||
|
{ label: t('Subtable'), value: 'TableField' },
|
||||||
|
{ label: t('Select'), value: 'AssociationSelect' },
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'm2o':
|
||||||
|
case 'm2m':
|
||||||
|
case 'linkTo':
|
||||||
|
return [
|
||||||
|
{ label: t('Record picker'), value: 'CollectionField' },
|
||||||
|
{ label: t('Select'), value: 'AssociationSelect' },
|
||||||
|
]
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
{ label: t('Record picker'), value: 'CollectionField' },
|
||||||
|
{ label: t('Subform'), value: 'FormField' },
|
||||||
|
{ label: t('Select'), value: 'AssociationSelect' },
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [t, collectionField?.interface]);
|
||||||
|
|
||||||
|
return fieldComponentOptions;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user