diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index ec0d0f67a..26a7be048 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -313,6 +313,7 @@ export default { "Display field title": "显示字段标题", "Field component": "字段组件", "Allow multiple": "允许添加/关联多条", + "Allow dissociate": "允许移除已关联记录", "Quick upload": "快速上传", "Select file": "选择文件", "Subtable": "子表格", diff --git a/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx b/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx index ef9ddcde6..7dd6806f5 100644 --- a/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx @@ -9,6 +9,7 @@ export const AssociationFieldProvider = observer((props) => { const { getCollectionJoinField, getCollection } = useCollectionManager(); const fieldSchema = useFieldSchema(); const allowMultiple = fieldSchema['x-component-props']?.multiple !== false; + const allowDissociate = fieldSchema['x-component-props']?.allowDissociate !== false; const collectionField = useMemo( () => getCollectionJoinField(fieldSchema['x-collection-field']), @@ -24,7 +25,9 @@ export const AssociationFieldProvider = observer((props) => { ); return collectionField ? ( - + {props.children} ) : null; diff --git a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx index 5d8fe4d52..33339666a 100644 --- a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx @@ -24,14 +24,18 @@ const ToOneNester = (props) => { const ToManyNester = observer((props) => { const fieldSchema = useFieldSchema(); - const { field, allowMultiple } = useAssociationFieldContext(); + const { options, field, allowMultiple, allowDissociate } = useAssociationFieldContext(); const { t } = useTranslation(); return ( {(field.value || []).map((value, index) => { + let allowed = allowDissociate; + if (!allowDissociate) { + allowed = !value?.[options.targetKey]; + } return ( <> - {!field.readPretty && ( + {!field.readPretty && allowed && (
({}); diff --git a/packages/core/client/src/schema-component/antd/association-field/hooks.ts b/packages/core/client/src/schema-component/antd/association-field/hooks.ts index e5e47b9a8..203249a95 100644 --- a/packages/core/client/src/schema-component/antd/association-field/hooks.ts +++ b/packages/core/client/src/schema-component/antd/association-field/hooks.ts @@ -35,6 +35,7 @@ export function useAssociationFieldContext() { field: F; currentMode: string; allowMultiple?: boolean; + allowDissociate?: boolean; }; } diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index 66f9a54d0..ea0c58d65 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -3,6 +3,7 @@ import { ArrayCollapse, ArrayItems, FormLayout, FormItem as Item } from '@formil import { Field } from '@formily/core'; import { ISchema, Schema, observer, useField, useFieldSchema } from '@formily/react'; import { uid } from '@formily/shared'; +import { Select } from 'antd'; import _ from 'lodash'; import moment from 'moment'; import React, { useContext, useEffect } from 'react'; @@ -32,7 +33,6 @@ import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent'; import { isInvariable } from '../variable'; import { FilterFormDesigner } from './FormItem.FilterFormDesigner'; import { useEnsureOperatorsValid } from './SchemaSettingOptions'; -import { Select } from 'antd'; const defaultInputStyle = css` & > .nb-form-item { @@ -175,6 +175,7 @@ FormItem.Designer = function Designer() { const fieldSchemaWithoutRequired = _.omit(fieldSchema, 'required'); + const isSubFormMode = fieldSchema['x-component-props'].mode === 'Nester'; const isPickerMode = fieldSchema['x-component-props'].mode === 'Picker'; const showFieldMode = isAssociationField && fieldModeOptions && !isTableField; const showModeSelect = showFieldMode && isPickerMode; @@ -687,6 +688,29 @@ FormItem.Designer = function Designer() { }} /> ) : null} + {IsShowMultipleSwitch() && isSubFormMode ? ( + { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + field.componentProps = field.componentProps || {}; + + fieldSchema['x-component-props'].allowDissociate = value; + field.componentProps.allowDissociate = value; + + schema['x-component-props'] = fieldSchema['x-component-props']; + dn.emit('patch', { + schema, + }); + refresh(); + }} + /> + ) : null} {field.readPretty && options.length > 0 && fieldSchema['x-component'] === 'CollectionField' && !isFileField && (