feat(data-template): support to set data scope and title field (#1918)
* refactor: optimize * feat(Data-template): support to set data scope and title field * fix: fix error when no template data * fix: fix error * fix: operator * chore: remove id * fix: filter * fix: should be global * fix: submit * fix: global sync * fix: title field * fix: fix filter * fix: fix first created * fix: collection * fix: collection * fix: collection * chore: should show N/A * Revert "chore: should show N/A" This reverts commit 00c91d77612aea0801fec88b5f3f91e4be999439. * chore: should show N/A * chore: remove useless code
This commit is contained in:
parent
c722ca41d9
commit
e61568ac57
@ -74,7 +74,7 @@ const CurrentFields = (props) => {
|
||||
const { resource, targetKey } = props.collectionResource || {};
|
||||
const { [targetKey]: filterByTk, titleField } = useRecord();
|
||||
const [loadingRecord, setLoadingRecord] = React.useState<any>(null);
|
||||
const { updateCollection, refreshCM } = useCollectionManager();
|
||||
const { refreshCM } = useCollectionManager();
|
||||
|
||||
const columns: TableColumnProps<any>[] = [
|
||||
{
|
||||
@ -180,7 +180,7 @@ const InheritFields = (props) => {
|
||||
const { [targetKey]: filterByTk, titleField, name } = useRecord();
|
||||
const [loadingRecord, setLoadingRecord] = React.useState(null);
|
||||
const { t } = useTranslation();
|
||||
const { updateCollection, refreshCM } = useCollectionManager();
|
||||
const { refreshCM } = useCollectionManager();
|
||||
|
||||
const columns: TableColumnProps<any>[] = [
|
||||
{
|
||||
@ -265,7 +265,7 @@ const InheritFields = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const CollectionFields = (props) => {
|
||||
export const CollectionFields = () => {
|
||||
const compile = useCompile();
|
||||
const field = useField<Field>();
|
||||
const { name } = useRecord();
|
||||
|
@ -160,7 +160,7 @@ AssociationSelect.Designer = function Designer() {
|
||||
readOnlyMode = 'read-pretty';
|
||||
}
|
||||
|
||||
const fieldSchemaWithoutRequired = _.omit(fieldSchema,'required')
|
||||
const fieldSchemaWithoutRequired = _.omit(fieldSchema, 'required');
|
||||
|
||||
return (
|
||||
<GeneralSchemaDesigner>
|
||||
|
@ -8,7 +8,15 @@ import { useAPIClient } from '../../../api-client';
|
||||
import { findFormBlock } from '../../../block-provider';
|
||||
import { useCollectionManager } from '../../../collection-manager';
|
||||
|
||||
interface ITemplate {
|
||||
export interface ITemplate {
|
||||
config?: {
|
||||
[key: string]: {
|
||||
/** 设置的数据范围 */
|
||||
filter?: any;
|
||||
/** 设置的标题字段 */
|
||||
titleField?: string;
|
||||
};
|
||||
};
|
||||
items: {
|
||||
key: string;
|
||||
title: string;
|
||||
@ -31,7 +39,7 @@ const useDataTemplates = () => {
|
||||
items.forEach((item) => {
|
||||
try {
|
||||
item.fields = item.fields
|
||||
.map((field) => {
|
||||
?.map((field) => {
|
||||
const joinField = getCollectionJoinField(`${item.collection}.${field}`);
|
||||
if (joinField) {
|
||||
return field;
|
||||
@ -57,7 +65,7 @@ const useDataTemplates = () => {
|
||||
templates,
|
||||
display,
|
||||
defaultTemplate,
|
||||
enabled: items.length > 0,
|
||||
enabled: items.length > 0 && items.every((item) => item.dataId !== undefined),
|
||||
};
|
||||
};
|
||||
|
||||
@ -68,7 +76,7 @@ export const Templates = ({ style = {}, form }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultTemplate) {
|
||||
if (enabled && defaultTemplate) {
|
||||
fetchTemplateData(api, defaultTemplate, t)
|
||||
.then((data) => {
|
||||
if (form && data) {
|
||||
|
@ -7,10 +7,11 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
||||
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||
import { useCompile } from '../../hooks';
|
||||
import { Select, defaultFieldNames } from '../select';
|
||||
import { ReadPretty } from './ReadPretty';
|
||||
|
||||
const EMPTY = 'N/A';
|
||||
|
||||
export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
|
||||
objectValue?: boolean;
|
||||
onChange?: (v: any) => void;
|
||||
@ -35,7 +36,6 @@ const InternalRemoteSelect = connect(
|
||||
targetField: _targetField,
|
||||
...others
|
||||
} = props;
|
||||
const compile = useCompile();
|
||||
const firstRun = useRef(false);
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
@ -58,49 +58,51 @@ const InternalRemoteSelect = connect(
|
||||
const mapOptionsToTags = useCallback(
|
||||
(options) => {
|
||||
try {
|
||||
return options.map((option) => {
|
||||
let label = option[fieldNames.label];
|
||||
return options
|
||||
.map((option) => {
|
||||
let label = option[fieldNames.label];
|
||||
|
||||
if (targetField?.uiSchema?.enum) {
|
||||
if (Array.isArray(label)) {
|
||||
label = label
|
||||
.map((item, index) => {
|
||||
const option = targetField.uiSchema.enum.find((i) => i.value === item);
|
||||
if (option) {
|
||||
return (
|
||||
<Tag key={index} color={option.color} style={{ marginRight: 3 }}>
|
||||
{option?.label || item}
|
||||
</Tag>
|
||||
);
|
||||
} else {
|
||||
return <Tag>{item}</Tag>;
|
||||
}
|
||||
})
|
||||
.reverse();
|
||||
} else {
|
||||
const item = targetField.uiSchema.enum.find((i) => i.value === label);
|
||||
if (item) {
|
||||
label = <Tag color={item.color}>{item.label}</Tag>;
|
||||
if (targetField?.uiSchema?.enum) {
|
||||
if (Array.isArray(label)) {
|
||||
label = label
|
||||
.map((item, index) => {
|
||||
const option = targetField.uiSchema.enum.find((i) => i.value === item);
|
||||
if (option) {
|
||||
return (
|
||||
<Tag key={index} color={option.color} style={{ marginRight: 3 }}>
|
||||
{option?.label || item}
|
||||
</Tag>
|
||||
);
|
||||
} else {
|
||||
return <Tag key={item}>{item}</Tag>;
|
||||
}
|
||||
})
|
||||
.reverse();
|
||||
} else {
|
||||
const item = targetField.uiSchema.enum.find((i) => i.value === label);
|
||||
if (item) {
|
||||
label = <Tag color={item.color}>{item.label}</Tag>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetField?.type === 'date') {
|
||||
label = moment(label).format('YYYY-MM-DD');
|
||||
}
|
||||
if (targetField?.type === 'date') {
|
||||
label = moment(label).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (mapOptions) {
|
||||
return mapOptions({
|
||||
[fieldNames.label]: label,
|
||||
if (mapOptions) {
|
||||
return mapOptions({
|
||||
[fieldNames.label]: label || EMPTY,
|
||||
[fieldNames.value]: option[fieldNames.value],
|
||||
});
|
||||
}
|
||||
return {
|
||||
...option,
|
||||
[fieldNames.label]: label || EMPTY,
|
||||
[fieldNames.value]: option[fieldNames.value],
|
||||
});
|
||||
}
|
||||
return {
|
||||
...option,
|
||||
[fieldNames.label]: label || option[fieldNames.value],
|
||||
[fieldNames.value]: option[fieldNames.value],
|
||||
};
|
||||
});
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return options;
|
||||
|
@ -35,7 +35,7 @@ export const SchemaComponentProvider: React.FC<ISchemaComponentProvider> = (prop
|
||||
const { designable, components, children } = props;
|
||||
const [, setUid] = useState(uid());
|
||||
const [formId, setFormId] = useState(uid());
|
||||
const form = props.form || useMemo(() => createForm(), [formId]);
|
||||
const form = useMemo(() => props.form || createForm(), [formId]);
|
||||
const { t } = useTranslation();
|
||||
const scope = { ...props.scope, t, randomString };
|
||||
const [active, setActive] = useCookieState('useCookieDesignable', {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { ISchema, useField, useFieldSchema,observer } from '@formily/react';
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ISchema, observer, useField, useFieldSchema } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useCollectionManager, useCollection } from '../collection-manager';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCollection, useCollectionManager } from '../collection-manager';
|
||||
import { useDesignable } from '../schema-component';
|
||||
import { SchemaSettings } from '../schema-settings';
|
||||
|
||||
@ -18,7 +17,6 @@ export const GeneralSchemaItems: React.FC<{
|
||||
const { t } = useTranslation();
|
||||
const { dn, refresh } = useDesignable();
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
console.log(field,field.decoratorProps )
|
||||
return (
|
||||
<>
|
||||
{collectionField && (
|
||||
|
@ -1,11 +1,22 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { connect, mapProps, observer } from '@formily/react';
|
||||
import { observable } from '@formily/reactive';
|
||||
import { Tree as AntdTree } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { mergeFilter } from '../../block-provider';
|
||||
import { useCollectionManager } from '../../collection-manager';
|
||||
import { AssociationSelect, SchemaComponent } from '../../schema-component';
|
||||
import {
|
||||
AssociationSelect,
|
||||
SchemaComponent,
|
||||
SchemaComponentContext,
|
||||
removeNullCondition,
|
||||
} from '../../schema-component';
|
||||
import { ITemplate } from '../../schema-component/antd/form-v2/Templates';
|
||||
import { AsDefaultTemplate } from './components/AsDefaultTemplate';
|
||||
import { ArrayCollapse } from './components/DataTemplateTitle';
|
||||
import { Designer, getSelectedIdFilter } from './components/Designer';
|
||||
import { useCollectionState } from './hooks/useCollectionState';
|
||||
|
||||
const Tree = connect(
|
||||
@ -18,22 +29,60 @@ const Tree = connect(
|
||||
);
|
||||
|
||||
export const FormDataTemplates = observer((props: any) => {
|
||||
const { useProps } = props;
|
||||
const { useProps, formSchema, designerCtx } = props;
|
||||
const { defaultValues, collectionName } = useProps();
|
||||
const { collectionList, getEnableFieldTree, onLoadData, onCheck } = useCollectionState(collectionName);
|
||||
const { getCollection, getCollectionField } = useCollectionManager();
|
||||
const collection = getCollection(collectionName);
|
||||
const { t } = useTranslation();
|
||||
const field = getCollectionField(`${collectionName}.${collection?.titleField || 'id'}`);
|
||||
|
||||
// 不要在后面的数组中依赖 defaultValues,否则会因为 defaultValues 的变化导致 activeData 响应性丢失
|
||||
const activeData = useMemo<ITemplate>(
|
||||
() =>
|
||||
observable(
|
||||
defaultValues || { items: [], display: true, config: { [collectionName]: { titleField: '', filter: {} } } },
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
const getTargetField = (collectionName: string) => {
|
||||
const collection = getCollection(collectionName);
|
||||
return getCollectionField(
|
||||
`${collectionName}.${activeData?.config[collectionName]?.titleField || collection?.titleField || 'id'}`,
|
||||
);
|
||||
};
|
||||
|
||||
const getFieldNames = (collectionName: string) => {
|
||||
const collection = getCollection(collectionName);
|
||||
return {
|
||||
label: getLabel(activeData.config?.[collectionName]?.titleField || collection?.titleField || 'id'),
|
||||
value: 'id',
|
||||
};
|
||||
};
|
||||
|
||||
const getFilter = (collectionName: string, value: any) => {
|
||||
const filter = activeData.config?.[collectionName]?.filter;
|
||||
return _.isEmpty(filter) ? {} : removeNullCondition(mergeFilter([filter, getSelectedIdFilter(value)], '$or'));
|
||||
};
|
||||
|
||||
const components = useMemo(() => ({ ArrayCollapse }), []);
|
||||
const scope = useMemo(() => ({ getEnableFieldTree }), []);
|
||||
const scope = useMemo(
|
||||
() => ({
|
||||
getEnableFieldTree,
|
||||
getTargetField,
|
||||
getFieldNames,
|
||||
getFilter,
|
||||
getResource,
|
||||
collectionName,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const schema = useMemo(
|
||||
() => ({
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array',
|
||||
default: defaultValues?.items,
|
||||
default: activeData?.items,
|
||||
'x-component': 'ArrayCollapse',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component-props': {
|
||||
@ -58,7 +107,7 @@ export const FormDataTemplates = observer((props: any) => {
|
||||
title: '{{ t("Collection") }}',
|
||||
required: true,
|
||||
description: t('If collection inherits, choose inherited collections as templates'),
|
||||
default: collectionName,
|
||||
default: '{{ collectionName }}',
|
||||
'x-display': collectionList.length > 1 ? 'visible' : 'hidden',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
@ -71,36 +120,27 @@ export const FormDataTemplates = observer((props: any) => {
|
||||
title: '{{ t("Template Data") }}',
|
||||
required: true,
|
||||
description: t('Select an existing piece of data as the initialization data for the form'),
|
||||
'x-designer': Designer,
|
||||
'x-designer-props': {
|
||||
formSchema,
|
||||
data: activeData,
|
||||
},
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': AssociationSelect,
|
||||
'x-component-props': {
|
||||
service: {
|
||||
resource: collectionName,
|
||||
resource: '{{ $record.collection || collectionName }}',
|
||||
params: {
|
||||
filter: '{{ getFilter($self.componentProps.service.resource, $self.value) }}',
|
||||
},
|
||||
},
|
||||
action: 'list',
|
||||
multiple: false,
|
||||
objectValue: false,
|
||||
manual: false,
|
||||
targetField: field,
|
||||
mapOptions(option) {
|
||||
try {
|
||||
const label = getLabel(collection);
|
||||
option[label] = (
|
||||
<>
|
||||
#{option.id} {option[label]}
|
||||
</>
|
||||
);
|
||||
|
||||
return option;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return option;
|
||||
}
|
||||
},
|
||||
fieldNames: {
|
||||
label: getLabel(collection),
|
||||
value: 'id',
|
||||
},
|
||||
targetField: '{{ getTargetField($self.componentProps.service.resource) }}',
|
||||
mapOptions: getMapOptions(),
|
||||
fieldNames: '{{ getFieldNames($self.componentProps.service.resource) }}',
|
||||
},
|
||||
'x-reactions': [
|
||||
{
|
||||
@ -110,7 +150,7 @@ export const FormDataTemplates = observer((props: any) => {
|
||||
disabled: '{{ !$deps[0] }}',
|
||||
componentProps: {
|
||||
service: {
|
||||
resource: '{{ $deps[0] }}',
|
||||
resource: '{{ getResource($deps[0], $self) }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -182,7 +222,7 @@ export const FormDataTemplates = observer((props: any) => {
|
||||
display: {
|
||||
type: 'boolean',
|
||||
'x-content': '{{ t("Display data template selector") }}',
|
||||
default: defaultValues?.display !== false,
|
||||
default: activeData?.display !== false,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
},
|
||||
@ -191,9 +231,30 @@ export const FormDataTemplates = observer((props: any) => {
|
||||
[],
|
||||
);
|
||||
|
||||
return <SchemaComponent components={components} scope={scope} schema={schema} />;
|
||||
return (
|
||||
<SchemaComponentContext.Provider value={{ ...designerCtx, designable: true }}>
|
||||
<SchemaComponent components={components} scope={scope} schema={schema} />
|
||||
</SchemaComponentContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
function getLabel(collection: any) {
|
||||
return !collection?.titleField || collection.titleField === 'id' ? 'label' : collection?.titleField;
|
||||
export function getLabel(titleField) {
|
||||
return titleField || 'label';
|
||||
}
|
||||
|
||||
function getMapOptions() {
|
||||
return (option) => {
|
||||
if (option?.id === undefined) {
|
||||
return null;
|
||||
}
|
||||
return option;
|
||||
};
|
||||
}
|
||||
|
||||
function getResource(resource: string, field: Field) {
|
||||
if (resource !== field.componentProps.service.resource) {
|
||||
// 切换 collection 后,之前选中的其它 collection 的数据就没有意义了,需要清空
|
||||
field.value = undefined;
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
@ -0,0 +1,182 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { ISchema, observer, useField, useFieldSchema } from '@formily/react';
|
||||
import { error } from '@nocobase/utils/client';
|
||||
import { Select } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GeneralSchemaDesigner, SchemaSettings } from '../..';
|
||||
import { mergeFilter } from '../../../block-provider';
|
||||
import { useCollectionFilterOptions, useCollectionManager } from '../../../collection-manager';
|
||||
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
|
||||
import { removeNullCondition, useCompile, useDesignable } from '../../../schema-component';
|
||||
import { ITemplate } from '../../../schema-component/antd/form-v2/Templates';
|
||||
import { FilterDynamicComponent } from '../../../schema-component/antd/table-v2/FilterDynamicComponent';
|
||||
|
||||
export const Designer = observer(() => {
|
||||
const { getCollectionFields, getCollectionField, getCollection } = useCollectionManager();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const { formSchema, data } = fieldSchema['x-designer-props'] as {
|
||||
formSchema: ISchema;
|
||||
data?: ITemplate;
|
||||
};
|
||||
|
||||
// 在这里读取 resource 的值,当 resource 变化时,会触发该组件的更新
|
||||
const collectionName = field.componentProps.service.resource;
|
||||
|
||||
const collection = getCollection(collectionName);
|
||||
const collectionFields = getCollectionFields(collectionName);
|
||||
const dataSource = useCollectionFilterOptions(collectionName);
|
||||
|
||||
if (!data) {
|
||||
error('data is required');
|
||||
return null;
|
||||
}
|
||||
|
||||
const getFilter = () => data.config?.[collectionName]?.filter || {};
|
||||
const setFilter = (filter) => {
|
||||
try {
|
||||
_.set(data, `config.${collectionName}.filter`, removeNullCondition(filter));
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
};
|
||||
const getTitleFIeld = () => data.config?.[collectionName]?.titleField || collection?.titleField || 'id';
|
||||
const setTitleField = (titleField) => {
|
||||
try {
|
||||
_.set(data, `config.${collectionName}.titleField`, titleField);
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const options = collectionFields
|
||||
.filter((field) => isTitleField(field))
|
||||
.map((field) => ({
|
||||
value: field?.name,
|
||||
label: compile(field?.uiSchema?.title) || field?.name,
|
||||
}));
|
||||
|
||||
return (
|
||||
<GeneralSchemaDesigner draggable={false}>
|
||||
<SchemaSettings.ModalItem
|
||||
title={t('Set the data scope')}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
title: t('Set the data scope'),
|
||||
properties: {
|
||||
filter: {
|
||||
default: getFilter(),
|
||||
// title: '数据范围',
|
||||
enum: dataSource,
|
||||
'x-component': 'Filter',
|
||||
'x-component-props': {
|
||||
dynamicComponent: (props) => FilterDynamicComponent({ ...props }),
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
onSubmit={({ filter }) => {
|
||||
setFilter(filter);
|
||||
|
||||
try {
|
||||
// 不仅更新当前模板,也更新同级的其它模板
|
||||
field.query('fieldReaction.items.*.layout.dataId').forEach((item) => {
|
||||
if (item.componentProps.service.resource !== collectionName) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.componentProps.service.params = {
|
||||
filter: _.isEmpty(filter)
|
||||
? {}
|
||||
: removeNullCondition(mergeFilter([filter, getSelectedIdFilter(field.value)], '$or')),
|
||||
};
|
||||
});
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
formSchema['x-data-templates'] = data;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: formSchema['x-uid'],
|
||||
['x-data-templates']: data,
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
<SelectItem
|
||||
key="title-field"
|
||||
title={t('Title field')}
|
||||
options={options}
|
||||
value={getTitleFIeld()}
|
||||
onChange={(label) => {
|
||||
setTitleField(label);
|
||||
|
||||
try {
|
||||
// 不仅更新当前模板,也更新同级的其它模板
|
||||
field.query('fieldReaction.items.*.layout.dataId').forEach((item) => {
|
||||
if (item.componentProps.service.resource !== collectionName) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.componentProps.fieldNames.label = label;
|
||||
item.componentProps.targetField = getCollectionField(
|
||||
`${collectionName}.${label || collection?.titleField || 'id'}`,
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
formSchema['x-data-templates'] = data;
|
||||
|
||||
const schema = {
|
||||
['x-uid']: formSchema['x-uid'],
|
||||
['x-data-templates']: data,
|
||||
};
|
||||
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
</GeneralSchemaDesigner>
|
||||
);
|
||||
});
|
||||
|
||||
export function getSelectedIdFilter(selectedId) {
|
||||
return selectedId
|
||||
? {
|
||||
id: {
|
||||
$eq: selectedId,
|
||||
},
|
||||
}
|
||||
: null;
|
||||
}
|
||||
|
||||
function SelectItem(props) {
|
||||
const { title, options, value, onChange, ...others } = props;
|
||||
|
||||
return (
|
||||
<SchemaSettings.Item {...others}>
|
||||
<div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
|
||||
{title}
|
||||
<Select
|
||||
bordered={false}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
style={{ textAlign: 'right', minWidth: 100 }}
|
||||
{...others}
|
||||
/>
|
||||
</div>
|
||||
</SchemaSettings.Item>
|
||||
);
|
||||
}
|
@ -31,6 +31,7 @@ import {
|
||||
FormProvider,
|
||||
RemoteSchemaComponent,
|
||||
SchemaComponent,
|
||||
SchemaComponentContext,
|
||||
SchemaComponentOptions,
|
||||
createDesignable,
|
||||
findFormBlock,
|
||||
@ -1011,8 +1012,15 @@ SchemaSettings.LinkageRules = function LinkageRules(props) {
|
||||
);
|
||||
};
|
||||
|
||||
export const useDataTemplates = () => {
|
||||
export const useDataTemplates = (schema?: Schema) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
|
||||
if (schema) {
|
||||
return {
|
||||
templateData: _.cloneDeep(schema['x-data-templates']),
|
||||
};
|
||||
}
|
||||
|
||||
const formSchema = findFormBlock(fieldSchema) || fieldSchema;
|
||||
return {
|
||||
templateData: _.cloneDeep(formSchema?.['x-data-templates']),
|
||||
@ -1020,6 +1028,7 @@ export const useDataTemplates = () => {
|
||||
};
|
||||
|
||||
SchemaSettings.DataTemplates = function DataTemplates(props) {
|
||||
const designerCtx = useContext(SchemaComponentContext);
|
||||
const { collectionName } = props;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { dn } = useDesignable();
|
||||
@ -1035,6 +1044,8 @@ SchemaSettings.DataTemplates = function DataTemplates(props) {
|
||||
fieldReaction: {
|
||||
'x-component': FormDataTemplates,
|
||||
'x-component-props': {
|
||||
designerCtx,
|
||||
formSchema,
|
||||
useProps: () => {
|
||||
return {
|
||||
defaultValues: templateData,
|
||||
@ -1048,7 +1059,7 @@ SchemaSettings.DataTemplates = function DataTemplates(props) {
|
||||
[templateData],
|
||||
);
|
||||
const onSubmit = useCallback((v) => {
|
||||
const data = v.fieldReaction || {};
|
||||
const data = { ...(formSchema['x-data-templates'] || {}), ...v.fieldReaction };
|
||||
|
||||
// 当 Tree 组件开启 checkStrictly 属性时,会导致 checkedKeys 的值是一个对象,而不是数组,所以这里需要转换一下以支持旧版本
|
||||
data.items.forEach((item) => {
|
||||
|
@ -9,7 +9,9 @@ export function useIsShowMultipleSwitch() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { getCollectionField } = useCollectionManager();
|
||||
|
||||
const collectionField = getCollectionField(fieldSchema['x-collection-field']);
|
||||
const collectionField = fieldSchema['x-collection-field']
|
||||
? getCollectionField(fieldSchema['x-collection-field'])
|
||||
: null;
|
||||
const uiSchema = collectionField?.uiSchema || fieldSchema;
|
||||
const hasMultiple = uiSchema['x-component-props']?.multiple === true;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Input, PageHeader as AntdPageHeader, Spin } from 'antd';
|
||||
import { PageHeader as AntdPageHeader, Input, Spin } from 'antd';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
import { useAPIClient, useRequest, useSchemaTemplateManager } from '..';
|
||||
|
Loading…
Reference in New Issue
Block a user