diff --git a/packages/core/client/src/modules/fields/component/Cascader/cascaderComponentFieldSettings.tsx b/packages/core/client/src/modules/fields/component/Cascader/cascaderComponentFieldSettings.tsx new file mode 100644 index 000000000..cde650901 --- /dev/null +++ b/packages/core/client/src/modules/fields/component/Cascader/cascaderComponentFieldSettings.tsx @@ -0,0 +1,390 @@ +import { Field } from '@formily/core'; +import { ISchema, useField, useFieldSchema } from '@formily/react'; +import _ from 'lodash'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings'; +import { useFormBlockContext } from '../../../../block-provider'; +import { + useCollectionManager_deprecated, + useCollection_deprecated, + useSortFields, +} from '../../../../collection-manager'; +import { useFieldComponentName } from '../../../../common/useFieldComponentName'; +import { useRecord } from '../../../../record-provider'; +import { removeNullCondition, useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component'; +import { isSubMode } from '../../../../schema-component/antd/association-field/util'; +import { DynamicComponentProps } from '../../../../schema-component/antd/filter/DynamicComponent'; +import { + useIsAssociationField, + useIsFieldReadPretty, + useIsSelectFieldMode, + useTitleFieldOptions, +} from '../../../../schema-component/antd/form-item/FormItem.Settings'; +import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator'; +import { SchemaSettingsModalItem, VariableInput, getShouldChange } from '../../../../schema-settings'; +import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope'; +import { useLocalVariables, useVariables } from '../../../../variables'; +import { useCollectionField } from '../utils'; +import { ArrayItems } from '@formily/antd-v5'; + +export const SchemaSettingsSortingRule = function SortRuleConfigure(props) { + const field = useField(); + const { dn } = useDesignable(); + const { t } = useTranslation(); + const currentSchema = useFieldSchema(); + const { getField } = useCollection_deprecated(); + const { getCollectionJoinField } = useCollectionManager_deprecated(); + const fieldSchema = props?.fieldSchema ?? currentSchema; + const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']); + const sortFields = useSortFields(collectionField?.target); + const defaultSort = fieldSchema['x-component-props']?.service?.params?.sort || []; + const sort = defaultSort?.map((item: string) => { + return item?.startsWith('-') + ? { + field: item.substring(1), + direction: 'desc', + } + : { + field: item, + direction: 'asc', + }; + }); + return ( + { + const sortArr = sort.map((item) => { + return item.direction === 'desc' ? `-${item.field}` : item.field; + }); + _.set(field.componentProps, 'service.params.sort', sortArr); + props?.onSubmitCallBack?.(sortArr); + fieldSchema['x-component-props']['service']['params']['sort'] = field.componentProps?.service.params?.sort; + const componentProps = fieldSchema['x-component-props']; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-component-props': componentProps, + }, + }); + }} + /> + ); +}; + +const titleField: any = { + name: 'titleField', + type: 'select', + useComponentProps() { + const { t } = useTranslation(); + const field = useField(); + const { dn } = useDesignable(); + const options = useTitleFieldOptions(); + const { uiSchema, fieldSchema: tableColumnSchema, collectionField: tableColumnField } = useColumnSchema(); + const schema = useFieldSchema(); + const fieldSchema = tableColumnSchema || schema; + const targetCollectionField = useCollectionField(); + const collectionField = tableColumnField || targetCollectionField; + // 处理多对一关系标题显示 + const { getCollectionFields } = useCollectionManager_deprecated(); + const fieldNames = { + ...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'], + ...field?.componentProps?.fieldNames, + ...fieldSchema?.['x-component-props']?.['fieldNames'], + }; + return { + title: t('Title field'), + options, + value: fieldNames?.label, + onChange(label) { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + const newFieldNames = { + ...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'], + ...fieldSchema['x-component-props']?.['fieldNames'], + label, + }; + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + fieldSchema['x-component-props']['fieldNames'] = newFieldNames; + // 处理多对一关系标题显示 + const target = getCollectionFields(collectionField.target).find((field) => field.name === label); + if (target.interface === 'm2o') { + fieldSchema['x-component-props']['x-next-title'] = { + label, + collection: target.collectionName, + }; + } else { + fieldSchema['x-component-props']['x-next-title'] = null; + } + schema['x-component-props'] = fieldSchema['x-component-props']; + field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames; + const path = field.path?.splice(field.path?.length - 1, 1); + field.form.query(`${path.concat(`*.` + fieldSchema.name)}`).forEach((f) => { + f.componentProps.fieldNames = newFieldNames; + }); + dn.emit('patch', { + schema, + }); + + dn.refresh(); + }, + }; + }, +}; + +export const allowMultiple: any = { + name: 'allowMultiple', + type: 'switch', + useVisible() { + const isFieldReadPretty = useIsFieldReadPretty(); + const collectionField = useCollectionField(); + return !isFieldReadPretty && ['hasMany', 'belongsToMany'].includes(collectionField?.type); + }, + useComponentProps() { + const { t } = useTranslation(); + const field = useField(); + const { fieldSchema: tableColumnSchema } = useColumnSchema(); + const schema = useFieldSchema(); + const fieldSchema = tableColumnSchema || schema; + const { dn, refresh } = useDesignable(); + return { + title: t('Allow multiple'), + checked: + fieldSchema['x-component-props']?.multiple === undefined ? true : fieldSchema['x-component-props'].multiple, + onChange(value) { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + field.componentProps = field.componentProps || {}; + + fieldSchema['x-component-props'].multiple = value; + field.componentProps.multiple = value; + + schema['x-component-props'] = fieldSchema['x-component-props']; + dn.emit('patch', { + schema, + }); + refresh(); + }, + }; + }, +}; + +const setDefaultSortingRules = { + name: 'setDefaultSortingRules', + Component: SchemaSettingsSortingRule, +}; + +const setTheDataScope: any = { + name: 'setTheDataScope', + Component: SchemaSettingsDataScope, + useComponentProps() { + const { getCollectionJoinField, getAllCollectionsInheritChain } = useCollectionManager_deprecated(); + const { getField } = useCollection_deprecated(); + const { form } = useFormBlockContext(); + const record = useRecord(); + const field = useField(); + const { fieldSchema: tableColumnSchema, collectionField: tableColumnField } = useColumnSchema(); + const schema = useFieldSchema(); + const fieldSchema = tableColumnSchema || schema; + const collectionField = + tableColumnField || getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']); + const variables = useVariables(); + const localVariables = useLocalVariables(); + const { dn } = useDesignable(); + return { + collectionName: collectionField?.target, + defaultFilter: fieldSchema?.['x-component-props']?.service?.params?.filter || {}, + form, + dynamicComponent: (props: DynamicComponentProps) => { + return ( + + ); + }, + onSubmit: ({ filter }) => { + filter = removeNullCondition(filter); + _.set(field.componentProps, 'service.params.filter', filter); + fieldSchema['x-component-props']['service']['params']['filter'] = filter; + const componentProps = fieldSchema['x-component-props']; + const path = field.path?.splice(field.path?.length - 1, 1); + field.form.query(`${path.concat(`*.` + fieldSchema.name)}`).forEach((f) => { + f.componentProps = componentProps; + }); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-component-props': componentProps, + }, + }); + dn.refresh(); + }, + }; + }, +}; + +const fieldComponent: any = { + name: 'fieldComponent', + type: 'select', + useComponentProps() { + const { t } = useTranslation(); + const field = useField(); + const { fieldSchema: tableColumnSchema, collectionField } = useColumnSchema(); + const schema = useFieldSchema(); + const fieldSchema = tableColumnSchema || schema; + const fieldModeOptions = useFieldModeOptions({ fieldSchema: tableColumnSchema, collectionField }); + const isAddNewForm = useIsAddNewForm(); + const fieldMode = useFieldComponentName(); + const { dn } = useDesignable(); + return { + title: t('Field component'), + options: fieldModeOptions, + value: fieldMode, + onChange(mode) { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + fieldSchema['x-component-props']['mode'] = mode; + schema['x-component-props'] = fieldSchema['x-component-props']; + field.componentProps = field.componentProps || {}; + field.componentProps.mode = mode; + + // 子表单状态不允许设置默认值 + if (isSubMode(fieldSchema) && isAddNewForm) { + // @ts-ignore + schema.default = null; + fieldSchema.default = null; + field?.setInitialValue?.(null); + field?.setValue?.(null); + } + + void dn.emit('patch', { + schema, + }); + dn.refresh(); + }, + }; + }, +}; + +export const cascaderComponentFieldSettings = new SchemaSettings({ + name: 'fieldSettings:component:Cascader', + items: [ + { + ...fieldComponent, + useVisible: useIsAssociationField, + }, + { + ...setTheDataScope, + useVisible() { + const isSelectFieldMode = useIsSelectFieldMode(); + const isFieldReadPretty = useIsFieldReadPretty(); + return isSelectFieldMode && !isFieldReadPretty; + }, + }, + { + ...setDefaultSortingRules, + useComponentProps() { + const { fieldSchema } = useColumnSchema(); + return { + fieldSchema, + }; + }, + useVisible() { + const isSelectFieldMode = useIsSelectFieldMode(); + const isFieldReadPretty = useIsFieldReadPretty(); + return isSelectFieldMode && !isFieldReadPretty; + }, + }, + { + ...titleField, + useVisible: useIsAssociationField, + }, + ], +}); diff --git a/packages/core/client/src/modules/fields/component/Select/selectComponentFieldSettings.tsx b/packages/core/client/src/modules/fields/component/Select/selectComponentFieldSettings.tsx index f107afef3..876b0f833 100644 --- a/packages/core/client/src/modules/fields/component/Select/selectComponentFieldSettings.tsx +++ b/packages/core/client/src/modules/fields/component/Select/selectComponentFieldSettings.tsx @@ -116,6 +116,7 @@ const titleField: any = { dn.emit('patch', { schema, }); + dn.refresh(); }, }; diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx index 1a3b56449..4c106227a 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalCascader.tsx @@ -4,11 +4,11 @@ import { FormProvider, connect, createSchemaField, observer, useField, useFieldS import { uid } from '@formily/shared'; import { Input, Space, Spin, Tag } from 'antd'; import dayjs from 'dayjs'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { css, useAPIClient, useCollectionManager_deprecated } from '../../..'; import { mergeFilter } from '../../../filter-provider/utils'; -import { CustomCascader, SchemaComponent, useCompile } from '../..'; +import { CustomCascader, SchemaComponent, useCompile, useDesignable } from '../..'; import useServiceOptions, { useAssociationFieldContext } from './hooks'; const EMPTY = 'N/A'; @@ -25,30 +25,21 @@ const Cascade = connect((props) => { const { data, mapOptions, onChange } = props; const [selectedOptions, setSelectedOptions] = useState([]); const [options, setOptions] = useState(data); + const fieldSchema = useFieldSchema(); const [loading, setLoading] = useState(false); - const compile = useCompile(); const api = useAPIClient(); - const service = useServiceOptions(props); const { options: collectionField, field: associationField } = useAssociationFieldContext(); const resource = api.resource(collectionField.target); - const { getCollectionJoinField, getInterface } = useCollectionManager_deprecated(); const fieldNames = associationField?.componentProps?.fieldNames; - const FieldSchema = useFieldSchema(); - const targetField = - collectionField?.target && - fieldNames?.label && - getCollectionJoinField(`${collectionField.target}.${fieldNames.label}`); - const operator = useMemo(() => { - if (targetField?.interface) { - return getInterface(targetField.interface)?.filterable?.operators[0].value || '$includes'; - } - return '$includes'; - }, [targetField]); + const fieldFilter = fieldSchema['x-component-props']['service']['params']['filter']; const field: any = useField(); useEffect(() => { if (props.value) { const values = Array.isArray(props.value) - ? extractLastNonNullValueObjects(props.value?.filter((v) => v.value), true) + ? extractLastNonNullValueObjects( + props.value?.filter((v) => v.value), + true, + ) : transformNestedData(props.value); const defaultData = values?.map?.((v) => { return v.id; @@ -60,11 +51,9 @@ const Cascade = connect((props) => { const handleGetOptions = async () => { const response = await resource.list({ pageSize: 9999, - params: service?.params, - filter: mergeFilter([service?.params?.filter, filter]), + filter: mergeFilter([fieldFilter, filter]), tree: true, }); - return response?.data?.data; }; @@ -139,6 +128,9 @@ const Cascade = connect((props) => { defaultValue={selectedOptions} options={options} onChange={(value, option) => handleSelect(option)} + onDropdownVisibleChange={(visible) => { + onDropdownVisibleChange(visible); + }} changeOnSelect placeholder="Please select" /> @@ -218,6 +210,7 @@ export const InternalCascader = observer( ...props, style: { width: '100%' }, }, + 'x-read-pretty': 'false', }, remove: { type: 'void', diff --git a/packages/core/client/src/schema-component/antd/select/Select.tsx b/packages/core/client/src/schema-component/antd/select/Select.tsx index 3d9784817..35781655e 100644 --- a/packages/core/client/src/schema-component/antd/select/Select.tsx +++ b/packages/core/client/src/schema-component/antd/select/Select.tsx @@ -40,7 +40,6 @@ const ObjectSelect = (props: Props) => { } return currentOptions.shift(); }; - return (