feat: improve code

This commit is contained in:
chenos 2021-08-30 18:27:39 +08:00
parent 10861d3c1c
commit 3c8c2d71e3
7 changed files with 242 additions and 41 deletions

View File

@ -3,8 +3,10 @@ import React from 'react';
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd';
import { action } from '@formily/reactive'; import { action } from '@formily/reactive';
import { useCollectionsContext } from '../../constate/Collections'; import { useCollectionsContext } from '../../constate/Collections';
import { Field } from '@formily/core';
export const useAsyncDataSource = (service: any) => (field: any) => { export const useAsyncDataSource = (service: any) => (field: any) => {
console.log('loadCollectionFields');
field.loading = true; field.loading = true;
service(field).then( service(field).then(
action.bound((data: any) => { action.bound((data: any) => {
@ -24,6 +26,22 @@ export default () => {
})); }));
}; };
const loadCollectionFields = async (field: Field) => {
const target = field.query('....target').get('value');
const f = field.query('....target').take();
console.log('loadCollectionFields', f, field);
const collection = collections?.find((item) => item.name === target);
if (!collection) {
return [];
}
return collection?.generalFields
?.filter((item) => item?.uiSchema?.title)
?.map((item) => ({
label: item?.uiSchema?.title || item.name,
value: item.name,
}));
};
const schema = { const schema = {
type: 'array', type: 'array',
name: 'collections', name: 'collections',
@ -56,7 +74,7 @@ export default () => {
}; };
return ( return (
<SchemaRenderer <SchemaRenderer
scope={{ loadCollections, useAsyncDataSource }} scope={{ loadCollections, loadCollectionFields, useAsyncDataSource }}
components={{ FormItem }} components={{ FormItem }}
schema={schema} schema={schema}
/> />

View File

@ -6,9 +6,14 @@ const [CollectionsProvider, useCollectionsContext] = constate(() => {
formatResult: (result) => result?.data, formatResult: (result) => result?.data,
}); });
return { return {
...result, collections: result.data || [], findCollection(name) { ...result, collections: result.data || [],
findCollection(name) {
return result?.data?.find((item) => item.name === name); return result?.data?.find((item) => item.name === name);
} },
getFieldsByCollection(collectionName) {
const collection = result?.data?.find((item) => item.name === collectionName);
return collection?.generalFields;
},
}; };
}); });

View File

