feat(client): improve code

This commit is contained in:
chenos 2022-02-16 15:11:24 +08:00
parent 054a73d576
commit 022c173f7e
11 changed files with 386 additions and 94 deletions

View File

@ -1,14 +1,15 @@
import React, { useContext, useEffect } from 'react';
import { connect, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@formily/react';
import { useCollectionField } from './hooks';
import { CollectionFieldProvider } from './CollectionFieldProvider';
import { Field, FormPath } from '@formily/core';
import { connect, SchemaOptionsContext, useField, useFieldSchema } from '@formily/react';
import React, { useContext, useEffect } from 'react';
import { CollectionFieldProvider } from './CollectionFieldProvider';
import { useCollectionField } from './hooks';
// TODO: 初步适配
const InternalField: React.FC = (props) => {
const field = useField<Field>();
const fieldSchema = useFieldSchema();
const { uiSchema } = useCollectionField();
console.log('uiSchema', uiSchema);
const options = useContext(SchemaOptionsContext);
const component = FormPath.getIn(options?.components, uiSchema['x-component']);
const setFieldProps = (key, value) => {

View File

@ -1,12 +1,15 @@
import React from 'react';
import { CollectionManagerOptions } from './types';
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
import { CollectionManagerContext } from './context';
import { CollectionManagerOptions } from './types';
export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (props) => {
const { interfaces, collections } = props;
return (
<CollectionManagerContext.Provider value={{ interfaces, collections }}>
<CollectionManagerSchemaComponentProvider>
{props.children}
</CollectionManagerSchemaComponentProvider>
</CollectionManagerContext.Provider>
);
};

View File

@ -0,0 +1,20 @@
import React from 'react';
import { SchemaComponentOptions } from '../';
import {
CollectionField,
CollectionFieldProvider,
CollectionProvider,
ResourceActionProvider,
useDataSourceFromRAC
} from './';
export const CollectionManagerSchemaComponentProvider: React.FC = (props) => {
return (
<SchemaComponentOptions
scope={{ useDataSourceFromRAC }}
components={{ CollectionField, CollectionFieldProvider, CollectionProvider, ResourceActionProvider }}
>
{props.children}
</SchemaComponentOptions>
);
};

View File

@ -0,0 +1,34 @@
import { Result } from 'ahooks/lib/useRequest/src/types';
import React, { createContext, useContext, useEffect } from 'react';
import { useRequest } from '../api-client';
export const ResourceActionContext = createContext<Result<any, any>>(null);
interface ResourceActionProviderProps {
request?: any;
uid?: string;
}
export const ResourceActionProvider: React.FC<ResourceActionProviderProps> = (props) => {
const { request, uid } = props;
console.log(request);
const service = useRequest(request, {
uid,
refreshDeps: [request],
});
return <ResourceActionContext.Provider value={service}>{props.children}</ResourceActionContext.Provider>;
};
export const useResourceActionContext = () => {
return useContext(ResourceActionContext);
};
export const useDataSourceFromRAC = (options: any) => {
const service = useContext(ResourceActionContext);
useEffect(() => {
if (!service.loading) {
options?.onSuccess(service.data);
}
}, [service.loading]);
return service;
};

View File

@ -0,0 +1,163 @@
import { ISchema } from '@formily/react';
import {
AntdSchemaComponentProvider, CollectionManagerProvider,
SchemaComponent,
SchemaComponentProvider
} from '@nocobase/client';
import React from 'react';
const schema: ISchema = {
type: 'object',
properties: {
block1: {
type: 'void',
'x-decorator': 'CollectionProvider',
'x-decorator-props': {
name: 'posts',
},
properties: {
createdBy: {
'x-component': 'CollectionField',
'x-read-pretty': true,
properties: {
rowSelection: {
'x-component': 'RowSelection',
'x-component-props': {
rowKey: 'id',
objectValue: true,
rowSelection: {
type: 'checkbox',
},
dataSource: [
{ id: 1, name: 'Name1' },
{ id: 2, name: 'Name2' },
{ id: 3, name: 'Name3' },
],
},
properties: {
column1: {
type: 'void',
title: 'Name',
'x-component': 'RowSelection.Column',
properties: {
name: {
type: 'string',
'x-component': 'Input',
'x-read-pretty': true,
},
},
},
},
},
item: {
'x-component': 'RecordPicker.SelectedItem',
properties: {
drawer1: {
'x-component': 'Action.Drawer',
type: 'void',
title: 'Drawer Title',
properties: {
hello1: {
'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
close1: {
type: 'void',
title: 'Close',
'x-component': 'Action',
'x-component-props': {
// useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
},
},
},
},
},
},
};
const collections = [
{
name: 'posts',
fields: [
{
type: 'integer',
name: 'id',
interface: 'input',
uiSchema: {
title: 'ID1',
type: 'number',
'x-component': 'InputNumber',
required: true,
description: 'description1',
} as ISchema,
},
{
type: 'string',
name: 'name',
interface: 'input',
uiSchema: {
title: 'Name1',
type: 'string',
'x-component': 'Input',
required: true,
description: 'description1',
} as ISchema,
},
{
type: 'string',
name: 'date',
interface: 'datetime',
uiSchema: {
type: 'boolean',
title: `Date1`,
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'DatePicker',
'x-component-props': {
dateFormat: 'YYYY/MM/DD',
// showTime: true,
},
},
},
{
type: 'belongsToMany',
name: 'createdBy',
target: 'users',
foreignKey: 'createdById',
uiSchema: {
type: 'array',
title: `创建人`,
default: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'name2' },
],
'x-decorator': 'FormItem',
'x-component': 'RecordPicker',
},
},
],
},
];
export default () => {
return (
<SchemaComponentProvider>
<AntdSchemaComponentProvider>
<CollectionManagerProvider collections={collections}>
<SchemaComponent schema={schema} />
</CollectionManagerProvider>
</AntdSchemaComponentProvider>
</SchemaComponentProvider>
);
};

View File

@ -142,3 +142,4 @@ const { name, uiSchema, resource } = useCollectionField();
resource 需要与 `<RecordProvider/>` 搭配使用,用于提供当前数据表行记录的上下文。如:
<code src="./demos/demo3.tsx"/>
<code src="./demos/demo4.tsx"/>

View File

@ -1,8 +1,11 @@
export * from './CollectionField';
export * from './CollectionFieldProvider';
export * from './CollectionManagerProvider';
export * from './CollectionManagerSchemaComponentProvider';
export * from './CollectionManagerShortcut';
export * from './CollectionProvider';
export * from './context';
export * from './hooks';
export * from './ResourceActionProvider';
export * from './types';
export * from './CollectionField';
export * from './CollectionManagerShortcut';

View File

@ -0,0 +1,54 @@
import { useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import React, { useEffect } from 'react';
import { useCollection, useDesignable } from '../../../';
export const useColumnSchema = () => {
const { getField } = useCollection();
const columnSchema = useFieldSchema();
const fieldSchema = columnSchema.reduceProperties((buf, s) => {
if (s['x-component'] === 'CollectionField') {
return s;
}
return buf;
}, null);
if (!fieldSchema) {
return;
}
const collectionField = getField(fieldSchema.name);
return { columnSchema, fieldSchema, collectionField };
};
export const TableColumnDecorator = (props) => {
const field = useField();
const { columnSchema, fieldSchema, collectionField } = useColumnSchema();
const { refresh } = useDesignable();
useEffect(() => {
if (field.title) {
return;
}
if (!fieldSchema) {
return;
}
if (collectionField?.uiSchema?.title) {
field.title = collectionField?.uiSchema?.title;
}
}, []);
return (
<>
{props.children}
<div
onClick={() => {
field.title = uid();
columnSchema.title = field.title = field.title;
refresh();
field.query(`.*.${fieldSchema.name}`).take((f) => {
f.componentProps.dateFormat = 'YYYY-MM-DD';
});
}}
>
Edit
</div>
</>
);
};

View File

@ -1,3 +1,4 @@
export * from './ArrayTable';
export * from './Initializer';
export * from './TableColumnDecorator';

View File

@ -22,7 +22,10 @@ mock.onGet('/posts:list').reply(async (config) => {
return {
id: v + (page - 1) * pageSize,
name: uid(),
date: '2022-01-02 22:22:22'
date: '2022-01-02 22:22:22',
createdBy: [
{ id: 1, name: 'name1' },
],
};
}),
meta: {

View File

@ -1,18 +1,13 @@
import { ISchema, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import { ISchema, observer, useField, useFieldSchema } from '@formily/react';
import {
AntdSchemaComponentProvider,
APIClientProvider,
CollectionField,
CollectionManagerProvider,
CollectionProvider,
SchemaComponent,
SchemaComponentProvider,
useCollection,
useDesignable,
useRequest
SchemaComponentProvider
} from '@nocobase/client';
import React, { createContext, useContext, useEffect } from 'react';
import { Button } from 'antd';
import React from 'react';
import { apiClient } from './apiClient';
const schema: ISchema = {
@ -30,6 +25,7 @@ const schema: ISchema = {
resource: 'posts',
action: 'list',
params: {
pageSize: 5,
filter: {},
sort: [],
appends: [],
@ -37,6 +33,9 @@ const schema: ISchema = {
},
},
properties: {
settings: {
'x-component': 'SimpleSettingsForm',
},
table1: {
type: 'void',
'x-uid': 'input',
@ -88,6 +87,50 @@ const schema: ISchema = {
},
},
},
column4: {
type: 'void',
// title: 'Name',
'x-decorator': 'TableColumnDecorator',
'x-component': 'VoidTable.Column',
properties: {
createdBy: {
'x-component': 'CollectionField',
'x-read-pretty': true,
properties: {
item: {
'x-component': 'RecordPicker.SelectedItem',
properties: {
drawer1: {
'x-component': 'Action.Drawer',
type: 'void',
title: 'Drawer Title',
properties: {
hello1: {
'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
close1: {
type: 'void',
title: 'Close',
'x-component': 'Action',
'x-component-props': {
// useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
@ -95,56 +138,6 @@ const schema: ISchema = {
},
};
const useColumnSchema = () => {
const { getField } = useCollection();
const columnSchema = useFieldSchema();
const fieldSchema = columnSchema.reduceProperties((buf, s) => {
if (s['x-component'] === 'CollectionField') {
return s;
}
return buf;
}, null);
if (!fieldSchema) {
return;
}
const collectionField = getField(fieldSchema.name);
return { columnSchema, fieldSchema, collectionField };
};
const TableColumnDecorator = (props) => {
const field = useField();
const { columnSchema, fieldSchema, collectionField } = useColumnSchema();
const { refresh } = useDesignable();
useEffect(() => {
if (field.title) {
return;
}
if (!fieldSchema) {
return;
}
if (collectionField?.uiSchema?.title) {
field.title = collectionField?.uiSchema?.title;
}
}, []);
return (
<>
{props.children}
<div
onClick={() => {
field.title = uid();
columnSchema.title = field.title = field.title;
refresh();
field.query(`.*.${fieldSchema.name}`).take((f) => {
f.componentProps.dateFormat = 'YYYY-MM-DD';
});
}}
>
Edit
</div>
</>
);
};
const collections = [
{
name: 'posts',
@ -189,41 +182,57 @@ const collections = [
},
},
},
{
type: 'belongsToMany',
name: 'createdBy',
target: 'users',
foreignKey: 'createdById',
uiSchema: {
type: 'array',
title: `创建人`,
// default: [
// { id: 1, name: 'name1' },
// { id: 2, name: 'name2' },
// ],
'x-decorator': 'FormItem',
'x-component': 'RecordPicker',
},
},
],
},
];
const ResourceActionContext = createContext(null);
const ResourceActionProvider = (props) => {
const { name } = useCollection();
const { request } = props;
const service = useRequest(request);
return <ResourceActionContext.Provider value={{ service }}>{props.children}</ResourceActionContext.Provider>;
};
const useDataSourceFromRAC = (options: any) => {
const { service } = useContext(ResourceActionContext);
useEffect(() => {
if (!service.loading) {
options?.onSuccess(service.data);
}
}, [service.loading]);
return service;
};
const componets = { CollectionProvider, TableColumnDecorator, ResourceActionProvider, CollectionField };
const SimpleSettingsForm = observer(() => {
const field = useField();
const fieldSchema = useFieldSchema();
return (
<div>
<Button
onClick={() => {
fieldSchema.parent['x-component-props']['request']['params']['pageSize'] = 20;
field.query('.').take((f) => {
f.componentProps.request.params.pageSize = 20;
});
}}
>
Edit
</Button>
<br />
<br />
</div>
);
});
export default () => {
return (
<APIClientProvider apiClient={apiClient}>
<CollectionManagerProvider collections={collections}>
<SchemaComponentProvider components={componets}>
<AntdSchemaComponentProvider>
<SchemaComponent schema={schema} scope={{ useDataSourceFromRAC }} />
</AntdSchemaComponentProvider>
</SchemaComponentProvider>
</CollectionManagerProvider>
<SchemaComponentProvider>
<AntdSchemaComponentProvider>
<CollectionManagerProvider collections={collections}>
<SchemaComponent schema={schema} components={{ SimpleSettingsForm }} />
</CollectionManagerProvider>
</AntdSchemaComponentProvider>
</SchemaComponentProvider>
</APIClientProvider>
);
};