mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-04 05:08:42 +08:00
feat: table related components (#172)
* table-related components * feat: ArrayTable & VoidTable & RowSelection * update * fix: missing request params * fix(client): get sideMenuRef from context * void table * fix: use request params merge * demo * void table demo * feat: improve code * feat: improve code * feat: row select table * feat: record picker
This commit is contained in:
parent
d0b6efaaf5
commit
f9a18863ad
@ -131,7 +131,7 @@ export default (apiClient: APIClient) => {
|
|||||||
uiSchemaUid: 'qqzzjakwkwl',
|
uiSchemaUid: 'qqzzjakwkwl',
|
||||||
path: '/admin/:name(.+)?',
|
path: '/admin/:name(.+)?',
|
||||||
component: 'AdminLayout',
|
component: 'AdminLayout',
|
||||||
title: 'NocoBase',
|
title: 'NocoBase Admin',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'route',
|
type: 'route',
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
|
||||||
import { Result } from 'ahooks/lib/useRequest/src/types';
|
import { Result } from 'ahooks/lib/useRequest/src/types';
|
||||||
|
import React, { createContext, useContext } from 'react';
|
||||||
import { useRequest } from '../api-client';
|
import { useRequest } from '../api-client';
|
||||||
|
|
||||||
export const AsyncDataContext = createContext<Result<any, any>>(null);
|
export const AsyncDataContext = createContext<Result<any, any>>(null);
|
||||||
|
|
||||||
export interface AsyncDataProviderProps {
|
export interface AsyncDataProviderProps {
|
||||||
value?: any;
|
value?: any;
|
||||||
resource?: any;
|
|
||||||
request?: any;
|
request?: any;
|
||||||
action?: string;
|
uid?: string;
|
||||||
defaultParams?: any;
|
onSuccess?: (data, params) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AsyncDataProvider: React.FC<AsyncDataProviderProps> = (props) => {
|
export const AsyncDataProvider: React.FC<AsyncDataProviderProps> = (props) => {
|
||||||
const { value, request, resource, action, defaultParams, children } = props;
|
const { value, request, children, ...others } = props;
|
||||||
if (value) {
|
if (value) {
|
||||||
return <AsyncDataContext.Provider value={value}>{children}</AsyncDataContext.Provider>;
|
return <AsyncDataContext.Provider value={value}>{children}</AsyncDataContext.Provider>;
|
||||||
}
|
}
|
||||||
const callback = (params?: any) => resource[action]({ ...defaultParams, ...params });
|
const result = useRequest(request, { ...others });
|
||||||
const result = useRequest(request || callback);
|
|
||||||
return <AsyncDataContext.Provider value={result}>{children}</AsyncDataContext.Provider>;
|
return <AsyncDataContext.Provider value={result}>{children}</AsyncDataContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
|
|
||||||
export const VisibleContext = createContext(null);
|
export const VisibleContext = createContext<[boolean, any]>([false, () => {}]);
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
import { ArrayField } from '@formily/core';
|
||||||
|
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { Table, TableColumnProps } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const isColumnComponent = (schema: Schema) => {
|
||||||
|
return schema['x-component']?.endsWith('.Column') > -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useTableColumns = () => {
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const columns = schema
|
||||||
|
.reduceProperties((buf, s) => {
|
||||||
|
if (isColumnComponent(s)) {
|
||||||
|
return buf.concat([s]);
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
.map((s: Schema) => {
|
||||||
|
return {
|
||||||
|
title: <RecursionField name={s.name} schema={s} onlyRenderSelf />,
|
||||||
|
dataIndex: s.name,
|
||||||
|
render: (v, record) => {
|
||||||
|
const index = field.value?.indexOf(record);
|
||||||
|
return <RecursionField schema={s} name={index} onlyRenderProperties />;
|
||||||
|
},
|
||||||
|
} as TableColumnProps<any>;
|
||||||
|
});
|
||||||
|
console.log(columns);
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ArrayTableType = React.FC<any> & {
|
||||||
|
Column?: React.FC<any>;
|
||||||
|
mixin?: (T: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ArrayTable: ArrayTableType = observer((props) => {
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const columns = useTableColumns();
|
||||||
|
const { onChange, ...others } = props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table {...others} columns={columns} dataSource={field.value?.slice()}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayTable.Column = (props) => {
|
||||||
|
const field = useField();
|
||||||
|
return <div>{field.title}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayTable.mixin = (Table: any) => {
|
||||||
|
Table.Column = ArrayTable.Column;
|
||||||
|
};
|
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* title: 勾选
|
||||||
|
*/
|
||||||
|
import { FormItem } from '@formily/antd';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { ArrayTable, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'array',
|
||||||
|
title: `编辑模式`,
|
||||||
|
default: [
|
||||||
|
{ id: 1, name: 'Name1' },
|
||||||
|
{ id: 2, name: 'Name2' },
|
||||||
|
{ id: 3, name: 'Name3' },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'read',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
read: {
|
||||||
|
type: 'array',
|
||||||
|
title: `阅读模式`,
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentProvider components={{ Input, ArrayTable, FormItem }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,4 +5,41 @@ group:
|
|||||||
path: /schema-components
|
path: /schema-components
|
||||||
---
|
---
|
||||||
|
|
||||||
# ArrayTable <Badge>待定</Badge>
|
# ArrayTable - 表格(数据录入) <Badge>待定</Badge>
|
||||||
|
|
||||||
|
ArrayTable 更侧重于数据录入,如果需要动态的表格数据展示,请使用 [VoidTable](void-table)。
|
||||||
|
|
||||||
|
## JSON Schema
|
||||||
|
|
||||||
|
ArrayTable 的 props 与 antd 的 [Table](https://ant.design/components/table/#API) 基本一致。但并不直接用 Table 组件的 columns 和 dataSource。dataSource 由表单提供,默认值写在 default 里;为了更好的支持 columns 的渲染,添加了 ArrayTable.Column 用于配置表格列,ArrayTable.Column 写在 properties 里,属性与 antd 的 [Table.Column](https://ant.design/components/table/#Column) 一致。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
default: [
|
||||||
|
{ id: 1, name: 'Name1' },
|
||||||
|
{ id: 2, name: 'Name2' },
|
||||||
|
{ id: 3, name: 'Name3' },
|
||||||
|
],
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'Name',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<code src="./demos/demo1.tsx"/>
|
@ -0,0 +1 @@
|
|||||||
|
export * from './ArrayTable';
|
@ -1,4 +1,5 @@
|
|||||||
export * from './action';
|
export * from './action';
|
||||||
|
export * from './array-table';
|
||||||
export * from './block-item';
|
export * from './block-item';
|
||||||
export * from './cascader';
|
export * from './cascader';
|
||||||
export * from './checkbox';
|
export * from './checkbox';
|
||||||
@ -15,7 +16,11 @@ export * from './menu';
|
|||||||
export * from './page';
|
export * from './page';
|
||||||
export * from './password';
|
export * from './password';
|
||||||
export * from './radio';
|
export * from './radio';
|
||||||
|
export * from './record-picker';
|
||||||
|
export * from './row-selection';
|
||||||
export * from './select';
|
export * from './select';
|
||||||
export * from './time-picker';
|
export * from './time-picker';
|
||||||
export * from './tree-select';
|
export * from './tree-select';
|
||||||
export * from './upload';
|
export * from './upload';
|
||||||
|
export * from './void-table';
|
||||||
|
|
||||||
|
@ -0,0 +1,138 @@
|
|||||||
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
|
import { createForm, Field, onFormSubmit } from '@formily/core';
|
||||||
|
import {
|
||||||
|
connect,
|
||||||
|
FieldContext,
|
||||||
|
FormContext,
|
||||||
|
mapProps,
|
||||||
|
mapReadPretty,
|
||||||
|
RecursionField,
|
||||||
|
Schema,
|
||||||
|
useField,
|
||||||
|
useFieldSchema
|
||||||
|
} from '@formily/react';
|
||||||
|
import { toArr } from '@formily/shared';
|
||||||
|
import { Button, Drawer, Select, Tag } from 'antd';
|
||||||
|
import React, { createContext, useContext, useMemo, useState } from 'react';
|
||||||
|
import { useAttach } from '../../hooks/useAttach';
|
||||||
|
import { VisibleContext } from '../action';
|
||||||
|
|
||||||
|
const InputRecordPicker: React.FC = (props) => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const field = useField<Field>();
|
||||||
|
const s = fieldSchema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-component'] === 'RowSelection') {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, new Schema({}));
|
||||||
|
const form = useMemo(
|
||||||
|
() =>
|
||||||
|
createForm({
|
||||||
|
initialValues: {
|
||||||
|
[s.name]: field.value,
|
||||||
|
},
|
||||||
|
effects() {
|
||||||
|
onFormSubmit((form) => {
|
||||||
|
field.value = form.values[s.name];
|
||||||
|
console.log('field.value', form.values[s.name]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const f = useAttach(form.createVoidField({ ...field.props, basePath: '' }));
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
onClick={() => {
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
open={false}
|
||||||
|
></Select>
|
||||||
|
<FormContext.Provider value={form}>
|
||||||
|
<FieldContext.Provider value={f}>
|
||||||
|
<Drawer
|
||||||
|
placement={'right'}
|
||||||
|
destroyOnClose
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => setVisible(false)}
|
||||||
|
footer={
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
await form.submit();
|
||||||
|
setVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
提交
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
basePath={f.address}
|
||||||
|
schema={fieldSchema}
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'RowSelection';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</FormContext.Provider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RowContext = createContext<any>({});
|
||||||
|
|
||||||
|
const ReadPrettyRecordPicker: React.FC = (props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const field = useField<Field>();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{toArr(field.value).map((record, index) => {
|
||||||
|
return (
|
||||||
|
<RowContext.Provider key={index} value={{ record, field, props }}>
|
||||||
|
<RecursionField
|
||||||
|
schema={fieldSchema}
|
||||||
|
onlyRenderProperties
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'RecordPicker.SelectedItem';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</RowContext.Provider>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapSuffixProps = (props, field) => {
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
suffix: <span>{field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffix}</span>,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordPicker: any = connect(
|
||||||
|
InputRecordPicker,
|
||||||
|
mapProps(mapSuffixProps),
|
||||||
|
mapReadPretty(ReadPrettyRecordPicker),
|
||||||
|
);
|
||||||
|
|
||||||
|
RecordPicker.SelectedItem = () => {
|
||||||
|
const ctx = useContext(RowContext);
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<VisibleContext.Provider value={[visible, setVisible]}>
|
||||||
|
<Tag style={{ cursor: 'pointer' }} onClick={() => setVisible(true)}>
|
||||||
|
{ctx.record?.name}
|
||||||
|
</Tag>
|
||||||
|
<RecursionField onlyRenderProperties schema={fieldSchema}></RecursionField>
|
||||||
|
</VisibleContext.Provider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* title: 勾选
|
||||||
|
*/
|
||||||
|
import { FormItem } from '@formily/antd';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { Action, Input, RecordPicker, RowSelection, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'array',
|
||||||
|
title: `编辑模式`,
|
||||||
|
default: [
|
||||||
|
{ id: 1, name: 'name1' },
|
||||||
|
{ id: 2, name: 'name2' },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'RecordPicker',
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'read',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
read: {
|
||||||
|
type: 'array',
|
||||||
|
title: `阅读模式`,
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'RecordPicker',
|
||||||
|
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 }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentProvider components={{ Input, RecordPicker, RowSelection, FormItem, Action }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,4 +5,78 @@ group:
|
|||||||
path: /schema-components
|
path: /schema-components
|
||||||
---
|
---
|
||||||
|
|
||||||
# RecordPicker <Badge>待定</Badge>
|
# RecordPicker - 记录选择器 <Badge>待定</Badge>
|
||||||
|
|
||||||
|
## JSON Schema
|
||||||
|
|
||||||
|
通过弹窗选择可选项,可选项用表格展示,在特定的 `RecordPicker.RowSelection` 节点里配置,仅当 `x-read-pretty: false` 时有效。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
default: [
|
||||||
|
{ id: 1, name: 'tag1' },
|
||||||
|
{ id: 2, name: 'tag2' },
|
||||||
|
],
|
||||||
|
'x-component': 'RecordPicker',
|
||||||
|
properties: {
|
||||||
|
rowSelection: {
|
||||||
|
'x-component': 'RecordPicker.RowSelection',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`x-read-pretty: true` 时,可以在 `RecordPicker.SelectedItem` 里配置选中项的 schema。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-component': 'RecordPicker',
|
||||||
|
properties: {
|
||||||
|
item: {
|
||||||
|
'x-component': 'RecordPicker.SelectedItem',
|
||||||
|
'x-component-props': {
|
||||||
|
// label、value 与字段的映射关系
|
||||||
|
fieldNames: {
|
||||||
|
value: 'id',
|
||||||
|
label: 'name'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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 }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<code src="./demos/demo1.tsx"/>
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './RecordPicker';
|
@ -0,0 +1,31 @@
|
|||||||
|
import { Field } from '@formily/core';
|
||||||
|
import { observer, useField } from '@formily/react';
|
||||||
|
import { isArr, isValid } from '@formily/shared';
|
||||||
|
import { TableProps } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { VoidTable } from '../void-table';
|
||||||
|
|
||||||
|
type Props = TableProps<any> & { value?: any; onChange?: any; objectValue?: boolean; };
|
||||||
|
|
||||||
|
const toArr = (value: any) => (isArr(value) ? value : isValid(value) ? [value] : []);
|
||||||
|
|
||||||
|
export const RowSelection = observer((props: Props) => {
|
||||||
|
const { rowKey = 'id', objectValue } = props;
|
||||||
|
const field = useField<Field>();
|
||||||
|
console.log('field.value', field.value)
|
||||||
|
const rowSelection: any = {
|
||||||
|
type: 'checkbox',
|
||||||
|
...props.rowSelection,
|
||||||
|
selectedRowKeys: toArr(field.value).map(val => typeof val === 'object' ? val[rowKey as any] : val),
|
||||||
|
onChange(selectedRowKeys: any[], selectedRows?: any) {
|
||||||
|
if (rowSelection.type === 'checkbox') {
|
||||||
|
props.onChange(objectValue ? selectedRows : selectedRowKeys);
|
||||||
|
} else {
|
||||||
|
props.onChange([...(objectValue ? selectedRows : selectedRowKeys)].shift());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return <VoidTable {...props} rowSelection={rowSelection} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
VoidTable.mixin(RowSelection);
|
@ -0,0 +1,35 @@
|
|||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { APIClient } from '@nocobase/client';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export const apiClient = new APIClient();
|
||||||
|
|
||||||
|
const mock = new MockAdapter(apiClient.axios);
|
||||||
|
|
||||||
|
const sleep = (value: number) => new Promise((resolve) => setTimeout(resolve, value));
|
||||||
|
|
||||||
|
mock.onGet('/posts:list').reply(async (config) => {
|
||||||
|
// const [{ pageSize }] = config.params;
|
||||||
|
const pageSize = config.params.pageSize || 10;
|
||||||
|
const page = config.params.page || 1;
|
||||||
|
console.log(pageSize, page, config.params);
|
||||||
|
await sleep(1000);
|
||||||
|
return [
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
data: _.range(pageSize).map((v) => {
|
||||||
|
return {
|
||||||
|
id: v + (page - 1) * pageSize,
|
||||||
|
name: uid(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
meta: {
|
||||||
|
count: 100,
|
||||||
|
pageSize,
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* title: 勾选
|
||||||
|
*/
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import {
|
||||||
|
APIClientProvider,
|
||||||
|
Input,
|
||||||
|
RowSelection,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
useAPIClient
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { apiClient } from './apiClient';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
hello: {
|
||||||
|
'x-component': 'Hello',
|
||||||
|
},
|
||||||
|
table1: {
|
||||||
|
type: 'string',
|
||||||
|
default: 1,
|
||||||
|
'x-uid': 'input',
|
||||||
|
'x-component': 'RowSelection',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
// current: 2,
|
||||||
|
pageSize: 2,
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
resource: 'posts',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
filter: {},
|
||||||
|
// pageSize: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'RowSelection.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Hello = () => {
|
||||||
|
const api = useAPIClient();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
const service = api.service('input');
|
||||||
|
if (!service) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
service.run({ ...service.params[0], page: 3 });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hello
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<APIClientProvider apiClient={apiClient}>
|
||||||
|
<SchemaComponentProvider components={{ Hello, Input, RowSelection }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
</APIClientProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,4 +5,86 @@ group:
|
|||||||
path: /schema-components
|
path: /schema-components
|
||||||
---
|
---
|
||||||
|
|
||||||
# RowSelection <Badge>待定</Badge>
|
# RowSelection - 行选择器 <Badge>待定</Badge>
|
||||||
|
|
||||||
|
用表格视图展示可选项数据,功能上与 Radio.Group 和 CheckBox.Group 一致。
|
||||||
|
|
||||||
|
## JSON Schema
|
||||||
|
|
||||||
|
[rowSelection](https://ant.design/components/table/#rowSelection)
|
||||||
|
|
||||||
|
单选
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'RowSelection',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
},
|
||||||
|
dataSource: [
|
||||||
|
{ id: 1, name: 'Name1' },
|
||||||
|
{ id: 2, name: 'Name2' },
|
||||||
|
{ id: 3, name: 'Name3' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
default: 1,
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'Name',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
多选
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'RowSelection',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
},
|
||||||
|
dataSource: [
|
||||||
|
{ id: 1, name: 'Name1' },
|
||||||
|
{ id: 2, name: 'Name2' },
|
||||||
|
{ id: 3, name: 'Name3' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
default: 1,
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'Name',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<code src="./demos/demo1.tsx">
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './RowSelection';
|
@ -0,0 +1,109 @@
|
|||||||
|
import { createForm, Field } from '@formily/core';
|
||||||
|
import { FieldContext, FormContext, observer, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { Options, Result } from 'ahooks/lib/useRequest/src/types';
|
||||||
|
import { TablePaginationConfig, TableProps } from 'antd';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { AsyncDataProvider, useRequest } from '../../../';
|
||||||
|
import { useAttach } from '../../hooks';
|
||||||
|
import { ArrayTable } from '../array-table';
|
||||||
|
|
||||||
|
type VoidTableProps = TableProps<any> & {
|
||||||
|
request?: any;
|
||||||
|
useDataSource?: (data?: any, options?: Options<any, any> & { uid?: string }) => Result<any, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type VoidTableType = React.FC<VoidTableProps> & {
|
||||||
|
Column?: React.FC<any>;
|
||||||
|
mixin?: (T: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const usePaginationProps = (props: TableProps<any> & { request?: any }, service): TablePaginationConfig | false => {
|
||||||
|
if (props.pagination === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const pagination: TablePaginationConfig = props.pagination || {};
|
||||||
|
if (props?.request?.params?.pageSize) {
|
||||||
|
pagination.defaultPageSize = props?.request?.params?.pageSize;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
showSizeChanger: true,
|
||||||
|
...pagination,
|
||||||
|
onChange(page, pageSize) {
|
||||||
|
service?.run({ ...service?.params?.[0], page, pageSize });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const useRequestProps = (props) => {
|
||||||
|
const { request, pagination, dataSource } = props;
|
||||||
|
if (request) {
|
||||||
|
if (pagination === false) {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
const params = cloneDeep(request.params || {});
|
||||||
|
if (!params.page) {
|
||||||
|
params.page = pagination?.current || pagination?.defaultCurrent || 1;
|
||||||
|
}
|
||||||
|
if (!params.pageSize) {
|
||||||
|
params.pageSize = pagination?.pageSize || pagination?.defaultPageSize || 10;
|
||||||
|
}
|
||||||
|
request.params = params;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
return (params: any = {}) => {
|
||||||
|
const { page = 1, pageSize = 10 } = params;
|
||||||
|
const startIndex = (page - 1) * pageSize;
|
||||||
|
const endIndex = startIndex + pageSize - 1;
|
||||||
|
return Promise.resolve({
|
||||||
|
data: pagination === false ? dataSource : dataSource?.slice(startIndex, endIndex + 1),
|
||||||
|
meta: {
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
count: dataSource?.length || 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDefDataSource = (props, options) => {
|
||||||
|
return useRequest(useRequestProps(props), options);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VoidTable: VoidTableType = observer((props) => {
|
||||||
|
const { useDataSource = useDefDataSource } = props;
|
||||||
|
const field = useField<Field>();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const form = useMemo(() => createForm(), []);
|
||||||
|
const f = useAttach(form.createArrayField({ name: fieldSchema.name }));
|
||||||
|
const result = useDataSource(props, {
|
||||||
|
uid: fieldSchema['x-uid'],
|
||||||
|
onSuccess(data) {
|
||||||
|
form.setValues({
|
||||||
|
[fieldSchema.name]: data?.data,
|
||||||
|
});
|
||||||
|
if (field?.componentProps?.pagination === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
field.componentProps.pagination = field.componentProps.pagination || {};
|
||||||
|
if (data?.meta?.count) {
|
||||||
|
field.componentProps.pagination.total = data?.meta?.count;
|
||||||
|
}
|
||||||
|
field.componentProps.pagination.current = data?.meta?.page || 1;
|
||||||
|
field.componentProps.pagination.pageSize = data?.meta?.pageSize || 10;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<AsyncDataProvider value={result}>
|
||||||
|
<FormContext.Provider value={form}>
|
||||||
|
<FieldContext.Provider value={f}>
|
||||||
|
<ArrayTable {...props} loading={result?.loading} pagination={usePaginationProps(props, result)} />
|
||||||
|
</FieldContext.Provider>
|
||||||
|
</FormContext.Provider>
|
||||||
|
</AsyncDataProvider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
VoidTable.mixin = ArrayTable.mixin;
|
||||||
|
|
||||||
|
ArrayTable.mixin(VoidTable);
|
@ -0,0 +1,35 @@
|
|||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { APIClient } from '@nocobase/client';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export const apiClient = new APIClient();
|
||||||
|
|
||||||
|
const mock = new MockAdapter(apiClient.axios);
|
||||||
|
|
||||||
|
const sleep = (value: number) => new Promise((resolve) => setTimeout(resolve, value));
|
||||||
|
|
||||||
|
mock.onGet('/posts:list').reply(async (config) => {
|
||||||
|
// const [{ pageSize }] = config.params;
|
||||||
|
const pageSize = config.params.pageSize || 10;
|
||||||
|
const page = config.params.page || 1;
|
||||||
|
console.log(pageSize, page, config.params);
|
||||||
|
await sleep(1000);
|
||||||
|
return [
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
data: _.range(pageSize).map((v) => {
|
||||||
|
return {
|
||||||
|
id: v + (page - 1) * pageSize,
|
||||||
|
name: uid(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
meta: {
|
||||||
|
count: 100,
|
||||||
|
pageSize,
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* title: 勾选
|
||||||
|
*/
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import {
|
||||||
|
APIClientProvider,
|
||||||
|
Input,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
useAPIClient,
|
||||||
|
VoidTable
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import React from 'react';
|
||||||
|
import { apiClient } from './apiClient';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
hello: {
|
||||||
|
'x-component': 'Hello',
|
||||||
|
},
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-uid': 'input',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
current: 2,
|
||||||
|
pageSize: 2,
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
resource: 'posts',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
filter: {},
|
||||||
|
// pageSize: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Hello = () => {
|
||||||
|
const api = useAPIClient();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
const service = api.service('input');
|
||||||
|
if (!service) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
service.run({ ...service.params[0], page: 3 });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hello
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<APIClientProvider apiClient={apiClient}>
|
||||||
|
<SchemaComponentProvider components={{ Hello, Input, VoidTable }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
</APIClientProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,12 +5,231 @@ group:
|
|||||||
path: /schema-components
|
path: /schema-components
|
||||||
---
|
---
|
||||||
|
|
||||||
# VoidTable <Badge>待定</Badge>
|
# VoidTable - 表格(数据展示) <Badge>待定</Badge>
|
||||||
|
|
||||||
- VoidTable
|
VoidTable 只用作数据展示,如果需要可以录入数据的表格字段,请使用 [ArrayTable](array-table)。
|
||||||
- VoidTable.Column
|
|
||||||
- VoidTable.SortHandle
|
## Examples
|
||||||
- TaVoidTableble.Index
|
|
||||||
- VoidTable.Pagination
|
VoidTable 的 props 与 antd 的 [Table](https://ant.design/components/table/#API) 一致。
|
||||||
- VoidTable.ActionBar
|
|
||||||
- VoidTable.Filter
|
### 基础使用
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import {
|
||||||
|
APIClientProvider,
|
||||||
|
Input,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
useAPIClient,
|
||||||
|
VoidTable
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
dataSource: _.range(5).map((v) => {
|
||||||
|
return {
|
||||||
|
id: v,
|
||||||
|
name: uid(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentProvider components={{ Input, VoidTable }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 分页
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import {
|
||||||
|
APIClientProvider,
|
||||||
|
Input,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
useAPIClient,
|
||||||
|
VoidTable
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
dataSource: _.range(50).map((v) => {
|
||||||
|
return {
|
||||||
|
id: v,
|
||||||
|
name: uid(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentProvider components={{ Input, VoidTable }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 不分页
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import {
|
||||||
|
APIClientProvider,
|
||||||
|
Input,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
useAPIClient,
|
||||||
|
VoidTable
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-uid': 'input',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
pagination: false,
|
||||||
|
dataSource: _.range(12).map((v) => {
|
||||||
|
return {
|
||||||
|
id: v,
|
||||||
|
name: uid(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Name',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentProvider components={{ Input, VoidTable }}>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 异步数据
|
||||||
|
|
||||||
|
<code src="./demos/demo1.tsx">
|
||||||
|
|
||||||
|
为了更好的支持 columns 的渲染,添加了 VoidTable.Column 用于配置表格列,VoidTable.Column 写在 properties 里,属性与 antd 的 [Table.Column](https://ant.design/components/table/#Column) 一致。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
dataSource: [
|
||||||
|
{ id: 1, name: 'Name1' },
|
||||||
|
{ id: 2, name: 'Name2' },
|
||||||
|
{ id: 3, name: 'Name3' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'Name',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './VoidTable';
|
Loading…
Reference in New Issue
Block a user