field switch

This commit is contained in:
chenos 2021-07-27 18:38:54 +08:00
parent a9177116aa
commit 428beabd5a
5 changed files with 143 additions and 61 deletions

View File

@ -51,6 +51,7 @@ import {
createCollectionField, createCollectionField,
createOrUpdateCollection, createOrUpdateCollection,
createSchema, createSchema,
removeSchema,
request, request,
useCollectionContext, useCollectionContext,
useDesignable, useDesignable,
@ -58,7 +59,7 @@ import {
} from '../'; } from '../';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { SchemaField } from '../../components/schema-renderer'; import { getSchemaPath, SchemaField } from '../../components/schema-renderer';
import { useResourceContext } from '../'; import { useResourceContext } from '../';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { options } from '../database-field/interfaces'; import { options } from '../database-field/interfaces';
@ -67,6 +68,7 @@ import { useDisplayFieldsContext } from '../form';
import './style.less'; import './style.less';
import IconPicker from '../../components/icon-picker'; import IconPicker from '../../components/icon-picker';
import { barChartConfig, columnChartConfig } from './chart'; import { barChartConfig, columnChartConfig } from './chart';
import { isGridRowOrCol } from '../grid';
const generateGridBlock = (schema: ISchema) => { const generateGridBlock = (schema: ISchema) => {
const name = schema.name || uid(); const name = schema.name || uid();
@ -659,9 +661,12 @@ AddNew.BlockItem = observer((props: any) => {
); );
}); });
function FieldSwitch({ field, onChange, defaultChecked }) { function SwitchField(props) {
const [checked, setChecked] = useState(defaultChecked); const { field, onChange } = props;
const form = useForm(); const [checked, setChecked] = useState(props.checked);
useEffect(() => {
setChecked(props.checked);
}, [props.checked]);
return ( return (
<div <div
style={{ style={{
@ -669,35 +674,32 @@ function FieldSwitch({ field, onChange, defaultChecked }) {
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
}} }}
onClick={(e) => { onClick={async () => {
setChecked((value) => { setChecked((checked) => {
onChange && onChange(!value); onChange(!checked);
return !value; return !checked;
}); });
console.log('FieldSwitch', form);
}} }}
> >
<span>{field?.uiSchema?.title || '未命名'}</span> <span>{field.uiSchema.title}</span>
<Switch <Switch checked={checked} size={'small'} />
onChange={(checked, e) => {
e.stopPropagation();
setChecked(checked);
onChange && onChange(checked);
}}
size={'small'}
checked={checked}
/>
</div> </div>
); );
} }
AddNew.FormItem = observer((props: any) => { AddNew.FormItem = observer((props: any) => {
const { ghost, defaultAction } = props; const { ghost, defaultAction } = props;
const { schema, insertBefore, insertAfter, appendChild } = useDesignable(); const { schema, insertBefore, insertAfter, appendChild, deepRemove } =
useDesignable();
const path = useSchemaPath(); const path = useSchemaPath();
const { resource = {}, refresh } = useResourceContext(); const { resource = {}, refresh } = useResourceContext();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { displayFields = [] } = useDisplayFieldsContext(); const {
displayFields,
hasDisplayField,
getDisplayField,
removeDisplayField,
} = useDisplayFieldsContext();
console.log({ displayFields }); console.log({ displayFields });
return ( return (
<Dropdown <Dropdown
@ -713,11 +715,23 @@ AddNew.FormItem = observer((props: any) => {
<Menu.ItemGroup className={'display-fields'} title={`要展示的字段`}> <Menu.ItemGroup className={'display-fields'} title={`要展示的字段`}>
{resource?.fields?.map((field) => ( {resource?.fields?.map((field) => (
<Menu.Item key={field.key}> <Menu.Item key={field.key}>
<FieldSwitch <SwitchField
field={field} field={field}
defaultChecked={displayFields.includes(field.name)} checked={hasDisplayField(field.name)}
onChange={async (checked) => { onChange={async (checked) => {
if (!checked) { if (!checked) {
const s: any = getDisplayField(field.name);
const p = getSchemaPath(s);
const removed = deepRemove(p);
if (!removed) {
console.log('getSchemaPath', p, removed);
return;
}
const last = removed.pop();
removeDisplayField(field.name);
if (isGridRowOrCol(last)) {
await removeSchema(last);
}
return; return;
} }
let data: ISchema = { let data: ISchema = {
@ -869,7 +883,7 @@ AddNew.PaneItem = observer((props: any) => {
const path = useSchemaPath(); const path = useSchemaPath();
const { resource = {}, refresh } = useResourceContext(); const { resource = {}, refresh } = useResourceContext();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { displayFields = [] } = useDisplayFieldsContext(); const { displayFields } = useDisplayFieldsContext();
console.log({ displayFields }); console.log({ displayFields });
return ( return (
<Dropdown <Dropdown
@ -978,8 +992,15 @@ AddNew.PaneItem = observer((props: any) => {
</Menu.Item> </Menu.Item>
</Menu.ItemGroup> </Menu.ItemGroup>
<Menu.ItemGroup title={'相关数据区块'}> <Menu.ItemGroup title={'相关数据区块'}>
<Menu.Item style={{ minWidth: 150 }} icon={<IconPicker type={'HistoryOutlined'} />}></Menu.Item> <Menu.Item
<Menu.Item icon={<IconPicker type={'CommentOutlined'} />}></Menu.Item> style={{ minWidth: 150 }}
icon={<IconPicker type={'HistoryOutlined'} />}
>
</Menu.Item>
<Menu.Item icon={<IconPicker type={'CommentOutlined'} />}>
</Menu.Item>
</Menu.ItemGroup> </Menu.ItemGroup>
<Menu.ItemGroup title={'多媒体区块'}> <Menu.ItemGroup title={'多媒体区块'}>
<Menu.Item <Menu.Item

View File

@ -8,3 +8,4 @@ group:
title: Schemas title: Schemas
path: /client/schemas path: /client/schemas
--- ---

View File

@ -33,7 +33,7 @@ import constate from 'constate';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer'; import { getSchemaPath } from '../../components/schema-renderer';
import { FormFieldUIDContext } from '.'; import { FormFieldUIDContext, useDisplayFieldsContext } from '.';
export const FieldDesignableBar = observer((props) => { export const FieldDesignableBar = observer((props) => {
const field = useField(); const field = useField();
@ -42,6 +42,7 @@ export const FieldDesignableBar = observer((props) => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { dragRef } = useContext(DraggableBlockContext); const { dragRef } = useContext(DraggableBlockContext);
const fieldUid = useContext(FormFieldUIDContext); const fieldUid = useContext(FormFieldUIDContext);
const { removeDisplayField } = useDisplayFieldsContext();
const fieldName = schema['x-component-props']?.['fieldName']; const fieldName = schema['x-component-props']?.['fieldName'];
if (!designable) { if (!designable) {
return null; return null;
@ -93,8 +94,11 @@ export const FieldDesignableBar = observer((props) => {
key={'delete'} key={'delete'}
onClick={async () => { onClick={async () => {
const removed = deepRemove(); const removed = deepRemove();
console.log({ schema, removed }); const fieldName =
schema['x-component-props']?.['fieldName'];
console.log({ schema, removed, fieldName });
const last = removed.pop(); const last = removed.pop();
removeDisplayField(fieldName);
if (isGridRowOrCol(last)) { if (isGridRowOrCol(last)) {
await removeSchema(last); await removeSchema(last);
} }

View File

@ -39,15 +39,24 @@ import { FieldDesignableBar } from './Field.DesignableBar';
import { createContext } from 'react'; import { createContext } from 'react';
import { BlockItem } from '../block-item'; import { BlockItem } from '../block-item';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useMap } from 'ahooks';
const [DisplayFieldsContextProvider, useDisplayFieldsContext] = constate(() => { const [DisplayFieldsContextProvider, useDisplayFieldsContext] = constate(() => {
const [displayFields, setDisplayFields] = useState([]); const [displayFields, { set, remove, get }] = useMap([]);
return { return {
displayFields, displayFields,
setDisplayFields, hasDisplayField(fieldName) {
addDisplayField(fieldName) { return !!get(fieldName);
setDisplayFields((fields) => fields.concat(fieldName)); },
addDisplayField(fieldName, schema) {
set(fieldName, schema);
},
getDisplayField(fieldName) {
return get(fieldName);
},
removeDisplayField(fieldName) {
remove(fieldName);
}, },
}; };
}); });
@ -65,7 +74,10 @@ export const Form: any = observer((props: any) => {
const initialValues = useValues(); const initialValues = useValues();
const form = useMemo(() => { const form = useMemo(() => {
console.log('Form.useMemo', initialValues); console.log('Form.useMemo', initialValues);
return createForm({ initialValues, readPretty: schema['x-read-pretty'] }); return createForm({
initialValues,
readPretty: schema['x-read-pretty'],
});
}, []); }, []);
const path = useSchemaPath(); const path = useSchemaPath();
const scope = useContext(SchemaExpressionScopeContext); const scope = useContext(SchemaExpressionScopeContext);
@ -128,7 +140,7 @@ export const Form: any = observer((props: any) => {
<DisplayFieldsContextProvider>{content}</DisplayFieldsContextProvider> <DisplayFieldsContextProvider>{content}</DisplayFieldsContextProvider>
</ResourceContextProvider> </ResourceContextProvider>
) : ( ) : (
content <DisplayFieldsContextProvider>{content}</DisplayFieldsContextProvider>
); );
}); });
@ -143,9 +155,9 @@ Form.Field = observer((props: any) => {
const { resource = {} } = useResourceContext(); const { resource = {} } = useResourceContext();
useEffect(() => { useEffect(() => {
if (fieldName) { if (fieldName) {
addDisplayField && addDisplayField(fieldName); addDisplayField && addDisplayField(fieldName, schema);
} }
}, [fieldName]); }, [fieldName, schema]);
if (!fieldName) { if (!fieldName) {
return null; return null;
} }

View File

@ -62,7 +62,7 @@ import AddNew from '../add-new';
import { isGridRowOrCol } from '../grid'; import { isGridRowOrCol } from '../grid';
import { options } from '../database-field/interfaces'; import { options } from '../database-field/interfaces';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useDisplayFieldsContext } from '../form'; import { DisplayFieldsContextProvider, useDisplayFieldsContext } from '../form';
interface TableRowProps { interface TableRowProps {
index: number; index: number;
@ -223,10 +223,39 @@ function useTableColumns(props?: any) {
return columns; return columns;
} }
function SwitchField(props) {
const { field, onChange } = props;
const [checked, setChecked] = useState(props.checked);
useEffect(() => {
setChecked(props.checked);
}, [props.checked]);
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
onClick={async () => {
setChecked((checked) => {
onChange(!checked);
return !checked;
});
}}
>
<span>{field.uiSchema.title}</span>
<Switch checked={checked} size={'small'} />
</div>
);
}
function AddColumn() { function AddColumn() {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { appendChild } = useDesignable(); const { appendChild, remove } = useDesignable();
const { resource = {}, refresh } = useResourceContext(); const { resource = {}, refresh } = useResourceContext();
const { hasDisplayField, removeDisplayField, getDisplayField } =
useDisplayFieldsContext();
return ( return (
<Dropdown <Dropdown
trigger={['click']} trigger={['click']}
@ -237,13 +266,11 @@ function AddColumn() {
<Menu.ItemGroup className={'display-fields'} title={'要展示的字段'}> <Menu.ItemGroup className={'display-fields'} title={'要展示的字段'}>
{resource?.fields?.map((field) => ( {resource?.fields?.map((field) => (
<Menu.Item style={{ minWidth: 150 }}> <Menu.Item style={{ minWidth: 150 }}>
<div <SwitchField
style={{ checked={hasDisplayField(field.name)}
display: 'flex', field={field}
alignItems: 'center', onChange={async (checked) => {
justifyContent: 'space-between', if (checked) {
}}
onClick={async () => {
const data = appendChild({ const data = appendChild({
type: 'void', type: 'void',
'x-component': 'Table.Column', 'x-component': 'Table.Column',
@ -253,11 +280,15 @@ function AddColumn() {
'x-designable-bar': 'Table.Column.DesignableBar', 'x-designable-bar': 'Table.Column.DesignableBar',
}); });
await createSchema(data); await createSchema(data);
} else {
const s: any = getDisplayField(field.name);
const p = getSchemaPath(s);
const removed = remove(p);
await removeSchema(removed);
removeDisplayField(field.name);
}
}} }}
> />
<span>{field.uiSchema.title}</span>
<Switch size={'small'} />
</div>
</Menu.Item> </Menu.Item>
))} ))}
</Menu.ItemGroup> </Menu.ItemGroup>
@ -611,12 +642,16 @@ export const Table: any = observer((props: any) => {
// @ts-ignore // @ts-ignore
<ResourceContextProvider resourceName={resourceName}> <ResourceContextProvider resourceName={resourceName}>
<TableContextProvider> <TableContextProvider>
<DisplayFieldsContextProvider>
<TableContainer /> <TableContainer />
</DisplayFieldsContextProvider>
</TableContextProvider> </TableContextProvider>
</ResourceContextProvider> </ResourceContextProvider>
) : ( ) : (
<TableContextProvider> <TableContextProvider>
<DisplayFieldsContextProvider>
<TableContainer /> <TableContainer />
</DisplayFieldsContextProvider>
</TableContextProvider> </TableContextProvider>
); );
}); });
@ -710,8 +745,14 @@ Table.Cell = observer((props: any) => {
}); });
Table.Column = observer((props: any) => { Table.Column = observer((props: any) => {
const resourceField = useContext(ResourceFieldContext) || {}; const resourceField = useContext(ResourceFieldContext);
const { schema, DesignableBar } = useDesignable(); const { schema, DesignableBar } = useDesignable();
const { addDisplayField } = useDisplayFieldsContext();
useEffect(() => {
if (resourceField?.name) {
addDisplayField(resourceField.name, schema);
}
}, [resourceField, schema]);
return ( return (
<div className={'nb-table-column'}> <div className={'nb-table-column'}>
{schema.title || resourceField?.uiSchema?.title} {schema.title || resourceField?.uiSchema?.title}
@ -725,6 +766,7 @@ Table.Column.DesignableBar = () => {
// const fieldSchema = useFieldSchema(); // const fieldSchema = useFieldSchema();
const { schema, remove, refresh, insertAfter } = useDesignable(); const { schema, remove, refresh, insertAfter } = useDesignable();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { removeDisplayField } = useDisplayFieldsContext();
return ( return (
<div className={cls('designable-bar', { active: visible })}> <div className={cls('designable-bar', { active: visible })}>
<span <span
@ -759,6 +801,8 @@ Table.Column.DesignableBar = () => {
<Menu.Item <Menu.Item
onClick={async () => { onClick={async () => {
const s = remove(); const s = remove();
const fieldName = schema['x-component-props']?.['fieldName'];
removeDisplayField(fieldName);
await removeSchema(s); await removeSchema(s);
}} }}
> >