feat(client): FormItem.Designer & TableColumn. Designer
This commit is contained in:
parent
2c38bf139f
commit
c9957dadab
@ -1,5 +1,6 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { connect, useField, useFieldSchema } from '@formily/react';
|
||||
import { merge } from '@formily/shared';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useCompile, useComponent } from '..';
|
||||
import { CollectionFieldProvider } from './CollectionFieldProvider';
|
||||
@ -33,7 +34,9 @@ const InternalField: React.FC = (props) => {
|
||||
setRequired();
|
||||
// @ts-ignore
|
||||
field.dataSource = uiSchema.enum;
|
||||
field.component = [component, uiSchema['x-component-props']];
|
||||
const originalProps = compile(uiSchema['x-component-props']);
|
||||
const componentProps = field.componentProps;
|
||||
field.component = [component, merge(originalProps, componentProps)];
|
||||
}, [uiSchema?.title, uiSchema?.description, uiSchema?.required]);
|
||||
if (!uiSchema) {
|
||||
return null;
|
||||
|
@ -30,7 +30,7 @@ export const useCancelFilterAction = () => {
|
||||
export const useCollectionFilterOptions = (collectionName: string) => {
|
||||
const { getCollectionFields, getInterface } = useCollectionManager();
|
||||
const fields = getCollectionFields(collectionName);
|
||||
const field2option = (field) => {
|
||||
const field2option = (field, nochildren) => {
|
||||
if (!field.interface) {
|
||||
return;
|
||||
}
|
||||
@ -45,21 +45,24 @@ export const useCollectionFilterOptions = (collectionName: string) => {
|
||||
schema: field?.uiSchema,
|
||||
operators: operators || [],
|
||||
};
|
||||
if (nochildren) {
|
||||
return option;
|
||||
}
|
||||
if (children?.length) {
|
||||
option['children'] = children;
|
||||
}
|
||||
if (nested) {
|
||||
const targetFields = getCollectionFields(field.target);
|
||||
const options = getOptions(targetFields);
|
||||
const options = getOptions(targetFields, true);
|
||||
option['children'] = option['children'] || [];
|
||||
option['children'].push(...options);
|
||||
}
|
||||
return option;
|
||||
};
|
||||
const getOptions = (fields) => {
|
||||
const getOptions = (fields, nochildren = false) => {
|
||||
const options = [];
|
||||
fields.forEach((field) => {
|
||||
const option = field2option(field);
|
||||
const option = field2option(field, nochildren);
|
||||
if (option) {
|
||||
options.push(option);
|
||||
}
|
||||
|
@ -32,4 +32,6 @@ export interface CollectionFieldOptions {
|
||||
collectionName?: string;
|
||||
sourceKey?: string; // association field
|
||||
uiSchema?: ISchema;
|
||||
target?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ export const Filter: any = observer((props: any) => {
|
||||
<FilterContext.Provider value={{ field, fieldSchema, dynamicComponent, options: field.dataSource || [] }}>
|
||||
<FilterGroup {...props} />
|
||||
</FilterContext.Provider>
|
||||
<pre>{JSON.stringify(field.value, null, 2)}</pre>
|
||||
{/* <pre>{JSON.stringify(field.value, null, 2)}</pre> */}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { FormItem as Item } from '@formily/antd';
|
||||
import { Field } from '@formily/core';
|
||||
import { ISchema, useField, useFieldSchema, useForm } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useActionContext } from '..';
|
||||
import { useCompile, useDesignable } from '../..';
|
||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||
import { BlockItem } from '../block-item';
|
||||
|
||||
@ -12,8 +17,144 @@ export const FormItem: any = (props) => {
|
||||
};
|
||||
|
||||
FormItem.Designer = () => {
|
||||
const { getCollectionFields } = useCollectionManager();
|
||||
const { getField } = useCollection();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { dn, reset, refresh } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionField = getField(fieldSchema['name']);
|
||||
const originalTitle = collectionField?.uiSchema?.title;
|
||||
const targetFields = collectionField.target ? getCollectionFields(collectionField.target) : [];
|
||||
const initialValue = {
|
||||
title: field.title === originalTitle ? undefined : field.title,
|
||||
};
|
||||
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,
|
||||
}));
|
||||
return (
|
||||
<GeneralSchemaDesigner>
|
||||
<SchemaSettings.PopupItem
|
||||
title={'编辑'}
|
||||
schema={
|
||||
{
|
||||
title: '编辑字段',
|
||||
'x-component': 'Action.Modal',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
initialValue,
|
||||
},
|
||||
type: 'void',
|
||||
properties: {
|
||||
title: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
title: '字段标题',
|
||||
'x-component-props': {},
|
||||
description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
||||
},
|
||||
required: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
'x-content': '必填',
|
||||
'x-hidden': field.readPretty,
|
||||
},
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Modal.Footer',
|
||||
properties: {
|
||||
cancel: {
|
||||
type: 'void',
|
||||
title: '{{t("Cancel")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction() {
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
ctx.setVisible(false);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
type: 'void',
|
||||
title: 'Submit',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction() {
|
||||
const form = useForm();
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
const { title, required, label } = form.values;
|
||||
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
|
||||
if (title) {
|
||||
field.title = title;
|
||||
fieldSchema['title'] = title;
|
||||
schema['title'] = title;
|
||||
}
|
||||
|
||||
field.required = required;
|
||||
fieldSchema['required'] = required;
|
||||
schema['required'] = required;
|
||||
|
||||
ctx.setVisible(false);
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
// dn.refresh();
|
||||
reset();
|
||||
refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
/>
|
||||
{collectionField?.target && (
|
||||
<SchemaSettings.SelectItem
|
||||
title={'标题字段'}
|
||||
options={options}
|
||||
value={field?.componentProps?.fieldNames?.label}
|
||||
onChange={(label) => {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
const fieldNames = {
|
||||
...field.componentProps.fieldNames,
|
||||
label,
|
||||
};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
field.componentProps.fieldNames = fieldNames;
|
||||
schema['x-component-props'] = {
|
||||
fieldNames,
|
||||
};
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<SchemaSettings.Divider />
|
||||
<SchemaSettings.Remove
|
||||
removeParentsIfNoChildren
|
||||
breakRemoveOn={{
|
||||
|
@ -16,7 +16,6 @@ import { toArr } from '@formily/shared';
|
||||
import { Button, Drawer, Select, Space } from 'antd';
|
||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCollectionField } from '../../../collection-manager';
|
||||
import { RecordProvider } from '../../../record-provider';
|
||||
import { useAttach } from '../../hooks/useAttach';
|
||||
import { ActionContext, useActionContext } from '../action';
|
||||
@ -85,7 +84,7 @@ const InputRecordPicker: React.FC<any> = (props) => {
|
||||
<Select
|
||||
size={props.size}
|
||||
mode={multiple ? 'multiple' : props.mode}
|
||||
fieldNames={fieldNames}
|
||||
// fieldNames={fieldNames}
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
@ -193,7 +192,6 @@ RecordPicker.SelectedItem = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const fieldNames = ctx.field.componentProps.fieldNames;
|
||||
const { target } = useCollectionField();
|
||||
return (
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<a style={{ cursor: 'pointer' }} onClick={() => setVisible(true)}>
|
||||
|
@ -17,13 +17,13 @@ export const useColumnSchema = () => {
|
||||
return {};
|
||||
}
|
||||
const collectionField = getField(fieldSchema.name);
|
||||
return { columnSchema, fieldSchema, uiSchema: compile(collectionField?.uiSchema) };
|
||||
return { columnSchema, fieldSchema, collectionField, uiSchema: compile(collectionField?.uiSchema) };
|
||||
};
|
||||
|
||||
export const TableColumnDecorator = (props) => {
|
||||
const Designer = useDesigner();
|
||||
const field = useField();
|
||||
const { fieldSchema, uiSchema } = useColumnSchema();
|
||||
const { fieldSchema, uiSchema, collectionField } = useColumnSchema();
|
||||
const { refresh } = useDesignable();
|
||||
const compile = useCompile();
|
||||
useLayoutEffect(() => {
|
||||
@ -37,10 +37,9 @@ export const TableColumnDecorator = (props) => {
|
||||
field.title = uiSchema?.title;
|
||||
}
|
||||
}, [uiSchema?.title]);
|
||||
console.log('field.title', uiSchema?.title, field.title);
|
||||
return (
|
||||
<SortableItem className={designerCss}>
|
||||
<Designer />
|
||||
<Designer fieldSchema={fieldSchema} uiSchema={uiSchema} collectionField={collectionField}/>
|
||||
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
||||
{field.title || compile(uiSchema?.title)}
|
||||
{/* <div
|
||||
|
@ -1,28 +1,137 @@
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { ISchema, useField, useFieldSchema, useForm } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useCollectionManager } from '../../../collection-manager';
|
||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||
import { useDesignable } from '../../hooks';
|
||||
import { useCompile, useDesignable } from '../../hooks';
|
||||
import { useActionContext } from '../action';
|
||||
|
||||
export const TableColumnDeigner = () => {
|
||||
const useLabelFields = (collectionName?: any) => {
|
||||
if (!collectionName) {
|
||||
return [];
|
||||
}
|
||||
const compile = useCompile();
|
||||
const { getCollectionFields } = useCollectionManager();
|
||||
const targetFields = getCollectionFields(collectionName);
|
||||
return targetFields
|
||||
?.filter((field) => !field?.target && field.type !== 'boolean')
|
||||
?.map((field) => {
|
||||
return {
|
||||
value: field.name,
|
||||
label: compile(field?.uiSchema?.title || field.name),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const TableColumnDeigner = (props) => {
|
||||
const { uiSchema, fieldSchema, collectionField } = props;
|
||||
const field = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const columnSchema = useFieldSchema();
|
||||
const { dn } = useDesignable();
|
||||
const initialValue = {
|
||||
title: columnSchema?.title,
|
||||
};
|
||||
const options = useLabelFields(collectionField.target);
|
||||
return (
|
||||
<GeneralSchemaDesigner>
|
||||
<SchemaSettings.Item
|
||||
<SchemaSettings.PopupItem
|
||||
title={'编辑'}
|
||||
onClick={() => {
|
||||
field.title = uid();
|
||||
fieldSchema.title = uid();
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
title: fieldSchema.title,
|
||||
schema={
|
||||
{
|
||||
title: '编辑字段',
|
||||
'x-component': 'Action.Modal',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
initialValue,
|
||||
},
|
||||
});
|
||||
}}
|
||||
type: 'void',
|
||||
properties: {
|
||||
title: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
title: '字段标题',
|
||||
'x-component-props': {},
|
||||
description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
||||
},
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Modal.Footer',
|
||||
properties: {
|
||||
cancel: {
|
||||
type: 'void',
|
||||
title: '{{t("Cancel")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction() {
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
ctx.setVisible(false);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
type: 'void',
|
||||
title: 'Submit',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction() {
|
||||
const form = useForm();
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
const { title } = form.values;
|
||||
if (title) {
|
||||
field.title = title;
|
||||
columnSchema.title = title;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': columnSchema['x-uid'],
|
||||
title: columnSchema.title,
|
||||
},
|
||||
});
|
||||
}
|
||||
ctx.setVisible(false);
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
/>
|
||||
{collectionField?.target && (
|
||||
<SchemaSettings.SelectItem
|
||||
title={'标题字段'}
|
||||
options={options}
|
||||
value={fieldSchema?.['x-component-props']?.['fieldNames']?.['label']}
|
||||
onChange={(label) => {
|
||||
const fieldNames = {
|
||||
...fieldSchema['x-component-props']['fieldNames'],
|
||||
label,
|
||||
};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
field.query(`.*.${fieldSchema.name}`).take((f) => {
|
||||
f.componentProps.fieldNames = fieldNames;
|
||||
});
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
'x-component-props': {
|
||||
fieldNames,
|
||||
},
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<SchemaSettings.Divider />
|
||||
<SchemaSettings.Remove
|
||||
removeParentsIfNoChildren
|
||||
|
@ -17,6 +17,7 @@ export const AddNewActionInitializer = (props) => {
|
||||
type: 'void',
|
||||
title: '{{ t("Add new") }}',
|
||||
'x-action': 'create',
|
||||
'x-designer': 'Action.Designer',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GeneralField } from '@formily/core';
|
||||
import { ISchema, Schema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Dropdown, Menu, MenuItemProps, Modal } from 'antd';
|
||||
import { Dropdown, Menu, MenuItemProps, Modal, Select } from 'antd';
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ActionContext, Designable, SchemaComponent } from '..';
|
||||
@ -17,6 +17,8 @@ interface SchemaSettingsContextProps {
|
||||
dn?: Designable;
|
||||
field?: GeneralField;
|
||||
fieldSchema?: Schema;
|
||||
setVisible?: any;
|
||||
visible?: any;
|
||||
}
|
||||
|
||||
const SchemaSettingsContext = createContext<SchemaSettingsContextProps>(null);
|
||||
@ -42,23 +44,36 @@ interface SchemaSettingsProviderProps {
|
||||
dn?: Designable;
|
||||
field?: GeneralField;
|
||||
fieldSchema?: Schema;
|
||||
setVisible?: any;
|
||||
visible?: any;
|
||||
}
|
||||
|
||||
export const SchemaSettingsProvider: React.FC<SchemaSettingsProviderProps> = (props) => {
|
||||
const { dn, field, fieldSchema, children } = props;
|
||||
return <SchemaSettingsContext.Provider value={{ dn, field, fieldSchema }}>{children}</SchemaSettingsContext.Provider>;
|
||||
const { visible, setVisible, dn, field, fieldSchema, children } = props;
|
||||
return (
|
||||
<SchemaSettingsContext.Provider value={{ visible, setVisible, dn, field, fieldSchema }}>
|
||||
{children}
|
||||
</SchemaSettingsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const SchemaSettings: React.FC<SchemaSettingsProps> & SchemaSettingsNested = (props) => {
|
||||
const { title, dn, field, fieldSchema } = props;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const DropdownMenu = (
|
||||
<Dropdown overlay={<Menu>{props.children}</Menu>}>
|
||||
<Dropdown
|
||||
visible={visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setVisible(visible);
|
||||
}}
|
||||
overlay={<Menu>{props.children}</Menu>}
|
||||
>
|
||||
{typeof title === 'string' ? <span>{title}</span> : title}
|
||||
</Dropdown>
|
||||
);
|
||||
if (dn) {
|
||||
return (
|
||||
<SchemaSettingsProvider dn={dn} field={field} fieldSchema={fieldSchema}>
|
||||
<SchemaSettingsProvider visible={visible} setVisible={setVisible} dn={dn} field={field} fieldSchema={fieldSchema}>
|
||||
{DropdownMenu}
|
||||
</SchemaSettingsProvider>
|
||||
);
|
||||
@ -121,21 +136,29 @@ SchemaSettings.Remove = (props: any) => {
|
||||
};
|
||||
|
||||
SchemaSettings.SelectItem = (props) => {
|
||||
return null;
|
||||
const { title, options, value, onChange, ...others } = props;
|
||||
return (
|
||||
<SchemaSettings.Item {...others}>
|
||||
{title}
|
||||
<Select bordered={false} defaultValue={value} onChange={onChange} options={options} style={{ minWidth: 100 }} />
|
||||
</SchemaSettings.Item>
|
||||
);
|
||||
};
|
||||
|
||||
SchemaSettings.SwitchItem = (props) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
SchemaSettings.Popup = (props) => {
|
||||
SchemaSettings.PopupItem = (props) => {
|
||||
const { schema, ...others } = props;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const ctx = useContext(SchemaSettingsContext);
|
||||
return (
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<SchemaSettings.Item
|
||||
{...others}
|
||||
onClick={() => {
|
||||
ctx.setVisible(false);
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
@ -150,12 +173,3 @@ SchemaSettings.Popup = (props) => {
|
||||
</ActionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
SchemaSettings.DrawerItem = (props) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<SchemaSettings.Item {...props}>{props.children || props.title}</SchemaSettings.Item>
|
||||
</ActionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user