feat: improve sub table
This commit is contained in:
parent
f5b2600640
commit
6d0978f2c2
@ -1,8 +1,8 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { I18nextProvider, useTranslation } from 'react-i18next';
|
||||
import { ConfigProvider, Spin } from 'antd';
|
||||
import enUS from 'antd/lib/locale/en_US';
|
||||
import zhCN from 'antd/lib/locale/zh_CN';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useRequest } from '../api-client';
|
||||
|
||||
export function AntdConfigProvider(props) {
|
||||
@ -19,7 +19,7 @@ export function AntdConfigProvider(props) {
|
||||
i18n.changeLanguage(data?.data?.lang);
|
||||
}
|
||||
},
|
||||
manual: !remoteLocale,
|
||||
manual: true, // !remoteLocale,
|
||||
},
|
||||
);
|
||||
if (loading) {
|
||||
|
@ -2,7 +2,7 @@ import { Result } from 'ahooks/lib/useRequest/src/types';
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import { useRequest } from '../api-client';
|
||||
|
||||
export const AsyncDataContext = createContext<Result<any, any>>(null);
|
||||
export const AsyncDataContext = createContext<Result<any, any> & { state?: any; setState?: any }>(null);
|
||||
|
||||
export interface AsyncDataProviderProps {
|
||||
value?: any;
|
||||
|
@ -0,0 +1,138 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { ArrayTable } from '@formily/antd';
|
||||
import { ISchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Button, Dropdown, Menu } from 'antd';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import React, { useState } from 'react';
|
||||
import { useRequest } from '../../api-client';
|
||||
import { ActionContext, SchemaComponent, useActionContext, useCompile, useFormBlockContext } from '../../schema-component';
|
||||
import { useCollectionManager } from '../hooks';
|
||||
import { IField } from '../interfaces/types';
|
||||
import { options } from './interfaces';
|
||||
|
||||
const getSchema = (schema: IField): ISchema => {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
const properties = cloneDeep(schema.properties) as any;
|
||||
const initialValue = {
|
||||
...cloneDeep(schema.default),
|
||||
interface: schema.name,
|
||||
name: `f_${uid()}`,
|
||||
};
|
||||
initialValue.uiSchema.title = schema.title;
|
||||
console.log('initialValue', initialValue);
|
||||
return {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
return useRequest(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
data: initialValue,
|
||||
}),
|
||||
options,
|
||||
);
|
||||
},
|
||||
},
|
||||
title: '{{ t("Add field") }}',
|
||||
properties: {
|
||||
// @ts-ignore
|
||||
...properties,
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '{{ t("Cancel") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ cm.useCancelAction }}',
|
||||
},
|
||||
},
|
||||
action2: {
|
||||
title: '{{ t("Submit") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: '{{ useCreateSubField }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const useCreateSubField = () => {
|
||||
// const form = useForm();
|
||||
const { form, parent } = useFormBlockContext();
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
await form.submit();
|
||||
const children = parent.form.values?.children?.slice?.();
|
||||
children.push(cloneDeep(form.values));
|
||||
console.log('form.values', form.values, children);
|
||||
parent.form.setValuesIn('children', children);
|
||||
ctx.setVisible(false);
|
||||
// const options = form?.values?.uiSchema?.enum?.slice() || [];
|
||||
// form.setValuesIn(
|
||||
// 'uiSchema.enum',
|
||||
// options.map((option) => {
|
||||
// return {
|
||||
// value: uid(),
|
||||
// ...option,
|
||||
// };
|
||||
// }),
|
||||
// );
|
||||
// await run();
|
||||
// await refreshCM();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const AddSubFieldAction = () => {
|
||||
const { getInterface } = useCollectionManager();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [schema, setSchema] = useState({});
|
||||
const compile = useCompile();
|
||||
return (
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu
|
||||
onClick={(info) => {
|
||||
const schema = getSchema(getInterface(info.key));
|
||||
setSchema(schema);
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
{options.map((option) => {
|
||||
return (
|
||||
<Menu.SubMenu title={compile(option.label)}>
|
||||
{option.children.map((child) => {
|
||||
return <Menu.Item key={child.name}>{compile(child.title)}</Menu.Item>;
|
||||
})}
|
||||
</Menu.SubMenu>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Button icon={<PlusOutlined />} type={'primary'}>
|
||||
添加字段
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useCreateSubField }} />
|
||||
</ActionContext.Provider>
|
||||
);
|
||||
};
|
@ -1,9 +1,13 @@
|
||||
import { useForm } from '@formily/react';
|
||||
import { action } from '@formily/reactive';
|
||||
import { uid } from '@formily/shared';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRequest } from '../../api-client';
|
||||
import { useRecord } from '../../record-provider';
|
||||
import { SchemaComponent, useActionContext } from '../../schema-component';
|
||||
import { useCollectionManager } from '../hooks/useCollectionManager';
|
||||
import { AddSubFieldAction } from './AddSubFieldAction';
|
||||
import { EditSubFieldAction } from './EditSubFieldAction';
|
||||
import { collectionSchema } from './schemas/collections';
|
||||
|
||||
const useAsyncDataSource = (service: any) => (field: any) => {
|
||||
@ -42,6 +46,33 @@ const useCollectionValues = (options) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const useSelectedRowKeys = () => {
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||
return [selectedRowKeys, setSelectedRowKeys];
|
||||
};
|
||||
|
||||
const useDestroySubField = () => {
|
||||
const record = useRecord();
|
||||
const form = useForm();
|
||||
return {
|
||||
async run() {
|
||||
const children = form.values?.children?.slice?.();
|
||||
form.setValuesIn(
|
||||
'children',
|
||||
children.filter((child) => {
|
||||
return child.name !== record.name;
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const useBulkDestroySubField = () => {
|
||||
return {
|
||||
async run() {},
|
||||
};
|
||||
};
|
||||
|
||||
export const ConfigurationTable = () => {
|
||||
const { collections = [] } = useCollectionManager();
|
||||
const loadCollections = async (field: any) => {
|
||||
@ -52,7 +83,21 @@ export const ConfigurationTable = () => {
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SchemaComponent schema={collectionSchema} scope={{ useCollectionValues, useAsyncDataSource, loadCollections }} />
|
||||
<SchemaComponent
|
||||
schema={collectionSchema}
|
||||
components={{
|
||||
AddSubFieldAction,
|
||||
EditSubFieldAction,
|
||||
}}
|
||||
scope={{
|
||||
useDestroySubField,
|
||||
useBulkDestroySubField,
|
||||
useSelectedRowKeys,
|
||||
useCollectionValues,
|
||||
useAsyncDataSource,
|
||||
loadCollections,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -102,7 +102,7 @@ export const EditFieldAction = (props) => {
|
||||
onClick={async () => {
|
||||
const { data } = await api.resource('collections.fields', record.collectionName).get({
|
||||
filterByTk: record.name,
|
||||
appends: ['uiSchema'],
|
||||
appends: record.interface === 'subTable' ? ['uiSchema', 'children'] : ['uiSchema'],
|
||||
});
|
||||
const schema = getSchema({
|
||||
...getInterface(record.interface),
|
||||
|
@ -0,0 +1,119 @@
|
||||
import { ArrayTable } from '@formily/antd';
|
||||
import { ISchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAPIClient, useRequest } from '../../api-client';
|
||||
import { useRecord } from '../../record-provider';
|
||||
import { ActionContext, SchemaComponent, useActionContext, useFormBlockContext } from '../../schema-component';
|
||||
import { useCollectionManager } from '../hooks';
|
||||
import { IField } from '../interfaces/types';
|
||||
|
||||
const getSchema = (schema: IField): ISchema => {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
const properties = cloneDeep(schema.properties) as any;
|
||||
properties.name['x-disabled'] = true;
|
||||
return {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
return useRequest(
|
||||
() =>
|
||||
Promise.resolve({
|
||||
data: cloneDeep(schema.default),
|
||||
}),
|
||||
options,
|
||||
);
|
||||
},
|
||||
},
|
||||
title: '{{ t("Edit field") }}',
|
||||
properties: {
|
||||
// @ts-ignore
|
||||
...properties,
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '{{ t("Cancel") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ cm.useCancelAction }}',
|
||||
},
|
||||
},
|
||||
action2: {
|
||||
title: '{{ t("Submit") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: '{{ useUpdateSubField }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const useUpdateSubField = () => {
|
||||
const { form, parent } = useFormBlockContext();
|
||||
const ctx = useActionContext();
|
||||
return {
|
||||
async run() {
|
||||
await form.submit();
|
||||
const children = parent.form.values?.children?.slice?.();
|
||||
parent.form.setValuesIn(
|
||||
'children',
|
||||
children.map((child) => {
|
||||
if (child.name === form.values.name) {
|
||||
return cloneDeep(form.values);
|
||||
}
|
||||
return child;
|
||||
}),
|
||||
);
|
||||
ctx.setVisible(false);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const EditSubFieldAction = (props) => {
|
||||
const record = useRecord();
|
||||
const { getInterface } = useCollectionManager();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [schema, setSchema] = useState({});
|
||||
const api = useAPIClient();
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<a
|
||||
onClick={async () => {
|
||||
// const { data } = await api.resource('fields.children', record.key).get({
|
||||
// filterByTk: record.name,
|
||||
// appends: ['uiSchema'],
|
||||
// });
|
||||
const schema = getSchema({
|
||||
...getInterface(record.interface),
|
||||
default: {
|
||||
...record,
|
||||
},
|
||||
});
|
||||
setSchema(schema);
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
{t('Edit')}
|
||||
</a>
|
||||
<SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useUpdateSubField }} />
|
||||
</ActionContext.Provider>
|
||||
);
|
||||
};
|
@ -31,6 +31,132 @@ export const subTable: IField = {
|
||||
},
|
||||
properties: {
|
||||
...defaultProps,
|
||||
subtable: {
|
||||
type: 'void',
|
||||
'x-component': 'div',
|
||||
properties: {
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': 'ActionBar',
|
||||
'x-component-props': {
|
||||
style: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
delete: {
|
||||
type: 'void',
|
||||
title: '{{ t("Delete") }}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useBulkDestroySubField }}',
|
||||
confirm: {
|
||||
title: "{{t('Delete record')}}",
|
||||
content: "{{t('Are you sure you want to delete it?')}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
create: {
|
||||
type: 'void',
|
||||
title: '{{ t("Add new") }}',
|
||||
'x-component': 'AddSubFieldAction',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
children: {
|
||||
type: 'array',
|
||||
title: '{{t("Fields")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Table.Array',
|
||||
'x-component-props': {
|
||||
pagination: false,
|
||||
rowKey: 'name',
|
||||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
useSelectedRowKeys: '{{ useSelectedRowKeys }}',
|
||||
// scroll: { x: '100%' },
|
||||
},
|
||||
properties: {
|
||||
column1: {
|
||||
type: 'void',
|
||||
title: '{{ t("Field display name") }}',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
'uiSchema.title': {
|
||||
type: 'number',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column2: {
|
||||
type: 'void',
|
||||
title: '{{ t("Field name") }}',
|
||||
'x-decorator': 'Table.Column.Decorator',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
name: {
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column3: {
|
||||
type: 'void',
|
||||
title: '{{ t("Field interface") }}',
|
||||
'x-decorator': 'Table.Column.Decorator',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
interface: {
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column4: {
|
||||
type: 'void',
|
||||
title: '{{ t("Actions") }}',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': 'Space',
|
||||
'x-component-props': {
|
||||
split: '|',
|
||||
},
|
||||
properties: {
|
||||
update: {
|
||||
type: 'void',
|
||||
title: '{{ t("Edit") }}',
|
||||
'x-component': 'EditSubFieldAction',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
type: 'void',
|
||||
title: '{{ t("Delete") }}',
|
||||
'x-component': 'Action.Link',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useDestroySubField }}',
|
||||
confirm: {
|
||||
title: "{{t('Delete record')}}",
|
||||
content: "{{t('Are you sure you want to delete it?')}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// children: {
|
||||
// type: 'array',
|
||||
// title: '{{t("Sub-table fields")}}',
|
||||
|
@ -104,6 +104,7 @@
|
||||
"Edit": "编辑",
|
||||
"Edit collection": "编辑数据表",
|
||||
"Configure fields": "配置字段",
|
||||
"Configure columns": "配置字段",
|
||||
"Edit field": "编辑字段",
|
||||
"Configure fields of {{title}}": "「{{title}}」的字段配置",
|
||||
"Basic": "基本类型",
|
||||
|
@ -3,7 +3,7 @@ import { createForm } from '@formily/core';
|
||||
import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||
import { Options, Result } from 'ahooks/lib/useRequest/src/types';
|
||||
import { Spin } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { createContext, useContext, useMemo } from 'react';
|
||||
import { useAttach, useComponent } from '../..';
|
||||
import { useRequest } from '../../../api-client';
|
||||
import { useCollection } from '../../../collection-manager';
|
||||
@ -75,9 +75,17 @@ const useDef = (opts: any = {}, props: FormProps = {}) => {
|
||||
return useRequest(useRequestProps(props), opts);
|
||||
};
|
||||
|
||||
const FormBlockContext = createContext<any>(null);
|
||||
|
||||
export const useFormBlockContext = () => {
|
||||
const ctx = useContext(FormBlockContext);
|
||||
return ctx;
|
||||
};
|
||||
|
||||
export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) => {
|
||||
const { request, effects, initialValue, useValues = useDef, ...others } = props;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const form = useMemo(() => createForm({ effects }), []);
|
||||
const result = useValues(
|
||||
{
|
||||
@ -89,14 +97,17 @@ export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) =
|
||||
},
|
||||
props,
|
||||
);
|
||||
const parent = useContext(FormBlockContext);
|
||||
return (
|
||||
<Spin spinning={result?.loading || false}>
|
||||
{fieldSchema['x-decorator'] === 'Form' ? (
|
||||
<FormDecorator form={form} {...others} />
|
||||
) : (
|
||||
<FormComponent form={form} {...others} />
|
||||
)}
|
||||
</Spin>
|
||||
<FormBlockContext.Provider value={{ parent, form, result, field, fieldSchema }}>
|
||||
<Spin spinning={result?.loading || false}>
|
||||
{fieldSchema['x-decorator'] === 'Form' ? (
|
||||
<FormDecorator form={form} {...others} />
|
||||
) : (
|
||||
<FormComponent form={form} {...others} />
|
||||
)}
|
||||
</Spin>
|
||||
</FormBlockContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { ArrayField } from '@formily/core';
|
||||
import { ArrayField, Field } from '@formily/core';
|
||||
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||
import { Table, TableColumnProps } from 'antd';
|
||||
import cls from 'classnames';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { DndContext } from '../..';
|
||||
import { RecordProvider, useSchemaInitializer } from '../../../';
|
||||
import { RecordProvider, useRequest, useSchemaInitializer } from '../../../';
|
||||
|
||||
const isColumnComponent = (schema: Schema) => {
|
||||
return schema['x-component']?.endsWith('.Column') > -1;
|
||||
@ -83,13 +83,45 @@ export const components = {
|
||||
},
|
||||
};
|
||||
|
||||
const useDef = () => {
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||
return [selectedRowKeys, setSelectedRowKeys];
|
||||
};
|
||||
|
||||
const useDefDataSource = (options, props) => {
|
||||
const field = useField<Field>();
|
||||
return useRequest(() => {
|
||||
return Promise.resolve({
|
||||
data: field.value,
|
||||
});
|
||||
}, options);
|
||||
};
|
||||
|
||||
export const TableArray: React.FC<any> = observer((props) => {
|
||||
const field = useField<ArrayField>();
|
||||
const columns = useTableColumns();
|
||||
const { onChange, ...others } = props;
|
||||
const { useSelectedRowKeys = useDef, useDataSource = useDefDataSource, onChange, ...others } = props;
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useSelectedRowKeys();
|
||||
useDataSource({
|
||||
onSuccess(data) {
|
||||
field.value = data?.data || [];
|
||||
},
|
||||
});
|
||||
const restProps = {
|
||||
rowSelection: props.rowSelection
|
||||
? {
|
||||
type: 'checkbox',
|
||||
selectedRowKeys,
|
||||
onChange(selectedRowKeys: any[]) {
|
||||
setSelectedRowKeys(selectedRowKeys);
|
||||
},
|
||||
...props.rowSelection,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<Table {...others} components={components} columns={columns} dataSource={field.value?.slice()} />
|
||||
<Table {...others} {...restProps} components={components} columns={columns} dataSource={field.value?.slice()} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import React, { useLayoutEffect } from 'react';
|
||||
import { designerCss, SortableItem, useCollection, useDesignable, useDesigner } from '../../../';
|
||||
import { SortableItem, useCollection, useCompile, useDesignable, useDesigner } from '../../../';
|
||||
import { designerCss } from './Table.Column.ActionBar';
|
||||
|
||||
export const useColumnSchema = () => {
|
||||
const { getField } = useCollection();
|
||||
const compile = useCompile();
|
||||
const columnSchema = useFieldSchema();
|
||||
const fieldSchema = columnSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'CollectionField') {
|
||||
@ -15,14 +17,15 @@ export const useColumnSchema = () => {
|
||||
return {};
|
||||
}
|
||||
const collectionField = getField(fieldSchema.name);
|
||||
return { columnSchema, fieldSchema, collectionField };
|
||||
return { columnSchema, fieldSchema, uiSchema: compile(collectionField?.uiSchema) };
|
||||
};
|
||||
|
||||
export const TableColumnDecorator = (props) => {
|
||||
const Designer = useDesigner();
|
||||
const field = useField();
|
||||
const { fieldSchema, collectionField } = useColumnSchema();
|
||||
const { fieldSchema, uiSchema } = useColumnSchema();
|
||||
const { refresh } = useDesignable();
|
||||
const compile = useCompile();
|
||||
useLayoutEffect(() => {
|
||||
if (field.title) {
|
||||
return;
|
||||
@ -30,16 +33,16 @@ export const TableColumnDecorator = (props) => {
|
||||
if (!fieldSchema) {
|
||||
return;
|
||||
}
|
||||
if (collectionField?.uiSchema?.title) {
|
||||
field.title = collectionField?.uiSchema?.title;
|
||||
if (uiSchema?.title) {
|
||||
field.title = uiSchema?.title;
|
||||
}
|
||||
}, [collectionField?.uiSchema?.title]);
|
||||
console.log('field.title', collectionField?.uiSchema?.title, field.title);
|
||||
}, [uiSchema?.title]);
|
||||
console.log('field.title', uiSchema?.title, field.title);
|
||||
return (
|
||||
<SortableItem className={designerCss}>
|
||||
<Designer />
|
||||
{/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
|
||||
{field.title || collectionField?.uiSchema?.title}
|
||||
{field.title || compile(uiSchema?.title)}
|
||||
{/* <div
|
||||
onClick={() => {
|
||||
field.title = uid();
|
||||
|
@ -4,12 +4,13 @@ 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 { AsyncDataProvider, useAsyncData, useRequest } from '../../../';
|
||||
import { useAttach } from '../../hooks';
|
||||
import { TableArray } from './Table.Array';
|
||||
|
||||
type TableVoidProps = TableProps<any> & {
|
||||
request?: any;
|
||||
useSelectedRowKeys?: any;
|
||||
useDataSource?: (
|
||||
options?: Options<any, any> & { uid?: string },
|
||||
props?: any,
|
||||
@ -69,8 +70,13 @@ const useDef = (options, props) => {
|
||||
return useRequest(useRequestProps(props), options);
|
||||
};
|
||||
|
||||
const useDefSelectedRowKeys = () => {
|
||||
const result = useAsyncData();
|
||||
return [result?.state?.selectedRowKeys, (selectedRowKeys) => result?.setState?.({ selectedRowKeys })];
|
||||
};
|
||||
|
||||
export const TableVoid: React.FC<TableVoidProps> = observer((props) => {
|
||||
const { useDataSource = useDef } = props;
|
||||
const { useDataSource = useDef, useSelectedRowKeys = useDefSelectedRowKeys } = props;
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const form = useMemo(() => createForm(), []);
|
||||
@ -96,23 +102,16 @@ export const TableVoid: React.FC<TableVoidProps> = observer((props) => {
|
||||
},
|
||||
props,
|
||||
);
|
||||
const others = {
|
||||
rowSelection: props.rowSelection
|
||||
? {
|
||||
type: 'checkbox',
|
||||
...props.rowSelection,
|
||||
selectedRowKeys: result?.state?.selectedRowKeys || [],
|
||||
onChange(selectedRowKeys: any[]) {
|
||||
result?.setState?.({ selectedRowKeys });
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
return (
|
||||
<AsyncDataProvider value={result}>
|
||||
<FormContext.Provider value={form}>
|
||||
<FieldContext.Provider value={f}>
|
||||
<TableArray {...props} {...others} loading={result?.loading} pagination={usePaginationProps(props, result)} />
|
||||
<TableArray
|
||||
{...props}
|
||||
useSelectedRowKeys={useSelectedRowKeys}
|
||||
loading={result?.loading}
|
||||
pagination={usePaginationProps(props, result)}
|
||||
/>
|
||||
</FieldContext.Provider>
|
||||
</FormContext.Provider>
|
||||
</AsyncDataProvider>
|
||||
|
181
packages/client/src/schema-component/antd/table/demos/demo4.tsx
Normal file
181
packages/client/src/schema-component/antd/table/demos/demo4.tsx
Normal file
@ -0,0 +1,181 @@
|
||||
import { ISchema, observer } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import {
|
||||
Action,
|
||||
Input,
|
||||
SchemaComponent,
|
||||
SchemaComponentProvider,
|
||||
Table,
|
||||
useRecord,
|
||||
useRequest
|
||||
} from '@nocobase/client';
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
|
||||
const DataSourceContext = createContext(null);
|
||||
|
||||
const schema: ISchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
context: {
|
||||
type: 'void',
|
||||
'x-component': 'Context',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '提交',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction() {
|
||||
const ctx = useContext(DataSourceContext);
|
||||
return {
|
||||
async run() {
|
||||
console.log(ctx.dataSource);
|
||||
const dataSource = ctx.dataSource || [];
|
||||
dataSource.push({
|
||||
id: uid(),
|
||||
name: uid(),
|
||||
});
|
||||
ctx.setDataSource([...dataSource]);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
action2: {
|
||||
title: '删除',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction() {
|
||||
const ctx = useContext(DataSourceContext);
|
||||
const { selectedRowKeys, setSelectedRowKeys } = ctx;
|
||||
return {
|
||||
async run() {
|
||||
const dataSource = ctx.dataSource || [];
|
||||
ctx.setDataSource(
|
||||
dataSource.filter((item) => {
|
||||
return !selectedRowKeys.includes(item.id);
|
||||
}),
|
||||
);
|
||||
setSelectedRowKeys([]);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
input: {
|
||||
type: 'array',
|
||||
title: `编辑模式`,
|
||||
'x-component': 'Table.Array',
|
||||
'x-component-props': {
|
||||
rowKey: 'id',
|
||||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
useSelectedRowKeys() {
|
||||
const ctx = useContext(DataSourceContext);
|
||||
return [ctx.selectedRowKeys, ctx.setSelectedRowKeys];
|
||||
},
|
||||
useDataSource(options) {
|
||||
const ctx = useContext(DataSourceContext);
|
||||
return useRequest(
|
||||
() => {
|
||||
console.log('ctx.dataSource', ctx.dataSource);
|
||||
return Promise.resolve({
|
||||
data: ctx.dataSource,
|
||||
});
|
||||
},
|
||||
{
|
||||
...options,
|
||||
refreshDeps: [JSON.stringify(ctx.dataSource)],
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
column1: {
|
||||
type: 'void',
|
||||
title: 'Name',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column2: {
|
||||
type: 'void',
|
||||
title: 'Actions',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
action: {
|
||||
title: '删除',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction() {
|
||||
const record = useRecord();
|
||||
const ctx = useContext(DataSourceContext);
|
||||
return {
|
||||
async run() {
|
||||
const dataSource = ctx.dataSource || [];
|
||||
ctx.setDataSource(
|
||||
dataSource.filter((item) => {
|
||||
return record.id !== item.id;
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Context = observer((props) => {
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
const service = useRequest(
|
||||
() => {
|
||||
return Promise.resolve({
|
||||
data: [
|
||||
{ id: 1, name: 'Name1' },
|
||||
{ id: 2, name: 'Name2' },
|
||||
{ id: 3, name: 'Name3' },
|
||||
],
|
||||
});
|
||||
},
|
||||
{
|
||||
onSuccess(data) {
|
||||
setDataSource(data.data);
|
||||
},
|
||||
},
|
||||
);
|
||||
console.log('dataSource1', dataSource);
|
||||
return (
|
||||
<DataSourceContext.Provider
|
||||
value={{
|
||||
service,
|
||||
dataSource,
|
||||
setDataSource,
|
||||
selectedRowKeys,
|
||||
setSelectedRowKeys,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</DataSourceContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<SchemaComponentProvider components={{ Action, Context, Table, Input }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
);
|
||||
};
|
@ -25,3 +25,5 @@ group:
|
||||
## Table.RowSelection
|
||||
|
||||
<code src="./demos/demo3.tsx" />
|
||||
|
||||
<code src="./demos/demo4.tsx" />
|
||||
|
@ -12,8 +12,8 @@ export const TableColumnInitializers = (props: any) => {
|
||||
wrap={(s) => {
|
||||
return {
|
||||
type: 'void',
|
||||
'x-decorator': 'TableColumnDecorator',
|
||||
'x-designer': 'TableColumnDeigner',
|
||||
'x-decorator': 'Table.Column.Decorator',
|
||||
'x-designer': 'Table.Column.Deigner',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
[s.name]: {
|
||||
|
Loading…
Reference in New Issue
Block a user