improve action & database field & table
This commit is contained in:
parent
b7a2d5d3e5
commit
14160761d3
@ -40,7 +40,7 @@ import { Menu } from '../menu';
|
|||||||
import { Password } from '../password';
|
import { Password } from '../password';
|
||||||
import { Radio } from '../radio';
|
import { Radio } from '../radio';
|
||||||
import { Select } from '../select';
|
import { Select } from '../select';
|
||||||
import { Table } from '../table';
|
import { Table, useTableCreateAction, useTableDestroyAction } from '../table';
|
||||||
import { Tabs } from '../tabs';
|
import { Tabs } from '../tabs';
|
||||||
import { TimePicker } from '../time-picker';
|
import { TimePicker } from '../time-picker';
|
||||||
import { Upload } from '../upload';
|
import { Upload } from '../upload';
|
||||||
@ -59,6 +59,8 @@ export const scope = {
|
|||||||
useLogin,
|
useLogin,
|
||||||
useRegister,
|
useRegister,
|
||||||
useSubmit,
|
useSubmit,
|
||||||
|
useTableCreateAction,
|
||||||
|
useTableDestroyAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const components = {
|
export const components = {
|
||||||
|
@ -29,7 +29,7 @@ group:
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer, registerScope } from '../';
|
import { SchemaRenderer, registerScope } from '../';
|
||||||
|
|
||||||
function useCustomAction() {
|
function useAction() {
|
||||||
return {
|
return {
|
||||||
run() {
|
run() {
|
||||||
alert('这是自定义的操作逻辑');
|
alert('这是自定义的操作逻辑');
|
||||||
@ -37,17 +37,13 @@ function useCustomAction() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerScope({
|
|
||||||
useCustomAction,
|
|
||||||
});
|
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '按钮',
|
title: '按钮',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction: '{{ useCustomAction }}'
|
useAction,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,6 +184,17 @@ export default () => {
|
|||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
|
import { useVisibleContext } from './';
|
||||||
|
|
||||||
|
function useAction() {
|
||||||
|
const { visible, setVisible } = useVisibleContext();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
console.log({ visible })
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -201,6 +208,40 @@ const schema = {
|
|||||||
'x-component': 'Action.Modal',
|
'x-component': 'Action.Modal',
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
properties: {
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '关闭',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
type: 'void',
|
||||||
|
title: '打开二级抽屉',
|
||||||
|
// 'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Action',
|
||||||
|
properties: {
|
||||||
|
drawer1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '二级抽屉标题',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -218,11 +259,16 @@ import React, { useRef } from 'react';
|
|||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
import { ActionContext } from './';
|
import { ActionContext } from './';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const containerRef = useRef();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '按钮',
|
title: '按钮',
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
containerRef
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
container1: {
|
container1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -240,74 +286,10 @@ const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const ref = useRef();
|
|
||||||
console.log('containerRef2222', ref)
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ActionContext.Provider value={{
|
|
||||||
containerRef: ref,
|
|
||||||
}}>
|
|
||||||
<SchemaRenderer schema={schema} />
|
<SchemaRenderer schema={schema} />
|
||||||
</ActionContext.Provider>
|
|
||||||
<div style={{padding: '8px 0'}}>目标容器:</div>
|
|
||||||
<div ref={ref} id={'container'} style={{ border: '1px dashed #ebedf1', background: '#fafafa', padding: 24 }}/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Action.DesignableBar - 按钮配置操作栏
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import React from 'react';
|
|
||||||
import { SchemaRenderer } from '../';
|
|
||||||
|
|
||||||
const schema = {
|
|
||||||
type: 'void',
|
|
||||||
name: 'action1',
|
|
||||||
title: '按钮',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designable-bar': 'Action.DesignableBar',
|
|
||||||
properties: {
|
|
||||||
drawer1: {
|
|
||||||
type: 'void',
|
|
||||||
title: '抽屉标题',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
input: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
action2: {
|
|
||||||
type: 'void',
|
|
||||||
title: '打开二级抽屉',
|
|
||||||
// 'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Action',
|
|
||||||
properties: {
|
|
||||||
drawer1: {
|
|
||||||
type: 'void',
|
|
||||||
title: '二级抽屉标题',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-component-props': {},
|
|
||||||
properties: {
|
|
||||||
input: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return <SchemaRenderer schema={schema} />
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -10,9 +10,8 @@ import {
|
|||||||
Schema,
|
Schema,
|
||||||
useField,
|
useField,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Button, Dropdown, Menu, Popover, Space } from 'antd';
|
import { Button, Dropdown, Menu, Popover, Space, Drawer, Modal } from 'antd';
|
||||||
import { Link, useHistory, LinkProps } from 'react-router-dom';
|
import { Link, useHistory, LinkProps } from 'react-router-dom';
|
||||||
import Drawer from '../../components/Drawer';
|
|
||||||
import { SchemaRenderer, useDesignable } from '../';
|
import { SchemaRenderer, useDesignable } from '../';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
@ -22,6 +21,7 @@ import { useMount } from 'ahooks';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
import constate from 'constate';
|
||||||
|
|
||||||
export function useDefaultAction() {
|
export function useDefaultAction() {
|
||||||
return {
|
return {
|
||||||
@ -95,92 +95,81 @@ function useDesignableBar() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionContext = createContext({ containerRef: null });
|
const [VisibleProvider, useVisibleContext] = constate(
|
||||||
|
(props: any = {}) => {
|
||||||
|
const { initialVisible = false, containerRef = null } = props;
|
||||||
|
const [visible, setVisible] = useState(initialVisible);
|
||||||
|
|
||||||
export const Action: ActionType = observer((props) => {
|
return { containerRef, visible, setVisible };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export { VisibleProvider, useVisibleContext };
|
||||||
|
|
||||||
|
const BaseAction = observer((props: any) => {
|
||||||
const { useAction = useDefaultAction, ...others } = props;
|
const { useAction = useDefaultAction, ...others } = props;
|
||||||
const { containerRef } = useContext(ActionContext);
|
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const schema = useFieldSchema();
|
|
||||||
const { run } = useAction();
|
const { run } = useAction();
|
||||||
const { DesignableBar } = useDesignableBar();
|
const { DesignableBar } = useDesignableBar();
|
||||||
|
const { setVisible } = useVisibleContext();
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
|
||||||
const renderContainer = () => {
|
const renderButton = () => (
|
||||||
let childSchema = null;
|
|
||||||
if (schema.properties) {
|
|
||||||
const key = Object.keys(schema.properties).shift();
|
|
||||||
const current = schema.properties[key];
|
|
||||||
childSchema = current;
|
|
||||||
}
|
|
||||||
if (childSchema && childSchema['x-component'] === 'Action.Container') {
|
|
||||||
containerRef &&
|
|
||||||
ReactDOM.render(
|
|
||||||
<div>
|
|
||||||
<SchemaRenderer schema={childSchema} onlyRenderProperties />
|
|
||||||
</div>,
|
|
||||||
containerRef.current,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useMount(() => {
|
|
||||||
renderContainer();
|
|
||||||
});
|
|
||||||
|
|
||||||
let childSchema = null;
|
|
||||||
|
|
||||||
if (schema.properties) {
|
|
||||||
const key = Object.keys(schema.properties).shift();
|
|
||||||
const current = schema.properties[key];
|
|
||||||
childSchema = current;
|
|
||||||
}
|
|
||||||
console.log({ schema });
|
|
||||||
if (childSchema && childSchema['x-component'] === 'Action.Popover') {
|
|
||||||
return (
|
|
||||||
<Popover
|
|
||||||
trigger={['click']}
|
|
||||||
title={childSchema.title}
|
|
||||||
{...childSchema['x-component-props']}
|
|
||||||
content={
|
|
||||||
<div>
|
|
||||||
<SchemaRenderer schema={childSchema} onlyRenderProperties />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button {...others}>{field.title}</Button>
|
|
||||||
</Popover>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
<Button
|
||||||
{...others}
|
{...others}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (!childSchema) {
|
setVisible && setVisible(true);
|
||||||
return await run();
|
await run();
|
||||||
}
|
|
||||||
if (childSchema['x-component'] === 'Action.Drawer') {
|
|
||||||
Drawer.open({
|
|
||||||
title: childSchema.title,
|
|
||||||
...(childSchema['x-component-props'] || {}),
|
|
||||||
content: () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SchemaRenderer schema={childSchema} onlyRenderProperties />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (childSchema['x-component'] === 'Action.Container') {
|
|
||||||
renderContainer();
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{field.title}
|
{field.title}
|
||||||
<DesignableBar />
|
<DesignableBar />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const popover = schema.reduceProperties((items, current) => {
|
||||||
|
if (current['x-component'] === 'Action.Popover') {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
if (popover) {
|
||||||
|
return (
|
||||||
|
<RecursionField
|
||||||
|
schema={
|
||||||
|
new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[popover.name]: {
|
||||||
|
...popover.toJSON(),
|
||||||
|
'x-button': renderButton(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderButton()}
|
||||||
|
{props.children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Action: ActionType = observer((props: any) => {
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
if (schema.properties) {
|
||||||
|
return (
|
||||||
|
<VisibleProvider containerRef={props.containerRef}>
|
||||||
|
<BaseAction {...props} />
|
||||||
|
</VisibleProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <BaseAction {...props} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
Action.Link = observer((props) => {
|
Action.Link = observer((props) => {
|
||||||
@ -198,21 +187,51 @@ Action.URL = observer((props) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Action.Container = ({ children }) => {
|
Action.Container = observer((props) => {
|
||||||
return children;
|
const { visible, setVisible } = useVisibleContext();
|
||||||
};
|
return visible && <div>{props.children}</div>;
|
||||||
|
});
|
||||||
|
|
||||||
Action.Popover = ({ children }) => {
|
Action.Popover = observer((props) => {
|
||||||
return children;
|
const schema = useFieldSchema();
|
||||||
};
|
return (
|
||||||
|
<Popover {...props} content={props.children}>
|
||||||
|
{schema['x-button']}
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Action.Drawer = ({ children }) => {
|
Action.Drawer = observer((props) => {
|
||||||
return children;
|
const field = useField();
|
||||||
};
|
const { visible, setVisible } = useVisibleContext();
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
title={field.title}
|
||||||
|
width={'50%'}
|
||||||
|
{...props}
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => setVisible(false)}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Action.Modal = ({ children }) => {
|
Action.Modal = observer((props) => {
|
||||||
return children;
|
const field = useField();
|
||||||
};
|
const { visible, setVisible } = useVisibleContext();
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={field.title}
|
||||||
|
width={'50%'}
|
||||||
|
{...props}
|
||||||
|
visible={visible}
|
||||||
|
onCancel={() => setVisible(false)}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Action.DesignableBar = () => {
|
Action.DesignableBar = () => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
|
@ -16,6 +16,7 @@ import React from 'react';
|
|||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
import { observer, connect, useField } from '@formily/react';
|
import { observer, connect, useField } from '@formily/react';
|
||||||
|
import Editor from '@monaco-editor/react';
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -50,73 +51,13 @@ const form = createForm();
|
|||||||
export default observer(() => {
|
export default observer(() => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{JSON.stringify(form.values, null, 2)}
|
|
||||||
<SchemaRenderer form={form} schema={schema} />
|
<SchemaRenderer form={form} schema={schema} />
|
||||||
|
<Editor
|
||||||
|
height="200px"
|
||||||
|
defaultLanguage="json"
|
||||||
|
value={JSON.stringify(form.values, null, 2)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
```tsx
|
|
||||||
import React from 'react';
|
|
||||||
import { SchemaRenderer } from '../';
|
|
||||||
|
|
||||||
const schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
array: {
|
|
||||||
type: 'array',
|
|
||||||
// title: '数据表字段',
|
|
||||||
'x-component': 'ArrayCollapse',
|
|
||||||
'x-component-props': {
|
|
||||||
accordion: true,
|
|
||||||
},
|
|
||||||
// maxItems: 3,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
'x-component': 'ArrayCollapse.CollapsePanel',
|
|
||||||
'x-component-props': {
|
|
||||||
header: '字段',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
index: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayCollapse.Index',
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
title: 'Input',
|
|
||||||
required: true,
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
remove: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayCollapse.Remove',
|
|
||||||
},
|
|
||||||
moveUp: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayCollapse.MoveUp',
|
|
||||||
},
|
|
||||||
moveDown: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayCollapse.MoveDown',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
addition: {
|
|
||||||
type: 'void',
|
|
||||||
title: '添加字段',
|
|
||||||
'x-component': 'ArrayCollapse.Addition',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return <SchemaRenderer schema={schema} />
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -11,13 +11,7 @@ import {
|
|||||||
import { ArrayCollapse } from '@formily/antd';
|
import { ArrayCollapse } from '@formily/antd';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import '@formily/antd/lib/form-tab/style';
|
import '@formily/antd/lib/form-tab/style';
|
||||||
import { Collapse, Button } from 'antd';
|
import { Collapse, Button, Dropdown, Menu } from 'antd';
|
||||||
|
|
||||||
const text = `
|
|
||||||
A dog is a type of domesticated animal.
|
|
||||||
Known for its loyalty and faithfulness,
|
|
||||||
it can be found as a welcome guest in many households across the world.
|
|
||||||
`;
|
|
||||||
|
|
||||||
const interfaces = new Map<string, ISchema>();
|
const interfaces = new Map<string, ISchema>();
|
||||||
|
|
||||||
@ -33,6 +27,21 @@ interfaces.set('string', {
|
|||||||
} as ISchema,
|
} as ISchema,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
|
'ui.title': {
|
||||||
|
type: 'string',
|
||||||
|
title: '字段名称',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
title: '字段标识',
|
||||||
|
required: true,
|
||||||
|
'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
type: {
|
type: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: '数据类型',
|
title: '数据类型',
|
||||||
@ -44,20 +53,6 @@ interfaces.set('string', {
|
|||||||
{ label: 'Text', value: 'text' },
|
{ label: 'Text', value: 'text' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
name: {
|
|
||||||
type: 'string',
|
|
||||||
title: '字段标识',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
'ui.title': {
|
|
||||||
type: 'string',
|
|
||||||
title: '字段名称',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
'ui.required': {
|
'ui.required': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: '必填',
|
title: '必填',
|
||||||
@ -79,6 +74,21 @@ interfaces.set('textarea', {
|
|||||||
} as ISchema,
|
} as ISchema,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
|
'ui.title': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: '字段名称',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: '字段标识',
|
||||||
|
'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
type: {
|
type: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: '数据类型',
|
title: '数据类型',
|
||||||
@ -90,13 +100,28 @@ interfaces.set('textarea', {
|
|||||||
{ label: 'Text', value: 'text' },
|
{ label: 'Text', value: 'text' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
name: {
|
'ui.required': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: true,
|
title: '必填',
|
||||||
title: '字段标识',
|
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input.TextArea',
|
'x-component': 'Checkbox',
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interfaces.set('subTable', {
|
||||||
|
type: 'object',
|
||||||
|
default: {
|
||||||
|
type: 'string',
|
||||||
|
// name,
|
||||||
|
ui: {
|
||||||
|
type: 'string',
|
||||||
|
// title,
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: [],
|
||||||
|
} as ISchema,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
'ui.title': {
|
'ui.title': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: true,
|
required: true,
|
||||||
@ -104,6 +129,170 @@ interfaces.set('textarea', {
|
|||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input',
|
'x-component': 'Input',
|
||||||
},
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: '字段标识',
|
||||||
|
'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
title: '数据类型',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: [
|
||||||
|
{ label: 'String', value: 'string' },
|
||||||
|
{ label: 'Text', value: 'text' },
|
||||||
|
{ label: 'HasMany', value: 'hasMany' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'children': {
|
||||||
|
type: 'array',
|
||||||
|
title: '子表格字段',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'DatabaseField',
|
||||||
|
},
|
||||||
|
// 'ui.required': {
|
||||||
|
// type: 'string',
|
||||||
|
// title: '必填',
|
||||||
|
// 'x-decorator': 'FormItem',
|
||||||
|
// 'x-component': 'Checkbox',
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interfaces.set('select', {
|
||||||
|
type: 'object',
|
||||||
|
default: {
|
||||||
|
type: 'string',
|
||||||
|
// name,
|
||||||
|
ui: {
|
||||||
|
type: 'string',
|
||||||
|
// title,
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: [],
|
||||||
|
} as ISchema,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
'ui.title': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: '字段名称',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
title: '字段标识',
|
||||||
|
'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
title: '数据类型',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: [
|
||||||
|
{ label: 'String', value: 'string' },
|
||||||
|
{ label: 'Text', value: 'text' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'ui.enum': {
|
||||||
|
type: 'array',
|
||||||
|
title: '可选项',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
'x-component-props': {
|
||||||
|
pagination: false,
|
||||||
|
// scroll: { x: '100%' },
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { width: 50, title: '', align: 'center' },
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.SortHandle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column2: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '选项值' },
|
||||||
|
properties: {
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column3: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '选项' },
|
||||||
|
properties: {
|
||||||
|
label: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column4: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '颜色' },
|
||||||
|
properties: {
|
||||||
|
color: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ColorSelect',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column5: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'operations',
|
||||||
|
fixed: 'right',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
item: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormItem',
|
||||||
|
properties: {
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Addition',
|
||||||
|
title: '添加可选项',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
'ui.required': {
|
'ui.required': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: '必填',
|
title: '必填',
|
||||||
@ -116,65 +305,101 @@ interfaces.set('textarea', {
|
|||||||
export const DatabaseField: any = observer((props) => {
|
export const DatabaseField: any = observer((props) => {
|
||||||
const field = useField<Formily.Core.Models.ArrayField>();
|
const field = useField<Formily.Core.Models.ArrayField>();
|
||||||
console.log('DatabaseField', field.componentProps);
|
console.log('DatabaseField', field.componentProps);
|
||||||
|
const [activeKey, setActiveKey] = useState(null);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Collapse
|
<Collapse activeKey={activeKey} onChange={(key) => {
|
||||||
// activeKey={field.componentProps.activeKey}
|
setActiveKey(key);
|
||||||
{...props}
|
}} accordion>
|
||||||
onChange={(key) => {
|
|
||||||
field.setComponentProps({
|
|
||||||
activeKey: key,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
accordion
|
|
||||||
>
|
|
||||||
{field.value?.map((item, index) => {
|
{field.value?.map((item, index) => {
|
||||||
const schema = interfaces.get(item.interface);
|
const schema = interfaces.get(item.interface);
|
||||||
console.log({ schema });
|
console.log({ schema });
|
||||||
return (
|
return (
|
||||||
<Collapse.Panel
|
<Collapse.Panel
|
||||||
extra={[
|
// extra={[
|
||||||
<Button onClick={() => field.moveUp(index)}>Up</Button>,
|
// <Button onClick={() => field.moveUp(index)}>Up</Button>,
|
||||||
<Button
|
// <Button
|
||||||
onClick={() => {
|
// onClick={() => {
|
||||||
field.remove(index);
|
// field.remove(index);
|
||||||
field.insert(index, {
|
// field.insert(index, {
|
||||||
...item,
|
// ...item,
|
||||||
interface: 'textarea',
|
// interface: 'textarea',
|
||||||
});
|
// });
|
||||||
}}
|
// }}
|
||||||
>
|
// >
|
||||||
Update
|
// Update
|
||||||
</Button>,
|
// </Button>,
|
||||||
]}
|
// ]}
|
||||||
header={item.name}
|
header={
|
||||||
|
<>
|
||||||
|
{item.ui && item.ui.title}
|
||||||
|
{' '}
|
||||||
|
{item.name}
|
||||||
|
</>
|
||||||
|
}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
>
|
>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
key={`${item.id}_${index}`}
|
key={`${item.id}_${index}`}
|
||||||
name={index}
|
name={index}
|
||||||
schema={new Schema(schema)}
|
schema={new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
layout: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormLayout',
|
||||||
|
'x-component-props': {
|
||||||
|
layout: 'vertical',
|
||||||
|
// labelCol: 4,
|
||||||
|
// wrapperCol: 20,
|
||||||
|
},
|
||||||
|
properties: schema.properties,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
<Dropdown
|
||||||
|
placement={'bottomCenter'}
|
||||||
|
overlayStyle={{
|
||||||
|
minWidth: 200,
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu
|
||||||
|
onClick={info => {
|
||||||
|
const schema = interfaces.get(info.key);
|
||||||
|
if (!schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
id: uid(),
|
||||||
|
name: uid(),
|
||||||
|
interface: info.key,
|
||||||
|
...schema.default
|
||||||
|
};
|
||||||
|
field.push(data);
|
||||||
|
setActiveKey(data.id);
|
||||||
|
console.log('info.key', info.key, schema);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu.Item key={'string'}>单行文本</Menu.Item>
|
||||||
|
<Menu.Item key={'textarea'}>多行文本</Menu.Item>
|
||||||
|
<Menu.Item key={'select'}>下拉选择</Menu.Item>
|
||||||
|
<Menu.Item key={'subTable'}>子表格</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
type={'dashed'}
|
type={'dashed'}
|
||||||
style={{ marginTop: 10 }}
|
style={{ marginTop: 10 }}
|
||||||
onClick={() => {
|
|
||||||
field.push({
|
|
||||||
id: uid(),
|
|
||||||
type: 'string',
|
|
||||||
interface: 'string',
|
|
||||||
name: uid(),
|
|
||||||
});
|
|
||||||
console.log('field.value', field.value);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
新增
|
新增
|
||||||
</Button>
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -9,18 +9,26 @@ group:
|
|||||||
path: /client/components
|
path: /client/components
|
||||||
---
|
---
|
||||||
|
|
||||||
# Table - 表格
|
### Table.View
|
||||||
|
|
||||||
|
只做数据展示,不能用作表单字段
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
import Editor from '@monaco-editor/react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { observer } from '@formily/react';
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
name: `t_${uid()}`,
|
name: `t_${uid()}`,
|
||||||
type: 'array',
|
type: 'void',
|
||||||
'x-component': 'Table',
|
'x-component': 'Table.View',
|
||||||
default: [{ field1: 'a1', field2: 'b1' }, { field1: 'a2', field2: 'b2' }],
|
// default: [
|
||||||
|
// { key: uid(), field1: 'a1', field2: 'b1' },
|
||||||
|
// { key: uid(), field1: 'a2', field2: 'b2' },
|
||||||
|
// ],
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
properties: {
|
properties: {
|
||||||
[`a_${uid()}`]: {
|
[`a_${uid()}`]: {
|
||||||
@ -28,17 +36,64 @@ const schema = {
|
|||||||
'x-component': 'Table.ActionBar',
|
'x-component': 'Table.ActionBar',
|
||||||
properties: {
|
properties: {
|
||||||
action1: {
|
action1: {
|
||||||
type: 'object',
|
type: 'void',
|
||||||
title: '按钮1',
|
name: 'action1',
|
||||||
'x-component': 'Table.BulkAction.Popover',
|
title: '筛选',
|
||||||
|
'x-component': 'Action',
|
||||||
|
properties: {
|
||||||
|
popover1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '弹窗标题',
|
||||||
|
'x-component': 'Action.Popover',
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
properties: {},
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
action2: {
|
action2: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '按钮2',
|
name: 'action1',
|
||||||
'x-component': 'Table.BulkAction',
|
title: '新增',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-designable-bar': 'Action.DesignableBar',
|
||||||
|
properties: {
|
||||||
|
drawer1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '抽屉标题',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '提交',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
'useAction': '{{ useTableCreateAction }}'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action3: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '删除',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
'useAction': '{{ useTableDestroyAction }}'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -65,8 +120,6 @@ const schema = {
|
|||||||
'x-component': 'Table.Column',
|
'x-component': 'Table.Column',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
title: 'z1',
|
title: 'z1',
|
||||||
width: 100,
|
|
||||||
// DesignableBar: 'Table.Column.DesignableBar',
|
|
||||||
},
|
},
|
||||||
'x-designable-bar': 'Table.Column.DesignableBar',
|
'x-designable-bar': 'Table.Column.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
@ -101,9 +154,172 @@ const schema = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
const form = createForm();
|
||||||
|
|
||||||
|
export default observer(() => {
|
||||||
return (
|
return (
|
||||||
<SchemaRenderer schema={schema} />
|
<div>
|
||||||
);
|
<SchemaRenderer form={form} schema={schema} />
|
||||||
};
|
<Editor
|
||||||
|
height="200px"
|
||||||
|
defaultLanguage="json"
|
||||||
|
value={JSON.stringify(form.values, null, 2)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Table.Field
|
||||||
|
|
||||||
|
可用作表单字段
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaRenderer } from '../';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import Editor from '@monaco-editor/react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { observer } from '@formily/react';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
name: `t_${uid()}`,
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'Table.Field',
|
||||||
|
// default: [
|
||||||
|
// { key: uid(), field1: 'a1', field2: 'b1' },
|
||||||
|
// { key: uid(), field1: 'a2', field2: 'b2' },
|
||||||
|
// ],
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
[`a_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Table.ActionBar',
|
||||||
|
properties: {
|
||||||
|
action1: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '筛选',
|
||||||
|
'x-component': 'Action',
|
||||||
|
properties: {
|
||||||
|
popover1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '弹窗标题',
|
||||||
|
'x-component': 'Action.Popover',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '新增',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-designable-bar': 'Action.DesignableBar',
|
||||||
|
properties: {
|
||||||
|
drawer1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '抽屉标题',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
action2: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '提交',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action3: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: '删除',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[`a_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Table.ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
align: 'bottom',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
pagination: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Table.Pagination',
|
||||||
|
'x-component-props': {
|
||||||
|
defaultCurrent: 1,
|
||||||
|
total: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[`c_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
title: '字段1',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: 'z1',
|
||||||
|
},
|
||||||
|
'x-designable-bar': 'Table.Column.DesignableBar',
|
||||||
|
properties: {
|
||||||
|
field1: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-decorator-props': {
|
||||||
|
feedbackLayout: 'popover',
|
||||||
|
},
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[`c_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
title: '字段2',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
properties: {
|
||||||
|
field2: {
|
||||||
|
type: 'string',
|
||||||
|
title: '字段2',
|
||||||
|
required: true,
|
||||||
|
'x-decorator-props': {
|
||||||
|
feedbackLayout: 'popover',
|
||||||
|
},
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = createForm();
|
||||||
|
|
||||||
|
export default observer(() => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SchemaRenderer form={form} schema={schema} />
|
||||||
|
<Editor
|
||||||
|
height="200px"
|
||||||
|
defaultLanguage="json"
|
||||||
|
value={JSON.stringify(form.values, null, 2)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
});
|
||||||
```
|
```
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
Schema,
|
Schema,
|
||||||
@ -6,13 +6,18 @@ import {
|
|||||||
RecursionField,
|
RecursionField,
|
||||||
useField,
|
useField,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Table as AntdTable } from 'antd';
|
import { Button, Pagination, Space, Table as AntdTable } from 'antd';
|
||||||
import { DesignableBar } from './DesignableBar';
|
import { DesignableBar } from './DesignableBar';
|
||||||
import { ColumnDesignableBar } from './ColumnDesignableBar';
|
import { ColumnDesignableBar } from './ColumnDesignableBar';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import useRequest from '@ahooksjs/use-request';
|
||||||
|
import constate from 'constate';
|
||||||
|
import { SchemaRenderer } from '../';
|
||||||
|
import { useVisibleContext } from '../action';
|
||||||
|
|
||||||
function useTableColumns(props) {
|
function useTableColumns(props?: any) {
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const { dataSource } = props;
|
const { dataSource } = props || {};
|
||||||
|
|
||||||
function findColumns(schema: Schema): Schema[] {
|
function findColumns(schema: Schema): Schema[] {
|
||||||
return schema.reduceProperties((columns, current) => {
|
return schema.reduceProperties((columns, current) => {
|
||||||
@ -29,14 +34,14 @@ function useTableColumns(props) {
|
|||||||
title: item.title,
|
title: item.title,
|
||||||
dataIndex: item.name,
|
dataIndex: item.name,
|
||||||
...columnProps,
|
...columnProps,
|
||||||
render(value, record) {
|
render(value, record, index) {
|
||||||
console.log({ item });
|
// console.log({ item });
|
||||||
const index = dataSource.indexOf(record);
|
// const index = dataSource.indexOf(record);
|
||||||
item.mapProperties((s) => {
|
item.mapProperties((s) => {
|
||||||
s['title'] = undefined;
|
s['title'] = undefined;
|
||||||
s['x-read-pretty'] = true;
|
s['x-read-pretty'] = true;
|
||||||
return s;
|
return s;
|
||||||
})
|
});
|
||||||
return (
|
return (
|
||||||
<RecursionField schema={item} name={index} onlyRenderProperties />
|
<RecursionField schema={item} name={index} onlyRenderProperties />
|
||||||
);
|
);
|
||||||
@ -74,35 +79,200 @@ function useTableActionBars() {
|
|||||||
return findActionBars(schema);
|
return findActionBars(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useTableDetails() {
|
function useTable() {
|
||||||
const schema = useFieldSchema();
|
const field = useField<Formily.Core.Models.ArrayField>();
|
||||||
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
function findDetails(schema: Schema) {
|
const response = useRequest<any>(
|
||||||
return schema.reduceProperties((items, current) => {
|
() => {
|
||||||
if (current['x-component'] === 'Table.Details') {
|
return new Promise((resolve) => {
|
||||||
return [...items, current];
|
console.log('useRequest');
|
||||||
}
|
setTimeout(() => {
|
||||||
return [...items, ...findDetails(current)];
|
resolve([
|
||||||
}, []);
|
{ key: uid(), field1: uid(), field2: uid() },
|
||||||
|
{ key: uid(), field1: uid(), field2: uid() },
|
||||||
|
]);
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess(data) {
|
||||||
|
field.setValue(data);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
selectedRowKeys,
|
||||||
|
setSelectedRowKeys,
|
||||||
|
mutate: response.mutate,
|
||||||
|
response,
|
||||||
|
async create() {
|
||||||
|
response.refresh()
|
||||||
|
},
|
||||||
|
async update() {
|
||||||
|
response.refresh()
|
||||||
|
},
|
||||||
|
async destroy() {
|
||||||
|
response.refresh()
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findDetails(schema);
|
const [TableContextProvider, useTableContext] = constate(useTable);
|
||||||
|
|
||||||
|
export function useTableCreateAction() {
|
||||||
|
const { visible, setVisible } = useVisibleContext()
|
||||||
|
const { create } = useTableContext();
|
||||||
|
return {
|
||||||
|
run: async () => {
|
||||||
|
setVisible(false);
|
||||||
|
await create();
|
||||||
|
console.log({ visible })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTableDestroyAction() {
|
||||||
|
// const { setVisible } = useVisibleContext()
|
||||||
|
const { destroy } = useTableContext();
|
||||||
|
return {
|
||||||
|
run: async () => {
|
||||||
|
// setVisible(false);
|
||||||
|
await destroy();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ArrayTable = (props) => {
|
||||||
|
const field = useField<Formily.Core.Models.ArrayField>();
|
||||||
|
// const dataSource = Array.isArray(field.value) ? field.value.slice() : [];
|
||||||
|
const columns = useTableColumns();
|
||||||
|
const actionBars = useTableActionBars();
|
||||||
|
const {
|
||||||
|
selectedRowKeys,
|
||||||
|
setSelectedRowKeys,
|
||||||
|
response = {},
|
||||||
|
create,
|
||||||
|
} = useTableContext();
|
||||||
|
console.log({ response });
|
||||||
|
const { data = [], loading, mutate } = response as any;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{actionBars.top.map((actionBarSchema) => {
|
||||||
|
return (
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
schema={
|
||||||
|
new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[actionBarSchema.name]: actionBarSchema,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
create();
|
||||||
|
// field.unshift({ key: uid(), field1: uid(), field2: uid() });
|
||||||
|
// const dataSource = Array.isArray(field.value)
|
||||||
|
// ? field.value.slice()
|
||||||
|
// : [];
|
||||||
|
// mutate(dataSource);
|
||||||
|
// response.refresh();
|
||||||
|
// console.log({ selectedRowKeys })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</Button>
|
||||||
|
<AntdTable
|
||||||
|
rowKey={'key'}
|
||||||
|
loading={loading}
|
||||||
|
pagination={false}
|
||||||
|
columns={columns}
|
||||||
|
dataSource={data}
|
||||||
|
rowSelection={{
|
||||||
|
type: 'checkbox',
|
||||||
|
selectedRowKeys,
|
||||||
|
onChange: (keys) => {
|
||||||
|
setSelectedRowKeys(keys);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{actionBars.bottom.map((actionBarSchema) => {
|
||||||
|
return (
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
schema={
|
||||||
|
new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[actionBarSchema.name]: actionBarSchema,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Table: any = observer((props) => {
|
export const Table: any = observer((props) => {
|
||||||
const field = useField<Formily.Core.Models.ArrayField>();
|
|
||||||
const dataSource = field.value;
|
|
||||||
const columns = useTableColumns({ dataSource });
|
|
||||||
const actionBars = useTableActionBars();
|
|
||||||
const details = useTableDetails();
|
|
||||||
console.log({ columns, actionBars, details });
|
|
||||||
return (
|
return (
|
||||||
<>
|
<TableContextProvider>
|
||||||
<AntdTable columns={columns} dataSource={dataSource} />
|
<ArrayTable {...props} />
|
||||||
</>
|
</TableContextProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Table.Column = () => null;
|
Table.Column = () => null;
|
||||||
Table.Column.DesignableBar = ColumnDesignableBar;
|
|
||||||
Table.DesignableBar = DesignableBar;
|
Table.ActionBar = observer((props) => {
|
||||||
|
return (
|
||||||
|
<div className={'action-bar'}>
|
||||||
|
<Space>{props.children}</Space>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.Pagination = observer((props) => {
|
||||||
|
const { response } = useTableContext();
|
||||||
|
return (
|
||||||
|
<Pagination
|
||||||
|
{...props}
|
||||||
|
onChange={(page, pageSize) => {
|
||||||
|
response.refresh();
|
||||||
|
// console.log('useRequest', { page, pageSize });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.View = observer(() => {
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
console.log('Table.View', schema);
|
||||||
|
return (
|
||||||
|
<SchemaRenderer
|
||||||
|
schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[schema.name]: {
|
||||||
|
...schema.toJSON(),
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'Table.Field',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.Field = observer((props) => {
|
||||||
|
return (
|
||||||
|
<TableContextProvider>
|
||||||
|
<ArrayTable {...props} />
|
||||||
|
</TableContextProvider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user