feat: improve code

This commit is contained in:
chenos 2021-08-29 00:25:28 +08:00
parent f8c3c6a19b
commit 0314faeae9
11 changed files with 791 additions and 442 deletions

View File

@ -162,6 +162,7 @@ export const SchemaField = createSchemaField({
loadData: loadChinaRegionData,
loadDataSource: loadChinaRegionDataSource,
},
Select,
},
components: {
Card,

View File

@ -0,0 +1,39 @@
import { useRequest } from 'ahooks';
import { Spin } from 'antd';
import React, { useMemo } from 'react';
import { MemoryRouter as Router } from 'react-router-dom';
import {
createRouteSwitch,
RouteRedirectProps,
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
} from '../';
import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request';
const request = extend({
prefix: process.env.API_URL,
timeout: 30000,
});
request.use(async (ctx, next) => {
const { headers } = ctx.req.options as any;
const token = localStorage.getItem('NOCOBASE_TOKEN');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
await next();
});
export const RequestProvider = (props) => {
return (
<UseRequestProvider
value={{
requestMethod: (service) => request(service),
}}
>
{props.children}
</UseRequestProvider>
);
};

View File

@ -124,16 +124,7 @@ function generateCardItemSchema(component) {
'x-designable-bar': 'Table.DesignableBar',
'x-decorator': 'CardItem',
'x-component': 'Table',
default: [
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
// { key: uid(), field1: uid(), field2: uid() },
],
default: [],
'x-component-props': {
rowKey: 'id',
dragSort: true,
@ -178,7 +169,7 @@ function generateCardItemSchema(component) {
icon: 'DeleteOutlined',
confirm: {
title: '删除数据',
content: '删除后无法恢复,确定要删除吗?'
content: '删除后无法恢复,确定要删除吗?',
},
useAction: '{{ Table.useTableDestroyAction }}',
},
@ -1407,6 +1398,110 @@ AddNew.FormItem = observer((props: any) => {
fieldName: field.name,
},
};
if (field.interface === 'linkTo') {
data.properties = {
options: {
type: 'void',
'x-decorator': 'Form',
'x-component': 'Select.Options.Drawer',
'x-component-props': {
useOkAction: '{{ Select.useOkAction }}',
},
title: '关联数据',
properties: {
table: {
type: 'array',
'x-designable-bar': 'Table.DesignableBar',
'x-decorator': 'BlockItem',
'x-decorator-props': {
draggable: false,
},
'x-component': 'Table',
default: [],
'x-component-props': {
rowKey: 'id',
defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}',
onSelect: '{{ Select.useSelect() }}',
collectionName: field.target,
// dragSort: true,
showIndex: true,
refreshRequestOnChange: true,
pagination: {
pageSize: 10,
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Table.ActionBar',
'x-designable-bar':
'Table.ActionBar.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '筛选',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'filter',
},
'x-align': 'left',
'x-component': 'Table.Filter',
'x-designable-bar':
'Table.Filter.DesignableBar',
'x-component-props': {
fieldNames: [],
},
},
},
},
},
},
},
},
option: {
type: 'void',
'x-component': 'Select.OptionTag',
properties: {
[uid()]: {
type: 'void',
title: '查看数据',
'x-component': 'Action.Drawer',
'x-component-props': {
bodyStyle: {
background: '#f0f2f5',
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Tabs',
'x-designable-bar': 'Tabs.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '详情',
'x-designable-bar':
'Tabs.TabPane.DesignableBar',
'x-component': 'Tabs.TabPane',
'x-component-props': {},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
'x-component-props': {
addNewComponent: 'AddNew.PaneItem',
},
},
},
},
},
},
},
},
},
},
};
}
if (isGridBlock(schema)) {
path.pop();
path.pop();

View File

@ -28,6 +28,7 @@ import cls from 'classnames';
import { Droppable, SortableItem } from '../../components/Sortable';
import { useDndContext } from '@dnd-kit/core';
import { getSchemaPath } from '../../components/schema-renderer';
import { BlockSchemaContext } from '../../context';
const DraggableBlock = (props) => {
const { className, children, ...others } = props;
@ -62,8 +63,13 @@ const Block = (props) => {
export const BlockItem: any = observer((props: any) => {
const { draggable = true } = props;
const ctx = useDndContext();
return React.createElement(
draggable && ctx.activators?.length > 0 ? DraggableBlock : Block,
props,
const { schema } = useDesignable();
return (
<BlockSchemaContext.Provider value={schema}>
{React.createElement(
draggable && ctx.activators?.length > 0 ? DraggableBlock : Block,
props,
)}
</BlockSchemaContext.Provider>
);
});

View File

@ -24,12 +24,10 @@ import { BlockSchemaContext } from '../../context';
export const CardItem: any = connect((props) => {
const { schema } = useDesignable();
return (
<BlockSchemaContext.Provider value={schema}>
<BlockItem className={'nb-card-item'}>
<Card bordered={false} {...props}>
{props.children}
</Card>
</BlockItem>
</BlockSchemaContext.Provider>
<BlockItem className={'nb-card-item'}>
<Card bordered={false} {...props}>
{props.children}
</Card>
</BlockItem>
);
});

View File

@ -11,7 +11,13 @@ import {
useForm,
RecursionField,
} from '@formily/react';
import { useSchemaPath, SchemaField, useDesignable, removeSchema, ISchema } from '../';
import {
useSchemaPath,
SchemaField,
useDesignable,
removeSchema,
ISchema,
} from '../';
import get from 'lodash/get';
import { Button, Dropdown, Menu, message, Space } from 'antd';
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
@ -38,6 +44,7 @@ import {
import { useResource as useGeneralResource } from '../../hooks/useResource';
import { Resource } from '../../resource';
import { BaseResult } from '@ahooksjs/use-request/lib/types';
import { CollectionFieldContext } from '../table';
export interface DescriptionsContextProps {
resource?: Resource;
@ -87,15 +94,11 @@ const FormMain = (props: any) => {
'x-decorator': 'Form.__Decorator',
},
},
}
};
const content = (
<FormProvider form={form}>
{schema['x-decorator'] === 'Form' ? (
<SchemaField
components={options.components}
scope={scope}
schema={s}
/>
<SchemaField components={options.components} scope={scope} schema={s} />
) : (
<FormLayout layout={'vertical'} {...others}>
<SchemaField
@ -180,25 +183,31 @@ Form.Field = observer((props: any) => {
const required = schema['required'] || collectionField?.uiSchema?.required;
const description =
schema['description'] || collectionField?.uiSchema?.description;
console.log('schema.properties', schema.properties)
return (
<RecursionField
name={randomName}
schema={
new Schema({
'x-path': path,
type: 'void',
properties: {
[collectionField.name]: {
...collectionField.uiSchema,
title,
required,
description,
'x-decorator': 'FormilyFormItem',
<CollectionFieldContext.Provider value={collectionField}>
<RecursionField
name={randomName}
schema={
new Schema({
'x-path': path,
type: 'void',
properties: {
[collectionField.name]: {
...collectionField.uiSchema,
title,
required,
description,
'x-decorator': 'FormilyFormItem',
properties: {
...schema.properties,
},
},
},
},
} as ISchema)
}
/>
} as ISchema)
}
/>
</CollectionFieldContext.Provider>
);
});

View File

@ -0,0 +1,206 @@
import React from 'react';
import { ISchema, SchemaRenderer } from '../../';
import { useSelect, useOptionTagValues } from '../';
import { uid } from '@formily/shared';
import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider';
import { CollectionsProvider } from '@nocobase/client/src/constate';
console.log({ useSelect });
const dataSource = [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
{
id: 3,
title: '标题3',
},
] as any[];
function useValues() {
return {
table: dataSource,
};
}
const schema: ISchema = {
type: 'object',
properties: {
input: {
interface: 'select',
type: 'string',
title: `编辑模式`,
enum: dataSource,
default: [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
],
'x-decorator': 'FormItem',
'x-component': 'Select.Drawer',
'x-component-props': {
placeholder: 'please enter',
mode: 'tags',
fieldNames: {
label: 'title',
value: 'id',
},
},
'x-reactions': {
target: 'read',
fulfill: {
state: {
value: '{{$self.value}}',
},
},
},
properties: {
options: {
type: 'void',
'x-decorator': 'Form',
'x-component': 'Select.Options.Drawer',
title: '关联数据',
properties: {
table: {
type: 'array',
'x-designable-bar': 'Table.DesignableBar',
'x-decorator': 'BlockItem',
'x-decorator-props': {
draggable: false,
},
'x-component': 'Table',
default: [],
'x-component-props': {
rowKey: 'id',
collectionName: 'users',
// dragSort: true,
showIndex: true,
refreshRequestOnChange: true,
pagination: {
pageSize: 10,
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Table.ActionBar',
'x-designable-bar': 'Table.ActionBar.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '筛选',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'filter',
},
'x-align': 'left',
'x-component': 'Table.Filter',
'x-designable-bar': 'Table.Filter.DesignableBar',
'x-component-props': {
fieldNames: [],
},
},
},
},
},
},
},
},
},
},
read: {
interface: 'select',
type: 'string',
title: `阅读模式`,
enum: dataSource,
default: [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
],
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Select.Drawer',
'x-component-props': {
placeholder: 'please enter',
mode: 'tags',
fieldNames: {
label: 'title',
value: 'id',
},
},
properties: {
option: {
type: 'void',
'x-component': 'Select.OptionTag',
properties: {
[uid()]: {
type: 'void',
title: '查看数据',
'x-component': 'Action.Drawer',
'x-component-props': {
bodyStyle: {
background: '#f0f2f5',
// paddingTop: 0,
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Tabs',
'x-designable-bar': 'Tabs.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '详情',
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
'x-component': 'Tabs.TabPane',
'x-component-props': {},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
'x-component-props': {
addNewComponent: 'AddNew.PaneItem',
},
},
},
},
},
},
},
},
},
},
},
},
},
};
export default () => {
return (
<RequestProvider>
<CollectionsProvider>
<SchemaRenderer
scope={{ useSelect, useValues, useOptionTagValues }}
schema={schema}
/>
</CollectionsProvider>
</RequestProvider>
);
};