@ -1437,12 +1437,13 @@ AddNew.FormItem = observer((props: any) => {
default: [], default: [],
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
defaultSelectedRowKeys: useSelectedRowKeys:
'{{ Select.useSelectedRowKeys() }}', '{{ Select.useSelectedRowKeys }}',
onSelect: '{{ Select.useSelect() }}', onSelect: '{{ Select.useSelect() }}',
useRowSelection: '{{ Select.useRowSelection }}',
collectionName: field.target, collectionName: field.target,
// dragSort: true, // dragSort: true,
showIndex: true, // showIndex: true,
refreshRequestOnChange: true, refreshRequestOnChange: true,
pagination: { pagination: {
pageSize: 10, pageSize: 10,

View File

@ -20,7 +20,7 @@ import {
updateSchema, updateSchema,
} from '../'; } from '../';
import get from 'lodash/get'; import get from 'lodash/get';
import { Button, Dropdown, Menu, Modal, Space, Switch } from 'antd'; import { Button, Dropdown, Menu, Modal, Select, Space, Switch } from 'antd';
import { MenuOutlined, DragOutlined } from '@ant-design/icons'; import { MenuOutlined, DragOutlined } from '@ant-design/icons';
import cls from 'classnames'; import cls from 'classnames';
import { FormDialog, FormLayout } from '@formily/antd'; import { FormDialog, FormLayout } from '@formily/antd';
@ -33,19 +33,25 @@ 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 { RandomNameContext } from '.'; import { RandomNameContext } from '.';
import { useCollectionContext, useDisplayedMapContext } from '../../constate'; import {
useCollectionContext,
useCollectionsContext,
useDisplayedMapContext,
} from '../../constate';
import SwitchMenuItem from '../../components/SwitchMenuItem'; import SwitchMenuItem from '../../components/SwitchMenuItem';
import { DragHandle } from '../../components/Sortable'; import { DragHandle } from '../../components/Sortable';
import { set } from 'lodash';
export const FieldDesignableBar = observer((props) => { export const FieldDesignableBar = observer((props) => {
const field = useField(); const field = useField();
const { schema, deepRemove } = useDesignable(); const { schema, deepRemove, refresh } = useDesignable();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { dragRef } = useContext(DraggableBlockContext); const { dragRef } = useContext(DraggableBlockContext);
const randomName = useContext(RandomNameContext); const randomName = useContext(RandomNameContext);
const displayed = useDisplayedMapContext(); const displayed = useDisplayedMapContext();
const fieldName = schema['x-component-props']?.['fieldName']; const fieldName = schema['x-component-props']?.['fieldName'];
const { getField } = useCollectionContext(); const { getField } = useCollectionContext();
const { getFieldsByCollection } = useCollectionsContext();
const collectionField = getField(fieldName); const collectionField = getField(fieldName);
@ -124,6 +130,59 @@ export const FieldDesignableBar = observer((props) => {
> >
</Menu.Item> </Menu.Item>
{collectionField.interface === 'linkTo' && (
<Menu.Item>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
{' '}
<Select
value={
schema?.['x-component-props']?.['fieldNames']?.[
'label'
]
}
placeholder={'默认为 ID 字段'}
onChange={async (value) => {
set(
schema['x-component-props'],
'fieldNames.label',
value,
);
refresh();
const fieldNames = {
label: value,
value:
get(
schema['x-component-props'],
'fieldNames.value',
) || 'id',
};
// realField.componentProps.fieldNames = fieldNames;
await updateSchema({
key: schema['key'],
'x-component-props': {
fieldNames,
},
});
// await service.refresh();
}}
bordered={false}
size={'small'}
style={{ marginLeft: 16, minWidth: 120 }}
options={getFieldsByCollection(collectionField.target)
.filter((f) => f?.uiSchema?.title)
.map((field) => ({
label: field?.uiSchema?.title || field.name,
value: field.name,
}))}
/>
</div>
</Menu.Item>
)}
<Menu.Item <Menu.Item
style={{ minWidth: 150 }} style={{ minWidth: 150 }}
onClick={async () => { onClick={async () => {

View File

@ -29,7 +29,7 @@ import { DraggableBlockContext } from '../../components/drag-and-drop';
import { isGridRowOrCol } from '../grid'; import { isGridRowOrCol } from '../grid';
import constate from 'constate'; import constate from 'constate';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { uid } from '@formily/shared'; import { uid, merge } from '@formily/shared';
import { getSchemaPath } from '../../components/schema-renderer'; import { getSchemaPath } from '../../components/schema-renderer';
import { DesignableBar } from './DesignableBar'; import { DesignableBar } from './DesignableBar';
import { FieldDesignableBar } from './Field.DesignableBar'; import { FieldDesignableBar } from './Field.DesignableBar';
@ -183,7 +183,15 @@ Form.Field = observer((props: any) => {
const required = schema['required'] || collectionField?.uiSchema?.required; const required = schema['required'] || collectionField?.uiSchema?.required;
const description = const description =
schema['description'] || collectionField?.uiSchema?.description; schema['description'] || collectionField?.uiSchema?.description;
console.log('schema.properties', schema.properties) console.log('schema.properties', schema.properties);
const componentProps = merge(
collectionField?.uiSchema?.['x-component-props'] || {},
schema?.['x-component-props'] || {},
{
arrayMerge: (t, s) => s,
},
);
return ( return (
<CollectionFieldContext.Provider value={collectionField}> <CollectionFieldContext.Provider value={collectionField}>
<RecursionField <RecursionField
@ -199,6 +207,7 @@ Form.Field = observer((props: any) => {
required, required,
description, description,
'x-decorator': 'FormilyFormItem', 'x-decorator': 'FormilyFormItem',
'x-component-props': componentProps,
properties: { properties: {
...schema.properties, ...schema.properties,
}, },

View File

@ -18,7 +18,7 @@ import { useState } from 'react';
import { useDesignable } from '../'; import { useDesignable } from '../';
import { createContext } from 'react'; import { createContext } from 'react';
import { useContext } from 'react'; import { useContext } from 'react';
import { isEmpty } from 'lodash'; import { get, isEmpty } from 'lodash';
import { Field, isArrayField, isField } from '@formily/core'; import { Field, isArrayField, isField } from '@formily/core';
import { Action } from '../action'; import { Action } from '../action';
import { BlockSchemaContext, VisibleContext } from '../../context'; import { BlockSchemaContext, VisibleContext } from '../../context';
@ -28,6 +28,7 @@ import { CollectionFieldContext } from '../table';
import { CollectionProvider, useCollectionContext } from '../../constate'; import { CollectionProvider, useCollectionContext } from '../../constate';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import constate from 'constate';
export const Select: any = connect( export const Select: any = connect(
(props) => { (props) => {
@ -236,11 +237,11 @@ Select.Object = connect(
const OptionTagContext = createContext(null); const OptionTagContext = createContext(null);
const SelectedRowKeysContext = createContext([]); const SelectedRowsContext = createContext<any>(null);
Select.useOkAction = () => { Select.useOkAction = () => {
const { props } = useContext(SelectContext); const { props } = useContext(SelectContext);
const [selectedRows] = useContext(SelectedRowKeysContext); const { selectedRows } = useContext(SelectedRowsContext);
return { return {
async run() { async run() {
props.onChange(selectedRows); props.onChange(selectedRows);
@ -249,38 +250,63 @@ Select.useOkAction = () => {
}; };
}; };
Select.useRowSelection = () => {
const { props } = useContext(SelectContext);
return {
type: props.multiple ? 'checkbox' : 'radio',
};
};
Select.useSelect = () => { Select.useSelect = () => {
const [, setSelectedRows] = useContext(SelectedRowKeysContext); const { setSelectedRows } = useContext(SelectedRowsContext);
return (keys, rows) => { return (keys, rows) => {
setSelectedRows(rows); setSelectedRows(rows);
console.log('Select.onSelect', keys, rows); console.log('Select.onSelect', keys, rows);
}; };
}; };
Select.useSelectedRowKeys = () => { export const useSelectedRowKeys = () => {
const [selectedRows] = useContext(SelectedRowKeysContext); const { selectedRows } = useContext(SelectedRowsContext);
return selectedRows?.map((row) => row.id) || []; const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
useEffect(() => {
setSelectedRowKeys(selectedRows.map((row) => row.id));
}, [selectedRows]);
return { selectedRowKeys, setSelectedRowKeys };
}; };
Select.useSelectedRowKeys = useSelectedRowKeys;
const SelectContext = createContext(null); const SelectContext = createContext(null);
Select.Drawer = connect( Select.Drawer = connect(
(props) => { (props) => {
const field = useField<Field>(); const field = useField<Field>();
const { const {
value,
onChange, onChange,
fieldNames = { // fieldNames = {
label: 'id', // label: 'id',
value: 'id', // value: 'id',
}, // },
...others ...others
} = props; } = props;
let value = props.value;
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { schema } = useDesignable(); const { schema } = useDesignable();
const fieldNames = {
label: 'id',
value: 'id',
...(get(schema['x-component-props'], 'fieldNames') || {}),
};
const options = field?.['dataSource'] || props.options || []; const options = field?.['dataSource'] || props.options || [];
if (props.multiple) {
Object.assign(others, {
mode: 'multiple',
});
}
let optionValue = undefined; let optionValue = undefined;
if (props.multiple) {
value = toArr(value);
}
if (isArr(value)) { if (isArr(value)) {
optionValue = value.map((val) => { optionValue = value.map((val) => {
return { return {
@ -294,6 +320,7 @@ Select.Drawer = connect(
value: value[fieldNames.value], value: value[fieldNames.value],
}; };
} }
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
const onFieldChange = (selectValue) => { const onFieldChange = (selectValue) => {
if (!isValid(selectValue)) { if (!isValid(selectValue)) {
@ -323,9 +350,9 @@ Select.Drawer = connect(
options.find((option) => option[fieldNames.value] === selectValue), options.find((option) => option[fieldNames.value] === selectValue),
); );
} }
setSelectedRows(toArr(field.value));
}; };
// const selectedKeys = toArr(optionValue).map((item) => item.value); // const selectedKeys = toArr(optionValue).map((item) => item.value);
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
console.log({ optionValue, value }); console.log({ optionValue, value });
const collectionField = useContext(CollectionFieldContext); const collectionField = useContext(CollectionFieldContext);
return ( return (
@ -352,8 +379,8 @@ Select.Drawer = connect(
} }
}} }}
></AntdSelect> ></AntdSelect>
<SelectedRowKeysContext.Provider <SelectedRowsContext.Provider
value={[selectedRows, setSelectedRows]} value={{ selectedRows, setSelectedRows }}
> >
<CollectionProvider collectionName={collectionField?.target}> <CollectionProvider collectionName={collectionField?.target}>
<RecursionField <RecursionField
@ -364,7 +391,7 @@ Select.Drawer = connect(
}} }}
/> />
</CollectionProvider> </CollectionProvider>
</SelectedRowKeysContext.Provider> </SelectedRowsContext.Provider>
</VisibleContext.Provider> </VisibleContext.Provider>
</SelectContext.Provider> </SelectContext.Provider>
); );
@ -391,9 +418,14 @@ Select.Drawer = connect(
observer((props: any) => { observer((props: any) => {
const collectionField = useContext(CollectionFieldContext); const collectionField = useContext(CollectionFieldContext);
const field = useField<Formily.Core.Models.Field>(); const field = useField<Formily.Core.Models.Field>();
const { fieldNames = { label: 'id' }, ...others } = props; const { ...others } = props;
const value = field.value || field.initialValue; const value = field.value || field.initialValue;
const { schema } = useDesignable(); const { schema } = useDesignable();
const fieldNames = {
label: 'id',
value: 'id',
...(get(schema['x-component-props'], 'fieldNames') || {}),
};
console.log({ fieldNames, field, value }); console.log({ fieldNames, field, value });
if (!value) { if (!value) {
return null; return null;
@ -437,7 +469,7 @@ Select.Drawer.useResource = ({ onSuccess }) => {
resourceName: collection?.name, resourceName: collection?.name,
resourceKey: ctx.data.id, resourceKey: ctx.data.id,
}); });
console.log('OptionTagContext', ctx.data.id) console.log('OptionTagContext', ctx.data.id);
const { schema } = useDesignable(); const { schema } = useDesignable();
const fieldFields = (schema: Schema) => { const fieldFields = (schema: Schema) => {
const names = []; const names = [];
@ -473,7 +505,7 @@ Select.Drawer.useResource = ({ onSuccess }) => {
} }
}, [visible]); }, [visible]);
return { resource, service, initialValues: service.data, ...service }; return { resource, service, initialValues: service.data, ...service };
} };
Select.Options = observer((props) => { Select.Options = observer((props) => {
return <>{props.children}</>; return <>{props.children}</>;

View File

@ -19,7 +19,7 @@ import {
createCollectionField, createCollectionField,
ISchema, ISchema,
} from '..'; } from '..';
import { uid } from '@formily/shared'; import { uid, merge } from '@formily/shared';
import useRequest from '@ahooksjs/use-request'; import useRequest from '@ahooksjs/use-request';
import { BaseResult } from '@ahooksjs/use-request/lib/types'; import { BaseResult } from '@ahooksjs/use-request/lib/types';
import cls from 'classnames'; import cls from 'classnames';
@ -30,7 +30,6 @@ import {
useSortable, useSortable,
verticalListSortingStrategy, verticalListSortingStrategy,
} from '@dnd-kit/sortable'; } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd'; import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
import { PlusOutlined, SettingOutlined } from '@ant-design/icons'; import { PlusOutlined, SettingOutlined } from '@ant-design/icons';
import './style.less'; import './style.less';
@ -54,6 +53,7 @@ import {
DisplayedMapProvider, DisplayedMapProvider,
useCollection, useCollection,
useCollectionContext, useCollectionContext,
useCollectionsContext,
useDisplayedMapContext, useDisplayedMapContext,
} from '../../constate'; } from '../../constate';
import { useResource as useGeneralResource } from '../../hooks/useResource'; import { useResource as useGeneralResource } from '../../hooks/useResource';
@ -140,7 +140,7 @@ function useTableCreateAction() {
const form = useForm(); const form = useForm();
return { return {
async run() { async run() {
console.log('useTableCreateAction', resource) console.log('useTableCreateAction', resource);
if (refreshRequestOnChange) { if (refreshRequestOnChange) {
await resource.create(form.values); await resource.create(form.values);
await form.reset(); await form.reset();
@ -457,11 +457,13 @@ function AddColumn() {
default: [], default: [],
'x-component-props': { 'x-component-props': {
rowKey: 'id', rowKey: 'id',
defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}', useRowSelection: '{{ Select.useRowSelection }}',
useSelectedRowKeys:
'{{ Select.useSelectedRowKeys }}',
onSelect: '{{ Select.useSelect() }}', onSelect: '{{ Select.useSelect() }}',
collectionName: field.target, collectionName: field.target,
// dragSort: true, // dragSort: true,
showIndex: true, // showIndex: true,
refreshRequestOnChange: true, refreshRequestOnChange: true,
pagination: { pagination: {
pageSize: 10, pageSize: 10,
@ -634,6 +636,12 @@ function AddColumn() {
); );
} }
const useDefaultRowSelection = () => {
return {
type: 'checkbox',
};
};
const useDataSource = () => { const useDataSource = () => {
const { const {
pagination, pagination,
@ -657,13 +665,20 @@ const TableMain = () => {
setSelectedRowKeys, setSelectedRowKeys,
service, service,
field, field,
props: { rowKey, dragSort, showIndex, onSelect }, props: {
rowKey,
dragSort,
showIndex,
onSelect,
useRowSelection = useDefaultRowSelection,
},
refresh, refresh,
} = useTable(); } = useTable();
const columns = useTableColumns(); const columns = useTableColumns();
const dataSource = useDataSource(); const dataSource = useDataSource();
const actionBars = useTableActionBars(); const actionBars = useTableActionBars();
const [html, setHtml] = useState(''); const [html, setHtml] = useState('');
const { type } = useRowSelection();
return ( return (
<div className={'nb-table'}> <div className={'nb-table'}>
<DndContext <DndContext
@ -744,7 +759,7 @@ const TableMain = () => {
}, },
}} }}
rowSelection={{ rowSelection={{
type: 'checkbox', type: type || 'checkbox',
selectedRowKeys, selectedRowKeys,
onChange: (rowKeys, rows) => { onChange: (rowKeys, rows) => {
setSelectedRowKeys(rowKeys); setSelectedRowKeys(rowKeys);
@ -815,20 +830,25 @@ const usePagination = () => {
]; ];
}; };
const useDefaultSelectedRowKeys = () => {
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
return { selectedRowKeys, setSelectedRowKeys };
};
const TableProvider = (props: any) => { const TableProvider = (props: any) => {
const { const {
rowKey = 'id', rowKey = 'id',
dataRequest, dataRequest,
useResource = useGeneralResource, useResource = useGeneralResource,
defaultSelectedRowKeys, defaultSelectedRowKeys,
useSelectedRowKeys = useDefaultSelectedRowKeys,
...others ...others
} = props; } = props;
const { schema } = useDesignable(); const { schema } = useDesignable();
const field = useField<Formily.Core.Models.ArrayField>(); const field = useField<Formily.Core.Models.ArrayField>();
const [pagination, setPagination] = usePagination(); const [pagination, setPagination] = usePagination();
const [selectedRowKeys, setSelectedRowKeys] = useState<any>( const { selectedRowKeys, setSelectedRowKeys } = useSelectedRowKeys();
defaultSelectedRowKeys || [], console.log('props.useSelectedRowKeys', selectedRowKeys);
);
const [, refresh] = useState(uid()); const [, refresh] = useState(uid());
const { resource } = useResource(); const { resource } = useResource();
const { sortableField } = useCollectionContext(); const { sortableField } = useCollectionContext();
@ -1968,6 +1988,14 @@ Table.Cell = observer((props: any) => {
uiSchema = cloneDeepWith(uiSchema); uiSchema = cloneDeepWith(uiSchema);
set(uiSchema, 'x-component-props.size', 'small'); set(uiSchema, 'x-component-props.size', 'small');
} }
const componentProps = merge(
uiSchema?.['x-component-props'] || {},
schema?.['x-component-props'] || {},
{
arrayMerge: (t, s) => s,
},
);
console.log('Table.Cell', collectionField?.interface, componentProps);
return ( return (
<div className={`field-interface-${collectionField?.interface}`}> <div className={`field-interface-${collectionField?.interface}`}>
<RecursionField <RecursionField
@ -1985,6 +2013,7 @@ Table.Cell = observer((props: any) => {
feedbackLayout: 'popover', feedbackLayout: 'popover',
}, },
'x-decorator': 'FormilyFormItem', 'x-decorator': 'FormilyFormItem',
'x-component-props': componentProps,
properties: { properties: {
...schema?.properties, ...schema?.properties,
}, },
@ -2018,10 +2047,12 @@ Table.Column = observer((props: any) => {
Table.Column.DesignableBar = () => { Table.Column.DesignableBar = () => {
const field = useField(); const field = useField();
const { service, refresh: refreshTable } = useTable();
// 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 displayed = useDisplayedMapContext(); const displayed = useDisplayedMapContext();
const { getFieldsByCollection } = useCollectionsContext();
const collectionField = useContext(CollectionFieldContext); const collectionField = useContext(CollectionFieldContext);
console.log('displayed.map', displayed.map); console.log('displayed.map', displayed.map);
return ( return (
@ -2088,6 +2119,52 @@ Table.Column.DesignableBar = () => {
> >
</Menu.Item> </Menu.Item>
{collectionField.interface === 'linkTo' && (
<Menu.Item>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
{' '}
<Select
value={
schema?.['x-component-props']?.['fieldNames']?.[
'label'
]
}
placeholder={'默认为 ID 字段'}
onChange={async (value) => {
set(
schema['x-component-props'],
'fieldNames.label',
value,
);
await updateSchema({
key: schema['key'],
'x-component-props': {
fieldNames: {
label: value,
},
},
});
refreshTable();
// await service.refresh();
}}
bordered={false}
size={'small'}
style={{ marginLeft: 16, minWidth: 120 }}
options={getFieldsByCollection(collectionField.target)
.filter((f) => f?.uiSchema?.title)
.map((field) => ({
label: field?.uiSchema?.title || field.name,
value: field.name,
}))}
/>
</div>
</Menu.Item>
)}
<Menu.Divider /> <Menu.Divider />
<Menu.Item <Menu.Item
onClick={async () => { onClick={async () => {