mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-03 20:58:01 +08:00
feat(client): example of CollectionProvider + ResourceActionProvider
This commit is contained in:
parent
0440591868
commit
6036189063
@ -2,6 +2,7 @@ import { ArrayField } from '@formily/core';
|
|||||||
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { Table, TableColumnProps } from 'antd';
|
import { Table, TableColumnProps } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { RecordProvider } from '../../../';
|
||||||
import { useComponent } from '../../hooks';
|
import { useComponent } from '../../hooks';
|
||||||
|
|
||||||
const isColumnComponent = (schema: Schema) => {
|
const isColumnComponent = (schema: Schema) => {
|
||||||
@ -24,7 +25,11 @@ const useTableColumns = () => {
|
|||||||
dataIndex: s.name,
|
dataIndex: s.name,
|
||||||
render: (v, record) => {
|
render: (v, record) => {
|
||||||
const index = field.value?.indexOf(record);
|
const index = field.value?.indexOf(record);
|
||||||
return <RecursionField schema={s} name={index} onlyRenderProperties />;
|
return (
|
||||||
|
<RecordProvider record={record}>
|
||||||
|
<RecursionField schema={s} name={index} onlyRenderProperties />
|
||||||
|
</RecordProvider>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
} as TableColumnProps<any>;
|
} as TableColumnProps<any>;
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,7 @@ export interface FormProps {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormUseValues = (props?: FormProps, opts?: Opts) => Result<any, any>;
|
export type FormUseValues = (opts?: Opts, props?: FormProps) => Result<any, any>;
|
||||||
|
|
||||||
const FormComponent: React.FC<FormProps> = (props) => {
|
const FormComponent: React.FC<FormProps> = (props) => {
|
||||||
const { form, children, ...others } = props;
|
const { form, children, ...others } = props;
|
||||||
@ -43,7 +43,7 @@ const useRequestProps = (props: any) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const useDef = (props: FormProps = {}, opts: any = {}) => {
|
const useDef = (opts: any = {}, props: FormProps = {}) => {
|
||||||
return useRequest(useRequestProps(props), opts);
|
return useRequest(useRequestProps(props), opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,13 +51,16 @@ export const Form: React.FC<FormProps> = observer((props) => {
|
|||||||
const { request, initialValue, useValues = useDef, ...others } = props;
|
const { request, initialValue, useValues = useDef, ...others } = props;
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const form = useMemo(() => createForm(), []);
|
const form = useMemo(() => createForm(), []);
|
||||||
const { loading } = useValues(props, {
|
const { loading } = useValues(
|
||||||
|
{
|
||||||
uid: fieldSchema['x-uid'],
|
uid: fieldSchema['x-uid'],
|
||||||
async onSuccess(data) {
|
async onSuccess(data) {
|
||||||
await form.reset();
|
await form.reset();
|
||||||
form.setValues(data?.data);
|
form.setValues(data?.data);
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
props,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<FormComponent form={form} {...others} />
|
<FormComponent form={form} {...others} />
|
||||||
|
@ -50,7 +50,7 @@ const useSubmit = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const useValues: FormUseValues = (props, opts) => {
|
const useValues: FormUseValues = (opts) => {
|
||||||
return useRequest(() => {
|
return useRequest(() => {
|
||||||
return Promise.resolve({ data: { field1: 'aabb' } });
|
return Promise.resolve({ data: { field1: 'aabb' } });
|
||||||
}, opts);
|
}, opts);
|
||||||
|
@ -10,7 +10,7 @@ import { ArrayTable } from '../array-table';
|
|||||||
|
|
||||||
type VoidTableProps = TableProps<any> & {
|
type VoidTableProps = TableProps<any> & {
|
||||||
request?: any;
|
request?: any;
|
||||||
useDataSource?: (data?: any, options?: Options<any, any> & { uid?: string }) => Result<any, any>;
|
useDataSource?: (options?: Options<any, any> & { uid?: string }, props?: any) => Result<any, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type VoidTableType = React.FC<VoidTableProps> & {
|
type VoidTableType = React.FC<VoidTableProps> & {
|
||||||
@ -66,17 +66,18 @@ const useRequestProps = (props) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const useDefDataSource = (props, options) => {
|
const useDef = (options, props) => {
|
||||||
return useRequest(useRequestProps(props), options);
|
return useRequest(useRequestProps(props), options);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VoidTable: VoidTableType = observer((props) => {
|
export const VoidTable: VoidTableType = observer((props) => {
|
||||||
const { useDataSource = useDefDataSource } = props;
|
const { useDataSource = useDef } = props;
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const form = useMemo(() => createForm(), []);
|
const form = useMemo(() => createForm(), []);
|
||||||
const f = useAttach(form.createArrayField({ name: fieldSchema.name }));
|
const f = useAttach(form.createArrayField({ name: fieldSchema.name }));
|
||||||
const result = useDataSource(props, {
|
const result = useDataSource(
|
||||||
|
{
|
||||||
uid: fieldSchema['x-uid'],
|
uid: fieldSchema['x-uid'],
|
||||||
onSuccess(data) {
|
onSuccess(data) {
|
||||||
form.setValues({
|
form.setValues({
|
||||||
@ -92,7 +93,9 @@ export const VoidTable: VoidTableType = observer((props) => {
|
|||||||
field.componentProps.pagination.current = data?.meta?.page || 1;
|
field.componentProps.pagination.current = data?.meta?.page || 1;
|
||||||
field.componentProps.pagination.pageSize = data?.meta?.pageSize || 10;
|
field.componentProps.pagination.pageSize = data?.meta?.pageSize || 10;
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
props,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<AsyncDataProvider value={result}>
|
<AsyncDataProvider value={result}>
|
||||||
<FormContext.Provider value={form}>
|
<FormContext.Provider value={form}>
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
/**
|
|
||||||
* title: 勾选
|
|
||||||
*/
|
|
||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import {
|
import {
|
||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
APIClientProvider,
|
APIClientProvider,
|
||||||
CollectionField,
|
CollectionField,
|
||||||
|
CollectionManagerProvider,
|
||||||
CollectionProvider,
|
CollectionProvider,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
SchemaComponentProvider,
|
SchemaComponentProvider,
|
||||||
useCollection
|
useCollection,
|
||||||
|
useDesignable,
|
||||||
|
useRequest
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React, { useEffect } from 'react';
|
import React, { createContext, useContext, useEffect } from 'react';
|
||||||
import { useDesignable } from '../../..';
|
|
||||||
import { apiClient } from './apiClient';
|
import { apiClient } from './apiClient';
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
@ -21,7 +20,22 @@ const schema: ISchema = {
|
|||||||
properties: {
|
properties: {
|
||||||
block1: {
|
block1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'CollectionBlock',
|
'x-decorator': 'CollectionProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
name: 'posts',
|
||||||
|
},
|
||||||
|
'x-component': 'ResourceActionProvider',
|
||||||
|
'x-component-props': {
|
||||||
|
request: {
|
||||||
|
resource: 'posts',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
filter: {},
|
||||||
|
sort: [],
|
||||||
|
appends: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
table1: {
|
table1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -32,18 +46,7 @@ const schema: ISchema = {
|
|||||||
rowSelection: {
|
rowSelection: {
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
pagination: {
|
useDataSource: '{{ useDataSourceFromRAC }}',
|
||||||
current: 2,
|
|
||||||
pageSize: 2,
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
resource: 'posts',
|
|
||||||
action: 'list',
|
|
||||||
params: {
|
|
||||||
filter: {},
|
|
||||||
// pageSize: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
column1: {
|
column1: {
|
||||||
@ -142,10 +145,8 @@ const TableColumnDecorator = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CollectionBlock = (props) => {
|
const collections = [
|
||||||
return (
|
{
|
||||||
<CollectionProvider
|
|
||||||
collection={{
|
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -189,21 +190,40 @@ const CollectionBlock = (props) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}}
|
},
|
||||||
>
|
];
|
||||||
{props.children}
|
|
||||||
</CollectionProvider>
|
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 };
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<APIClientProvider apiClient={apiClient}>
|
<APIClientProvider apiClient={apiClient}>
|
||||||
<SchemaComponentProvider components={{ TableColumnDecorator, CollectionBlock, CollectionField }}>
|
<CollectionManagerProvider collections={collections}>
|
||||||
|
<SchemaComponentProvider components={componets}>
|
||||||
<AntdSchemaComponentProvider>
|
<AntdSchemaComponentProvider>
|
||||||
<SchemaComponent schema={schema} />
|
<SchemaComponent schema={schema} scope={{ useDataSourceFromRAC }} />
|
||||||
</AntdSchemaComponentProvider>
|
</AntdSchemaComponentProvider>
|
||||||
</SchemaComponentProvider>
|
</SchemaComponentProvider>
|
||||||
|
</CollectionManagerProvider>
|
||||||
</APIClientProvider>
|
</APIClientProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -202,6 +202,50 @@ export default () => {
|
|||||||
|
|
||||||
<code src="./demos/demo1.tsx">
|
<code src="./demos/demo1.tsx">
|
||||||
|
|
||||||
CollectionProvider + CollectionField
|
### CollectionProvider + ResourceActionProvider
|
||||||
|
|
||||||
<code src="./demos/demo2.tsx">
|
<code src="./demos/demo2.tsx">
|
||||||
|
|
||||||
|
大纲
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
<CollectionProvider> {/* 属于哪个 collection */}
|
||||||
|
<ResourceActionProvider> {/* 发起请求,将请求结果存到上下文共享给子组件 */}
|
||||||
|
<SettingsForm /> {/* 区块的配置表单 */}
|
||||||
|
<ActionBar /> {/* 操作区 */}
|
||||||
|
<Table/> {/* 具体的组件,如 Table、Form、Calendar 等 */}
|
||||||
|
</ResourceActionProvider>
|
||||||
|
</CollectionProvider>
|
||||||
|
```
|
||||||
|
|
||||||
|
通过 CollectionProvider 和 ResourceActionProvider 来解决数据区块配置和数据请求,与具体组件无关,所有区块通用。在里面可以放任意东西。
|
||||||
|
|
||||||
|
嵌套使用的情况
|
||||||
|
|
||||||
|
```tsx | pure
|
||||||
|
<CollectionProvider> {/* 属于哪个 collection */}
|
||||||
|
<ResourceActionProvider> {/* 发起请求,将请求结果存到上下文共享给子组件 */}
|
||||||
|
<SettingsForm /> {/* 区块的配置表单 */}
|
||||||
|
<ActionBar /> {/* 操作区 */}
|
||||||
|
<Table> {/* 具体的组件 */}
|
||||||
|
<Table.Column>
|
||||||
|
<SettingsForm /> {/* 表格列的配置表单 */}
|
||||||
|
<RecordProvider> {/* 列表数据的行记录 */}
|
||||||
|
<CollectionField>
|
||||||
|
<CollectionFieldProvider> {/* 是哪个字段 */}
|
||||||
|
<CollectionProvider> {/* 关联字段的关联表 collection */}
|
||||||
|
<ResourceActionProvider> {/* 可能也会发起请求,如查看详情 */}
|
||||||
|
<SettingsForm />
|
||||||
|
<ActionBar />
|
||||||
|
<Table />
|
||||||
|
</ResourceActionProvider>
|
||||||
|
</CollectionProvider>
|
||||||
|
</CollectionFieldProvider>
|
||||||
|
</CollectionField>
|
||||||
|
</RecordProvider>
|
||||||
|
</Table.Column>
|
||||||
|
<Table.Column></Table.Column> {/* 会有很多列 */}
|
||||||
|
</Table>
|
||||||
|
</ResourceActionProvider>
|
||||||
|
</CollectionProvider>
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user