View File

@ -383,192 +383,7 @@ export default () => {
## Select.Drawer
```tsx
import React from 'react';
import { SchemaRenderer } from '../';
import { useSelect, useOptionTagValues } from './';
console.log({ useSelect })
const dataSource = [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
{
id: 3,
title: '标题3',
},
];
function useValues() {
return {
table: dataSource,
}
}
const schema = {
type: 'object',
properties: {
input: {
interface: 'select',
type: 'string',
title: `编辑模式`,
enum: dataSource,
default: [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
],
'x-decorator': 'FormItem',
'x-component': 'Select.Drawer',
'x-component-props': {
placeholder: 'please enter',
mode: 'tags',
fieldNames: {
label: 'title',
value: 'id',
},
},
'x-reactions': {
target: 'read',
fulfill: {
state: {
value: '{{$self.value}}',
},
},
},
properties: {
options: {
type: 'void',
'x-component': 'Select.Options',
properties: {
form: {
type: 'void',
'x-component': 'Form',
'x-component-props': {
useValues: '{{ useValues }}',
},
properties: {
table: {
type: 'array',
'x-component': 'Table',
properties: {
actionbar: {
type: 'void',
'x-component': 'Table.ActionBar',
'x-component-props': {
align: 'bottom',
},
properties: {
action: {
type: 'void',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useSelect }}',
},
title: '确定',
},
},
},
column1: {
type: 'void',
title: '标题',
'x-component': 'Table.Column',
'x-component-props': {
// title: 'z1',
},
// 'x-designable-bar': 'Table.Column.DesignableBar',
properties: {
title: {
type: 'string',
required: true,
'x-read-pretty': true,
'x-decorator-props': {
feedbackLayout: 'popover',
},
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
},
},
},
},
},
},
read: {
interface: 'select',
type: 'string',
title: `阅读模式`,
enum: dataSource,
default: [
{
id: 1,
title: '标题1',
},
{
id: 2,
title: '标题2',
},
],
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Select.Drawer',
'x-component-props': {
placeholder: 'please enter',
mode: 'tags',
fieldNames: {
label: 'title',
value: 'id',
},
},
properties: {
option: {
type: 'void',
'x-component': 'Select.OptionTag',
properties: {
form: {
type: 'void',
'x-component': 'Form',
'x-component-props': {
useValues: '{{ useOptionTagValues }}',
},
properties: {
title: {
type: 'string',
title: '标题',
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
},
},
},
}
}
};
export default () => {
return (
<SchemaRenderer scope={{ useSelect, useValues, useOptionTagValues }} schema={schema} />
);
};
```
<code src="./demos/demo1.tsx"/>
## Schema API

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import {
connect,
mapReadPretty,
@ -7,6 +7,7 @@ import {
observer,
RecursionField,
useFieldSchema,
Schema,
} from '@formily/react';
import { Drawer, Select as AntdSelect, Tag } from 'antd';
import { PreviewText } from '@formily/antd';
@ -19,6 +20,14 @@ import { createContext } from 'react';
import { useContext } from 'react';
import { isEmpty } from 'lodash';
import { Field, isArrayField, isField } from '@formily/core';
import { Action } from '../action';
import { BlockSchemaContext, VisibleContext } from '../../context';
import { SchemaRenderer } from '../../components/schema-renderer';
import { uid } from '@formily/shared';
import { CollectionFieldContext } from '../table';
import { CollectionProvider, useCollectionContext } from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
export const Select: any = connect(
(props) => {
@ -227,22 +236,48 @@ Select.Object = connect(
const OptionTagContext = createContext(null);
const SelectContext = createContext<any>({});
const SelectedRowKeysContext = createContext([]);
Select.useOkAction = () => {
const { props } = useContext(SelectContext);
const [selectedRows] = useContext(SelectedRowKeysContext);
return {
async run() {
props.onChange(selectedRows);
console.log('selectedRows', selectedRows);
},
};
};
Select.useSelect = () => {
const [, setSelectedRows] = useContext(SelectedRowKeysContext);
return (keys, rows) => {
setSelectedRows(rows);
console.log('Select.onSelect', keys, rows);
};
};
Select.useSelectedRowKeys = () => {
const [selectedRows] = useContext(SelectedRowKeysContext);
return selectedRows?.map((row) => row.id) || [];
};
const SelectContext = createContext(null);
Select.Drawer = connect(
(props) => {
const field = useField();
const field = useField<Field>();
const {
value,
onChange,
fieldNames = {
label: 'label',
value: 'value',
label: 'id',
value: 'id',
},
...others
} = props;
const [visible, setVisible] = useState(false);
const schema = useFieldSchema();
const { schema } = useDesignable();
const options = field?.['dataSource'] || props.options || [];
let optionValue = undefined;
@ -289,60 +324,49 @@ Select.Drawer = connect(
);
}
};
const selectedKeys = toArr(optionValue).map((item) => item.value);
console.log({ selectedKeys });
// const selectedKeys = toArr(optionValue).map((item) => item.value);
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
console.log({ optionValue, value });
const collectionField = useContext(CollectionFieldContext);
return (
<>
<AntdSelect
{...others}
labelInValue
open={false}
value={optionValue}
onClick={() => {
setVisible(true);
}}
onChange={(selectValue: any) => {
if (!selectValue) {
onChange(null);
return;
}
if (isArr(selectValue)) {
const selectValues = selectValue.map((s) => s.value);
onFieldChange(selectValues);
} else {
onFieldChange(selectValue.value);
}
}}
></AntdSelect>
<Drawer
width={'50%'}
visible={visible}
onClose={() => setVisible(false)}
destroyOnClose
>
{/* <SelectedRowKeysContext.Provider value={selectedKeys}> */}
<SelectContext.Provider
value={{
onChange(selectValue) {
onFieldChange(selectValue);
setVisible(false);
},
<SelectContext.Provider value={{ field, schema, props }}>
<VisibleContext.Provider value={[visible, setVisible]}>
<AntdSelect
{...others}
labelInValue
open={false}
value={optionValue}
onClick={() => {
setVisible(true);
}}
onChange={(selectValue: any) => {
if (!selectValue) {
onChange(null);
return;
}
if (isArr(selectValue)) {
const selectValues = selectValue.map((s) => s.value);
onFieldChange(selectValues);
} else {
onFieldChange(selectValue.value);
}
}}
></AntdSelect>
<SelectedRowKeysContext.Provider
value={[selectedRows, setSelectedRows]}
>
<RecursionField
onlyRenderProperties
schema={schema}
filterProperties={(s) => {
return s['x-component'] === 'Select.Options';
}}
/>
</SelectContext.Provider>
{/* </SelectedRowKeysContext.Provider> */}
</Drawer>
</>
<CollectionProvider collectionName={collectionField?.target}>
<RecursionField
onlyRenderProperties
schema={schema}
filterProperties={(s) => {
return s['x-component'] === 'Select.Options.Drawer';
}}
/>
</CollectionProvider>
</SelectedRowKeysContext.Provider>
</VisibleContext.Provider>
</SelectContext.Provider>
);
},
mapProps(
@ -365,41 +389,98 @@ Select.Drawer = connect(
),
mapReadPretty(
observer((props: any) => {
const collectionField = useContext(CollectionFieldContext);
const field = useField<Formily.Core.Models.Field>();
const { fieldNames = { label: 'label' }, ...others } = props;
const { fieldNames = { label: 'id' }, ...others } = props;
const value = field.value || field.initialValue;
const schema = useFieldSchema();
const { schema } = useDesignable();
console.log({ fieldNames, field, value });
if (!value) {
return null;
}
const values = toArr(value);
const s = schema.reduceProperties((buf, current) => {
if (current['x-component'] === 'Select.OptionTag') {
return current;
}
return buf;
}, null);
return (
<div>
{values.map((data, index) => {
return (
<OptionTagContext.Provider value={{ index, data, fieldNames }}>
{data[fieldNames.label]}
{/* <RecursionField
schema={schema}
onlyRenderProperties
filterProperties={(s) => {
return s['x-component'] === 'Select.OptionTag';
}}
/> */}
</OptionTagContext.Provider>
);
})}
<BlockSchemaContext.Provider value={schema}>
<CollectionProvider collectionName={collectionField?.target}>
{values.map((data, index) => {
return (
<OptionTagContext.Provider
value={{ index, data, fieldNames }}
>
{s ? (
<RecursionField name={s.name} schema={s} />
) : (
data[fieldNames.label]
)}
</OptionTagContext.Provider>
);
})}
</CollectionProvider>
</BlockSchemaContext.Provider>
</div>
);
}),
),
);
Select.Drawer.useResource = ({ onSuccess }) => {
const { collection } = useCollectionContext();
const ctx = useContext(OptionTagContext);
const resource = Resource.make({
resourceName: collection?.name,
resourceKey: ctx.data.id,
});
console.log('OptionTagContext', ctx.data.id)
const { schema } = useDesignable();
const fieldFields = (schema: Schema) => {
const names = [];
schema.reduceProperties((buf, current) => {
if (current['x-component'] === 'Form.Field') {
const fieldName = current['x-component-props']?.['fieldName'];
if (fieldName) {
buf.push(fieldName);
}
} else {
const fieldNames = fieldFields(current);
buf.push(...fieldNames);
}
return buf;
}, names);
return names;
};
const [visible] = useContext(VisibleContext);
const service = useRequest(
(params?: any) => {
console.log('Table.useResource', params);
return resource.get({ ...params, appends: fieldFields(schema) });
},
{
formatResult: (result) => result?.data,
onSuccess,
manual: true,
},
);
useEffect(() => {
if (visible) {
service.run();
}
}, [visible]);
return { resource, service, initialValues: service.data, ...service };
}
Select.Options = observer((props) => {
return <>{props.children}</>;
});
Select.Options.Drawer = Action.Drawer;
export function useSelect() {
const { onChange } = useContext(SelectContext);
return {
@ -418,12 +499,10 @@ Select.OptionTag = observer((props) => {
const [visible, setVisible] = useState(false);
const { data, fieldNames } = useContext(OptionTagContext);
return (
<>
<VisibleContext.Provider value={[visible, setVisible]}>
<Tag onClick={() => setVisible(true)}>{data[fieldNames.label]}</Tag>
<Drawer width={'50%'} visible={visible} onClose={() => setVisible(false)}>
{props.children}
</Drawer>
</>
{props.children}
</VisibleContext.Provider>
);
});

View File

@ -3,39 +3,29 @@ import { range } from 'lodash';
import { ISchema } from '@formily/react';
import { SchemaRenderer } from '../..';
import { uid } from '@formily/shared';
import {
CollectionsProvider,
DesignableSwitchProvider,
} from '@nocobase/client/src/constate';
import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider';
const loadDataSource = (params?: any): Promise<any> => {
const { page, pageSize = 50 } = params || {};
console.log({ pageSize });
return new Promise((resolve) => {
setTimeout(() => {
resolve({
list: range(50 || pageSize).map(() => {
return { id: uid(), title: uid() };
}),
total: 50,
});
}, 1000);
});
};
const schema: ISchema = {
const schema = {
name: 'table1',
type: 'array',
name: 'arr',
'x-designable-bar': 'Table.DesignableBar',
'x-decorator': 'CardItem',
'x-component': 'Table',
default: [],
'x-component-props': {
collectionName: 'users',
rowKey: 'id',
dragSort: true,
showIndex: true,
refreshRequestOnChange: false,
clientSidePagination: true,
dataRequest: '{{ loadDataSource }}',
refreshRequestOnChange: true,
pagination: {
pageSize: 2,
pageSize: 10,
},
},
// default: range(50).map(() => {
// return { id: uid(), title: uid() };
// }),
properties: {
[uid()]: {
type: 'void',
@ -44,6 +34,12 @@ const schema: ISchema = {
properties: {
[uid()]: {
type: 'void',
title: '筛选',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'filter',
},
'x-align': 'left',
'x-component': 'Table.Filter',
'x-designable-bar': 'Table.Filter.DesignableBar',
'x-component-props': {
@ -53,15 +49,44 @@ const schema: ISchema = {
[uid()]: {
type: 'void',
name: 'action1',
title: '添加',
title: '删除',
'x-align': 'right',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'destroy',
},
'x-component': 'Action',
'x-designable-bar': 'Table.Action.DesignableBar',
'x-component-props': {
icon: 'DeleteOutlined',
confirm: {
title: '删除数据',
content: '删除后无法恢复,确定要删除吗?',
},
useAction: '{{ Table.useTableDestroyAction }}',
},
},
[uid()]: {
type: 'void',
name: 'action1',
title: '添加',
'x-align': 'right',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'create',
},
'x-component': 'Action',
'x-component-props': {
icon: 'PlusOutlined',
type: 'primary',
},
'x-designable-bar': 'Table.Action.DesignableBar',
properties: {
modal: {
type: 'void',
title: '添加数据',
'x-decorator': 'Form',
'x-component': 'Action.Modal',
'x-component': 'Action.Drawer',
'x-component-props': {
useOkAction: '{{ Table.useTableCreateAction }}',
},
@ -77,76 +102,55 @@ const schema: ISchema = {
},
},
},
[uid()]: {
type: 'void',
name: 'action1',
title: '删除',
'x-component': 'Action',
'x-designable-bar': 'Table.Action.DesignableBar',
'x-component-props': {
useAction: '{{ Table.useTableDestroyAction }}',
},
},
},
},
column2: {
[uid()]: {
type: 'void',
title: '操作',
'x-component': 'Table.Column',
'x-component-props': {
className: 'nb-table-operation',
},
'x-component-props': {},
'x-designable-bar': 'Table.Operation.DesignableBar',
properties: {
action1: {
[uid()]: {
type: 'void',
name: 'dropdown1',
'x-component': 'Action.Dropdown',
'x-designable-bar': 'Action.DesignableBar',
'x-component': 'Action.Group',
'x-component-props': {
buttonProps: {
icon: 'EllipsisOutlined',
},
type: 'link',
},
properties: {
[uid()]: {
type: 'void',
title: '操作 1',
'x-component': 'Menu.Action',
'x-component-props': {
style: {
minWidth: 150,
},
disabled: true,
},
},
[uid()]: {
type: 'void',
name: 'action1',
title: '查看',
'x-component': 'Menu.Action',
'x-component': 'Action',
'x-component-props': {
type: 'link',
},
'x-designable-bar': 'Table.Action.DesignableBar',
'x-action-type': 'view',
properties: {
[uid()]: {
type: 'void',
title: '查看',
'x-component': 'Action.Modal',
title: '查看数据',
'x-component': 'Action.Drawer',
'x-component-props': {
bodyStyle: {
background: '#f0f2f5',
paddingTop: 0,
// paddingTop: 0,
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Tabs',
'x-designable-bar': 'Tabs.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '详情',
'x-designable-bar': 'Tabs.TabPane.DesignableBar',
'x-component': 'Tabs.TabPane',
'x-component-props': {
tab: 'Tab1',
},
'x-component-props': {},
properties: {
[uid()]: {
type: 'void',
@ -166,17 +170,22 @@ const schema: ISchema = {
[uid()]: {
type: 'void',
title: '编辑',
'x-component': 'Menu.Action',
'x-component': 'Action',
'x-component-props': {
type: 'link',
},
'x-designable-bar': 'Table.Action.DesignableBar',
'x-action-type': 'update',
properties: {
[uid()]: {
type: 'void',
title: '编辑数据',
'x-decorator': 'Form',
'x-decorator-props': {
useResource: '{{ Table.useResource }}',
useValues: '{{ Table.useTableRowRecord }}',
},
'x-component': 'Action.Modal',
'x-component': 'Action.Drawer',
'x-component-props': {
useOkAction: '{{ Table.useTableUpdateAction }}',
},
@ -187,75 +196,39 @@ const schema: ISchema = {
'x-component-props': {
addNewComponent: 'AddNew.FormItem',
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
title: {
title: '标题',
type: 'string',
'x-component': 'Input',
'x-decorator': 'FormItem',
},
},
},
},
},
},
},
},
},
},
},
[uid()]: {
type: 'void',
title: '删除',
'x-component': 'Menu.Action',
'x-component-props': {
useAction: '{{ Table.useTableDestroyAction }}',
},
},
// [uid()]: {
// type: 'void',
// title: '删除',
// 'x-component': 'Action',
// 'x-designable-bar': 'Table.Action.DesignableBar',
// 'x-action-type': 'destroy',
// 'x-component-props': {
// type: 'link',
// useAction: '{{ Table.useTableDestroyAction }}',
// },
// },
},
},
},
},
column0: {
type: 'void',
title: 'ID',
'x-component': 'Table.Column',
'x-designable-bar': 'Table.Column.DesignableBar',
properties: {
id: {
type: 'string',
'x-component': 'Input',
'x-read-pretty': true,
},
},
},
column1: {
type: 'void',
title: 'Title',
'x-component': 'Table.Column',
properties: {
title: {
type: 'string',
'x-component': 'Input',
'x-read-pretty': true,
},
},
},
},
};
export default () => {
return (
<div>
<SchemaRenderer scope={{ loadDataSource }} schema={schema} />
<RequestProvider>
<DesignableSwitchProvider>
<CollectionsProvider>
<SchemaRenderer schema={schema} />
</CollectionsProvider>
</DesignableSwitchProvider>
</RequestProvider>
</div>
);
};

View File

@ -40,7 +40,11 @@ import {
SchemaField,
SchemaRenderer,
} from '../../components/schema-renderer';
import { interfaces, isAssociation, options } from '../database-field/interfaces';
import {
interfaces,
isAssociation,
options,
} from '../database-field/interfaces';
import { DraggableBlockContext } from '../../components/drag-and-drop';
import AddNew from '../add-new';
import { isGridRowOrCol } from '../grid';
@ -94,7 +98,7 @@ export interface ITableRowContext {
const TableContext = createContext<ITableContext>({} as any);
export const TableRowContext = createContext<ITableRowContext>(null);
const CollectionFieldContext = createContext(null);
export const CollectionFieldContext = createContext(null);
export const useTable = () => {
return useContext(TableContext);
@ -417,20 +421,133 @@ function AddColumn() {
checked={displayed.has(field.name)}
onChange={async (checked) => {
if (checked) {
console.log('SwitchMenuItem.field.name', field.dataType, service.params[0])
const data = appendChild({
console.log(
'SwitchMenuItem.field.name',
field.dataType,
service.params[0],
);
const columnSchema: ISchema = {
type: 'void',
'x-component': 'Table.Column',
'x-component-props': {
fieldName: field.name,
},
'x-designable-bar': 'Table.Column.DesignableBar',
});
};
if (field.interface === 'linkTo') {
columnSchema.properties = {
options: {
type: 'void',
'x-decorator': 'Form',
'x-component': 'Select.Options.Drawer',
'x-component-props': {
useOkAction: '{{ Select.useOkAction }}',
},
title: '关联数据',
properties: {
table: {
type: 'array',
'x-designable-bar': 'Table.DesignableBar',
'x-decorator': 'BlockItem',
'x-decorator-props': {
draggable: false,
},
'x-component': 'Table',
default: [],
'x-component-props': {
rowKey: 'id',
defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}',
onSelect: '{{ Select.useSelect() }}',
collectionName: field.target,
// dragSort: true,
showIndex: true,
refreshRequestOnChange: true,
pagination: {
pageSize: 10,
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Table.ActionBar',
'x-designable-bar':
'Table.ActionBar.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '筛选',
'x-decorator': 'AddNew.Displayed',
'x-decorator-props': {
displayName: 'filter',
},
'x-align': 'left',
'x-component': 'Table.Filter',
'x-designable-bar':
'Table.Filter.DesignableBar',
'x-component-props': {
fieldNames: [],
},
},
},
},
},
},
},
},
option: {
type: 'void',
'x-component': 'Select.OptionTag',
properties: {
[uid()]: {
type: 'void',
title: '查看数据',
'x-component': 'Action.Drawer',
'x-component-props': {
bodyStyle: {
background: '#f0f2f5',
},
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Tabs',
'x-designable-bar': 'Tabs.DesignableBar',
properties: {
[uid()]: {
type: 'void',
title: '详情',
'x-designable-bar':
'Tabs.TabPane.DesignableBar',
'x-component': 'Tabs.TabPane',
'x-component-props': {},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
'x-component-props': {
addNewComponent: 'AddNew.PaneItem',
},
},
},
},
},
},
},
},
},
},
};
}
const data = appendChild(columnSchema);
await createSchema(data);
if (isAssociation(field)) {
const defaultAppends = service.params[0]?.defaultAppends || [];
const defaultAppends =
service.params[0]?.defaultAppends || [];
defaultAppends.push(field.name);
await service.run({...service.params[0], defaultAppends});
await service.run({
...service.params[0],
defaultAppends,
});
}
} else {
const s: any = displayed.get(field.name);
@ -439,12 +556,16 @@ function AddColumn() {
await removeSchema(removed);
displayed.remove(field.name);
if (isAssociation(field)) {
const defaultAppends = service.params[0]?.defaultAppends || [];
const defaultAppends =
service.params[0]?.defaultAppends || [];
const index = defaultAppends.indexOf(field.name);
if (index > -1) {
defaultAppends.splice(index, 1);
}
await service.run({...service.params[0], defaultAppends});
await service.run({
...service.params[0],
defaultAppends,
});
}
}
// service.refresh();
@ -535,7 +656,7 @@ const TableMain = () => {
setSelectedRowKeys,
service,
field,
props: { rowKey, dragSort, showIndex },
props: { rowKey, dragSort, showIndex, onSelect },
refresh,
} = useTable();
const columns = useTableColumns();
@ -624,8 +745,9 @@ const TableMain = () => {
rowSelection={{
type: 'checkbox',
selectedRowKeys,
onChange: (rowKeys) => {
onChange: (rowKeys, rows) => {
setSelectedRowKeys(rowKeys);
onSelect && onSelect(rowKeys, rows);
},
renderCell: (checked, record, _, originNode) => {
const index = findIndex(
@ -697,12 +819,15 @@ const TableProvider = (props: any) => {
rowKey = 'id',
dataRequest,
useResource = useGeneralResource,
defaultSelectedRowKeys,
...others
} = props;
const { schema } = useDesignable();
const field = useField<Formily.Core.Models.ArrayField>();
const [pagination, setPagination] = usePagination();
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<any>(
defaultSelectedRowKeys || [],
);
const [, refresh] = useState(uid());
const { resource } = useResource();
const { sortableField } = useCollectionContext();
@ -1859,6 +1984,9 @@ Table.Cell = observer((props: any) => {
feedbackLayout: 'popover',
},
'x-decorator': 'FormilyFormItem',
properties: {
...schema?.properties,
},
},
},
})