updates
This commit is contained in:
parent
c9aa381045
commit
78740f9905
56
packages/client/src/components/admin-layout/datatable.ts
Normal file
56
packages/client/src/components/admin-layout/datatable.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
export const schema = {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
// title: 'ModalForm',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'DatabaseOutlined',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
modal1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '对话框标题',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
title: '数据表名称',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
type: 'array',
|
||||||
|
title: '字段',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'DatabaseField',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
interface: 'string',
|
||||||
|
dataType: 'string',
|
||||||
|
name: 'title',
|
||||||
|
ui: {
|
||||||
|
title: '标题',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
dataType: 'text',
|
||||||
|
interface: 'textarea',
|
||||||
|
name: 'content',
|
||||||
|
ui: {
|
||||||
|
title: '内容',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default schema;
|
@ -21,6 +21,10 @@ import { SchemaRenderer } from '../../schemas';
|
|||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import datatable from './datatable';
|
||||||
|
|
||||||
function LayoutWithMenu({ schema }) {
|
function LayoutWithMenu({ schema }) {
|
||||||
const match = useRouteMatch<any>();
|
const match = useRouteMatch<any>();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@ -33,7 +37,7 @@ function LayoutWithMenu({ schema }) {
|
|||||||
console.log({ match });
|
console.log({ match });
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Header>
|
<Layout.Header style={{ display: 'flex' }}>
|
||||||
<SchemaRenderer
|
<SchemaRenderer
|
||||||
schema={schema}
|
schema={schema}
|
||||||
scope={{
|
scope={{
|
||||||
@ -42,6 +46,7 @@ function LayoutWithMenu({ schema }) {
|
|||||||
selectedKeys: [activeKey].filter(Boolean),
|
selectedKeys: [activeKey].filter(Boolean),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<SchemaRenderer schema={datatable} />
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Sider
|
<Layout.Sider
|
||||||
@ -59,7 +64,7 @@ function LayoutWithMenu({ schema }) {
|
|||||||
|
|
||||||
function Content({ activeKey }) {
|
function Content({ activeKey }) {
|
||||||
const { data = {}, loading } = useRequest(
|
const { data = {}, loading } = useRequest(
|
||||||
`ui_schemas:getTree/${activeKey}?filter[parentId]=${activeKey}`,
|
`ui_schemas:getTree?filter[parentKey]=${activeKey}`,
|
||||||
{
|
{
|
||||||
refreshDeps: [activeKey],
|
refreshDeps: [activeKey],
|
||||||
formatResult: (result) => result?.data,
|
formatResult: (result) => result?.data,
|
||||||
@ -70,7 +75,31 @@ function Content({ activeKey }) {
|
|||||||
return <Spin />;
|
return <Spin />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <SchemaRenderer schema={data} />;
|
const schema: ISchema = {
|
||||||
|
type: 'void',
|
||||||
|
name: uid(),
|
||||||
|
'x-component': 'Grid',
|
||||||
|
properties: {
|
||||||
|
[`row_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
properties: {
|
||||||
|
[`col_${uid()}`]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AddNew.BlockItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return <SchemaRenderer schema={schema} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminLayout({ route }: any) {
|
export function AdminLayout({ route }: any) {
|
||||||
|
@ -6,6 +6,10 @@ import { SchemaRenderer } from '../../schemas';
|
|||||||
import { useForm } from '@formily/react';
|
import { useForm } from '@formily/react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
|
function Div(props) {
|
||||||
|
return <div {...props}></div>
|
||||||
|
}
|
||||||
|
|
||||||
export function useLogin() {
|
export function useLogin() {
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -41,7 +45,7 @@ export function RouteSchemaRenderer({ route }) {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SchemaRenderer scope={{ useLogin, useRegister }} schema={data} />
|
<SchemaRenderer components={{ Div }} scope={{ useLogin, useRegister }} schema={data} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,8 @@ export function useDesignable(path?: any) {
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const currentSchema =
|
const currentSchema =
|
||||||
findPropertyByPath(schema, schemaPath) || ({} as Schema);
|
findPropertyByPath(schema, schemaPath) || ({} as Schema);
|
||||||
console.log({ currentSchema })
|
console.log({ currentSchema });
|
||||||
// console.log('useDesignable', { schema, schemaPath, currentSchema });
|
// console.log('useDesignable', { schema, schemaPath, currentSchema });
|
||||||
const options = useContext(SchemaOptionsContext);
|
const options = useContext(SchemaOptionsContext);
|
||||||
const DesignableBar =
|
const DesignableBar =
|
||||||
get(options.components, currentSchema['x-designable-bar']) || (() => null);
|
get(options.components, currentSchema['x-designable-bar']) || (() => null);
|
||||||
@ -184,6 +184,9 @@ export function useDesignable(path?: any) {
|
|||||||
}
|
}
|
||||||
if (target['key']) {
|
if (target['key']) {
|
||||||
property['parentKey'] = target['key'];
|
property['parentKey'] = target['key'];
|
||||||
|
if (!property['key']) {
|
||||||
|
property['key'] = uid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const properties = {};
|
const properties = {};
|
||||||
properties[property.name] = property;
|
properties[property.name] = property;
|
||||||
@ -211,6 +214,9 @@ export function useDesignable(path?: any) {
|
|||||||
}
|
}
|
||||||
if (target['key']) {
|
if (target['key']) {
|
||||||
property['parentKey'] = target['key'];
|
property['parentKey'] = target['key'];
|
||||||
|
if (!property['key']) {
|
||||||
|
property['key'] = uid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
target.addProperty(property.name, property);
|
target.addProperty(property.name, property);
|
||||||
// BUG: 空 properties 时,addProperty 无反应。
|
// BUG: 空 properties 时,addProperty 无反应。
|
||||||
@ -232,8 +238,12 @@ export function useDesignable(path?: any) {
|
|||||||
if (!property.name) {
|
if (!property.name) {
|
||||||
property.name = uid();
|
property.name = uid();
|
||||||
}
|
}
|
||||||
|
console.log('target.parentKey', target);
|
||||||
if (target['parentKey']) {
|
if (target['parentKey']) {
|
||||||
property['parentKey'] = target['parentKey'];
|
property['parentKey'] = target['parentKey'];
|
||||||
|
if (!property['key']) {
|
||||||
|
property['key'] = uid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addPropertyAfter(target, property);
|
addPropertyAfter(target, property);
|
||||||
refresh();
|
refresh();
|
||||||
@ -253,6 +263,9 @@ export function useDesignable(path?: any) {
|
|||||||
}
|
}
|
||||||
if (target['parentKey']) {
|
if (target['parentKey']) {
|
||||||
property['parentKey'] = target['parentKey'];
|
property['parentKey'] = target['parentKey'];
|
||||||
|
if (!property['key']) {
|
||||||
|
property['key'] = uid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addPropertyBefore(target, property);
|
addPropertyBefore(target, property);
|
||||||
refresh();
|
refresh();
|
||||||
|
@ -18,9 +18,11 @@ import './style.less';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
import { MenuOutlined } from '@ant-design/icons';
|
||||||
|
import { FormLayout } from '@formily/antd';
|
||||||
|
import IconPicker from '../../components/icon-picker';
|
||||||
|
|
||||||
export const Action: any = observer((props: any) => {
|
export const Action: any = observer((props: any) => {
|
||||||
const { useAction = useDefaultAction, ...others } = props;
|
const { useAction = useDefaultAction, icon, ...others } = props;
|
||||||
const { run } = useAction();
|
const { run } = useAction();
|
||||||
const { schema, DesignableBar } = useDesignable();
|
const { schema, DesignableBar } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
@ -28,12 +30,13 @@ export const Action: any = observer((props: any) => {
|
|||||||
const isDropdownOrPopover =
|
const isDropdownOrPopover =
|
||||||
child &&
|
child &&
|
||||||
['Action.Dropdown', 'Action.Popover'].includes(child['x-component']);
|
['Action.Dropdown', 'Action.Popover'].includes(child['x-component']);
|
||||||
console.log({ DesignableBar, schema })
|
console.log({ DesignableBar, schema });
|
||||||
return (
|
return (
|
||||||
<VisibleContext.Provider value={[visible, setVisible]}>
|
<VisibleContext.Provider value={[visible, setVisible]}>
|
||||||
{!isDropdownOrPopover && (
|
{!isDropdownOrPopover && (
|
||||||
<Button
|
<Button
|
||||||
{...others}
|
{...others}
|
||||||
|
icon={<IconPicker type={icon} />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
await run();
|
await run();
|
||||||
@ -48,10 +51,31 @@ export const Action: any = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Action.Link = observer((props: any) => {
|
||||||
|
const { schema } = useDesignable();
|
||||||
|
return <Link {...props}>{schema.title}</Link>;
|
||||||
|
});
|
||||||
|
|
||||||
|
Action.URL = observer((props: any) => {
|
||||||
|
const { schema } = useDesignable();
|
||||||
|
return (
|
||||||
|
<a target={'_blank'} {...props}>
|
||||||
|
{schema.title}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Action.Modal = observer((props: any) => {
|
Action.Modal = observer((props: any) => {
|
||||||
|
const {
|
||||||
|
useOkAction = useDefaultAction,
|
||||||
|
useCancelAction = useDefaultAction,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
const [visible, setVisible] = useContext(VisibleContext);
|
const [visible, setVisible] = useContext(VisibleContext);
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
|
const { run: runOk } = useOkAction();
|
||||||
|
const { run: runCancel } = useCancelAction();
|
||||||
const isFormDecorator = schema['x-decorator'] === 'Form';
|
const isFormDecorator = schema['x-decorator'] === 'Form';
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -66,6 +90,7 @@ Action.Modal = observer((props: any) => {
|
|||||||
if (isFormDecorator) {
|
if (isFormDecorator) {
|
||||||
form.clearErrors();
|
form.clearErrors();
|
||||||
}
|
}
|
||||||
|
runCancel && (await runCancel());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -77,6 +102,7 @@ Action.Modal = observer((props: any) => {
|
|||||||
if (isFormDecorator) {
|
if (isFormDecorator) {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
}
|
}
|
||||||
|
runOk && (await runOk());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -85,24 +111,32 @@ Action.Modal = observer((props: any) => {
|
|||||||
]
|
]
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
{...props}
|
{...others}
|
||||||
onCancel={() => {
|
onCancel={async () => {
|
||||||
if (isFormDecorator) {
|
if (isFormDecorator) {
|
||||||
form.clearErrors();
|
form.clearErrors();
|
||||||
}
|
}
|
||||||
|
runCancel && (await runCancel());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
>
|
>
|
||||||
{props.children}
|
<FormLayout layout={'vertical'}>{props.children}</FormLayout>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Action.Drawer = observer((props: any) => {
|
Action.Drawer = observer((props: any) => {
|
||||||
|
const {
|
||||||
|
useOkAction = useDefaultAction,
|
||||||
|
useCancelAction = useDefaultAction,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
const [visible, setVisible] = useContext(VisibleContext);
|
const [visible, setVisible] = useContext(VisibleContext);
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
|
const { run: runOk } = useOkAction();
|
||||||
|
const { run: runCancel } = useCancelAction();
|
||||||
const isFormDecorator = schema['x-decorator'] === 'Form';
|
const isFormDecorator = schema['x-decorator'] === 'Form';
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
@ -117,6 +151,7 @@ Action.Drawer = observer((props: any) => {
|
|||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
form.clearErrors();
|
form.clearErrors();
|
||||||
props.onClose && (await props.onClose(e));
|
props.onClose && (await props.onClose(e));
|
||||||
|
runCancel && (await runCancel());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -126,6 +161,7 @@ Action.Drawer = observer((props: any) => {
|
|||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
props.onOk && (await props.onOk(e));
|
props.onOk && (await props.onOk(e));
|
||||||
|
runOk && (await runOk());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
type={'primary'}
|
type={'primary'}
|
||||||
@ -135,14 +171,15 @@ Action.Drawer = observer((props: any) => {
|
|||||||
</Space>
|
</Space>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{...props}
|
{...others}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onClose={async (e) => {
|
onClose={async (e) => {
|
||||||
props.onClose && (await props.onClose(e));
|
props.onClose && (await props.onClose(e));
|
||||||
|
runCancel && (await runCancel());
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
<FormLayout layout={'vertical'}>{props.children}</FormLayout>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -264,4 +301,4 @@ Action.DesignableBar = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
44
packages/client/src/schemas/database-field/demos/demo1.tsx
Normal file
44
packages/client/src/schemas/database-field/demos/demo1.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { SchemaRenderer } from '../../';
|
||||||
|
import { observer, connect, useField } from '@formily/react';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
fields: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'DatabaseField',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
interface: 'string',
|
||||||
|
dataType: 'string',
|
||||||
|
name: 'title',
|
||||||
|
ui: {
|
||||||
|
title: '标题',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
dataType: 'text',
|
||||||
|
interface: 'textarea',
|
||||||
|
name: 'content',
|
||||||
|
ui: {
|
||||||
|
title: '内容',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = createForm();
|
||||||
|
|
||||||
|
export default observer(() => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SchemaRenderer form={form} schema={schema} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
63
packages/client/src/schemas/database-field/demos/demo2.tsx
Normal file
63
packages/client/src/schemas/database-field/demos/demo2.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { SchemaRenderer } from '../../';
|
||||||
|
import { observer, connect, useField } from '@formily/react';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'void',
|
||||||
|
name: 'action1',
|
||||||
|
title: 'ModalForm',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
modal1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '对话框标题',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
title: '数据表名称',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'DatabaseField',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
interface: 'string',
|
||||||
|
dataType: 'string',
|
||||||
|
name: 'title',
|
||||||
|
ui: {
|
||||||
|
title: '标题',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
dataType: 'text',
|
||||||
|
interface: 'textarea',
|
||||||
|
name: 'content',
|
||||||
|
ui: {
|
||||||
|
title: '内容',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = createForm();
|
||||||
|
|
||||||
|
export default observer(() => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SchemaRenderer form={form} schema={schema} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -23,53 +23,6 @@ group:
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
```tsx
|
<code src="./demos/demo1.tsx"/>
|
||||||
import React from 'react';
|
|
||||||
import { createForm } from '@formily/core';
|
|
||||||
import { SchemaRenderer } from '../';
|
|
||||||
import { observer, connect, useField } from '@formily/react';
|
|
||||||
|
|
||||||
const schema = {
|
<code src="./demos/demo2.tsx"/>
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
array: {
|
|
||||||
type: 'array',
|
|
||||||
'x-component': 'DatabaseField',
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
interface: 'string',
|
|
||||||
dataType: 'string',
|
|
||||||
name: 'title',
|
|
||||||
ui: {
|
|
||||||
title: '标题',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
dataType: 'text',
|
|
||||||
interface: 'textarea',
|
|
||||||
name: 'content',
|
|
||||||
ui: {
|
|
||||||
title: '内容',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// input: {
|
|
||||||
// type: 'string',
|
|
||||||
// 'x-component': 'Input',
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const form = createForm();
|
|
||||||
|
|
||||||
export default observer(() => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SchemaRenderer form={form} schema={schema} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
@ -26,16 +26,19 @@ export const Form: any = observer((props: any) => {
|
|||||||
}, []);
|
}, []);
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
const path = useSchemaPath();
|
const path = useSchemaPath();
|
||||||
|
const scope = useContext(SchemaExpressionScopeContext);
|
||||||
return (
|
return (
|
||||||
<FormProvider form={form}>
|
<FormProvider form={form}>
|
||||||
{schema['x-decorator'] === 'Form' ? (
|
{schema['x-decorator'] === 'Form' ? (
|
||||||
<SchemaField
|
<SchemaField
|
||||||
|
scope={scope}
|
||||||
schema={{
|
schema={{
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
[schema.name]: {
|
[schema.name]: {
|
||||||
...schema.toJSON(),
|
...schema.toJSON(),
|
||||||
'x-path': path,
|
'x-path': path,
|
||||||
|
// 避免死循环
|
||||||
'x-decorator': 'Form.__Decorator',
|
'x-decorator': 'Form.__Decorator',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -44,6 +47,7 @@ export const Form: any = observer((props: any) => {
|
|||||||
) : (
|
) : (
|
||||||
<FormLayout layout={'vertical'} {...others}>
|
<FormLayout layout={'vertical'} {...others}>
|
||||||
<SchemaField
|
<SchemaField
|
||||||
|
scope={scope}
|
||||||
schema={{
|
schema={{
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: schema.properties,
|
properties: schema.properties,
|
||||||
|
@ -9,3 +9,10 @@ export function useDefaultAction() {
|
|||||||
async run () {}
|
async run () {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { extend } from 'umi-request';
|
||||||
|
|
||||||
|
export const request = extend({
|
||||||
|
prefix: 'http://localhost:23003/api/',
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer } from '@nocobase/client';
|
import { SchemaRenderer } from '@nocobase/client';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
|
||||||
const schema = {
|
const schema: ISchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
menu1: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Menu',
|
'x-component': 'Menu',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
@ -16,37 +18,46 @@ const schema = {
|
|||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
item1: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `菜单1`,
|
title: `菜单1`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item2: {
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
title: `链接`,
|
||||||
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
|
'x-component': 'Menu.Link',
|
||||||
|
"x-component-props": {
|
||||||
|
to: '/abc/def',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `菜单2`,
|
title: `菜单2`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item3: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '菜单组3',
|
title: '菜单组3',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item5: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单5`,
|
title: `子菜单5`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item8: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单8`,
|
title: `子菜单8`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item9: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单9`,
|
title: `子菜单9`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
@ -56,19 +67,19 @@ const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
item4: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '菜单组4',
|
title: '菜单组4',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item6: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单6`,
|
title: `子菜单6`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item7: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单7`,
|
title: `子菜单7`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { SchemaRenderer } from '@nocobase/client';
|
import { SchemaRenderer } from '@nocobase/client';
|
||||||
import { Layout } from 'antd';
|
import { Layout } from 'antd';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
menu1: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Menu',
|
'x-component': 'Menu',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
@ -15,37 +16,37 @@ const schema = {
|
|||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
item1: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `菜单1`,
|
title: `菜单1`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item2: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `菜单2`,
|
title: `菜单2`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item3: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '菜单组3',
|
title: '菜单组3',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item5: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单5`,
|
title: `子菜单5`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item8: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单8`,
|
title: `子菜单8`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item9: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单9`,
|
title: `子菜单9`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
@ -55,19 +56,19 @@ const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
item4: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '菜单组4',
|
title: '菜单组4',
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
properties: {
|
properties: {
|
||||||
item6: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单6`,
|
title: `子菜单6`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
},
|
},
|
||||||
item7: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: `子菜单7`,
|
title: `子菜单7`,
|
||||||
'x-designable-bar': 'Menu.DesignableBar',
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
@ -86,6 +87,7 @@ export default () => {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Header>
|
<Layout.Header>
|
||||||
<SchemaRenderer
|
<SchemaRenderer
|
||||||
|
debug={true}
|
||||||
scope={{ sideMenuRef }}
|
scope={{ sideMenuRef }}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
/>
|
/>
|
||||||
|
@ -33,16 +33,21 @@ import {
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { useDesignable } from '../../components/schema-renderer';
|
import { useDesignable } from '../../components/schema-renderer';
|
||||||
import { MenuOutlined } from '@ant-design/icons';
|
import { MenuOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { IconPicker } from '../../components/icon-picker';
|
import { IconPicker } from '../../components/icon-picker';
|
||||||
import { VisibleContext } from '..';
|
import { useDefaultAction, VisibleContext } from '..';
|
||||||
import { useMount } from 'ahooks';
|
import { useMount } from 'ahooks';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useSchemaPath } from '@nocobase/client/lib';
|
||||||
|
import { request } from '../';
|
||||||
|
|
||||||
export const MenuModeContext = createContext(null);
|
export const MenuModeContext = createContext(null);
|
||||||
|
|
||||||
|
function useSelectedKey() {}
|
||||||
|
|
||||||
const SideMenu = (props: any) => {
|
const SideMenu = (props: any) => {
|
||||||
const { visible, selectedKey, onSelect } = props;
|
const { visible, selectedKey, onSelect, path } = props;
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
if (!selectedKey || !visible) {
|
if (!selectedKey || !visible) {
|
||||||
return null;
|
return null;
|
||||||
@ -53,10 +58,16 @@ const SideMenu = (props: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AntdMenu mode={'inline'} onSelect={onSelect}>
|
<MenuModeContext.Provider value={'inline'}>
|
||||||
<RecursionField schema={child} onlyRenderProperties />
|
<AntdMenu mode={'inline'} onSelect={onSelect}>
|
||||||
<AntdMenu.Item key={uid()}>{selectedKey}</AntdMenu.Item>
|
<RecursionField schema={child} onlyRenderProperties />
|
||||||
</AntdMenu>
|
<Menu.AddNew key={uid()} path={[...path, selectedKey]}>
|
||||||
|
<Button block type={'dashed'}>
|
||||||
|
<PlusOutlined className={'nb-add-new-icon'} />
|
||||||
|
</Button>
|
||||||
|
</Menu.AddNew>
|
||||||
|
</AntdMenu>
|
||||||
|
</MenuModeContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +76,9 @@ export const Menu: any = observer((props: any) => {
|
|||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
const [selectedKey, setSelectedKey] = useState(null);
|
const [selectedKey, setSelectedKey] = useState(null);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
const path = useSchemaPath();
|
||||||
|
const child = schema.properties && schema.properties[selectedKey];
|
||||||
|
const isSubMenu = child && child['x-component'] === 'Menu.SubMenu';
|
||||||
|
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
if (mode !== 'mix') {
|
if (mode !== 'mix') {
|
||||||
@ -74,8 +88,17 @@ export const Menu: any = observer((props: any) => {
|
|||||||
if (sideMenuElement && ref.current) {
|
if (sideMenuElement && ref.current) {
|
||||||
sideMenuElement.querySelector(':scope > div').appendChild(ref.current);
|
sideMenuElement.querySelector(':scope > div').appendChild(ref.current);
|
||||||
}
|
}
|
||||||
|
sideMenuElement.style.display = isSubMenu ? 'block' : 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const sideMenuElement = sideMenuRef && (sideMenuRef.current as HTMLElement);
|
||||||
|
if (!sideMenuElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sideMenuElement.style.display = isSubMenu ? 'block' : 'none';
|
||||||
|
}, [selectedKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuModeContext.Provider value={mode}>
|
<MenuModeContext.Provider value={mode}>
|
||||||
<AntdMenu
|
<AntdMenu
|
||||||
@ -89,13 +112,14 @@ export const Menu: any = observer((props: any) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
<AntdMenu.ItemGroup title={
|
<Menu.AddNew key={uid()} path={path}>
|
||||||
<div>新增</div>
|
<PlusOutlined className={'nb-add-new-icon'} />
|
||||||
}></AntdMenu.ItemGroup>
|
</Menu.AddNew>
|
||||||
</AntdMenu>
|
</AntdMenu>
|
||||||
{mode === 'mix' && (
|
{mode === 'mix' && (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
<SideMenu
|
<SideMenu
|
||||||
|
path={path}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
visible={mode === 'mix'}
|
visible={mode === 'mix'}
|
||||||
selectedKey={selectedKey}
|
selectedKey={selectedKey}
|
||||||
@ -107,6 +131,62 @@ export const Menu: any = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Menu.AddNew = observer((props: any) => {
|
||||||
|
const { appendChild } = useDesignable(props.path);
|
||||||
|
return (
|
||||||
|
<AntdMenu.ItemGroup
|
||||||
|
className={'nb-menu-add-new'}
|
||||||
|
title={
|
||||||
|
<Dropdown
|
||||||
|
overlay={
|
||||||
|
<AntdMenu>
|
||||||
|
<AntdMenu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const data = appendChild({
|
||||||
|
type: 'void',
|
||||||
|
title: uid(),
|
||||||
|
'x-component': 'Menu.Item',
|
||||||
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
|
});
|
||||||
|
if (data['key']) {
|
||||||
|
await request('ui_schemas:create', {
|
||||||
|
method: 'post',
|
||||||
|
data: data.toJSON(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新建菜单
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const data = appendChild({
|
||||||
|
type: 'void',
|
||||||
|
key: uid(),
|
||||||
|
title: uid(),
|
||||||
|
'x-component': 'Menu.SubMenu',
|
||||||
|
'x-designable-bar': 'Menu.DesignableBar',
|
||||||
|
});
|
||||||
|
if (data['key']) {
|
||||||
|
await request('ui_schemas:create', {
|
||||||
|
method: 'post',
|
||||||
|
data: data.toJSON(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新建菜单组
|
||||||
|
</AntdMenu.Item>
|
||||||
|
</AntdMenu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<a>{props.children}</a>
|
||||||
|
</Dropdown>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Menu.Divider = observer(AntdMenu.Divider);
|
Menu.Divider = observer(AntdMenu.Divider);
|
||||||
|
|
||||||
Menu.Item = observer((props: any) => {
|
Menu.Item = observer((props: any) => {
|
||||||
@ -125,18 +205,54 @@ Menu.Item = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Menu.Action = observer((props: any) => {
|
Menu.Link = observer((props: any) => {
|
||||||
const { icon } = props;
|
const { icon } = props;
|
||||||
const { schema, DesignableBar } = useDesignable();
|
const { schema, DesignableBar } = useDesignable();
|
||||||
|
return (
|
||||||
|
<AntdMenu.Item
|
||||||
|
{...props}
|
||||||
|
icon={<IconPicker type={icon} />}
|
||||||
|
eventKey={schema.name}
|
||||||
|
key={schema.name}
|
||||||
|
>
|
||||||
|
<Link to={props.to}>{schema.title}</Link>
|
||||||
|
<DesignableBar />
|
||||||
|
</AntdMenu.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Menu.URL = observer((props: any) => {
|
||||||
|
const { icon } = props;
|
||||||
|
const { schema, DesignableBar } = useDesignable();
|
||||||
|
return (
|
||||||
|
<AntdMenu.Item
|
||||||
|
{...props}
|
||||||
|
icon={<IconPicker type={icon} />}
|
||||||
|
eventKey={schema.name}
|
||||||
|
key={schema.name}
|
||||||
|
>
|
||||||
|
<a target={'_blank'} href={props.href}>
|
||||||
|
{schema.title}
|
||||||
|
</a>
|
||||||
|
<DesignableBar />
|
||||||
|
</AntdMenu.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Menu.Action = observer((props: any) => {
|
||||||
|
const { icon, useAction = useDefaultAction, ...others } = props;
|
||||||
|
const { schema, DesignableBar } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { run } = useAction();
|
||||||
return (
|
return (
|
||||||
<VisibleContext.Provider value={[visible, setVisible]}>
|
<VisibleContext.Provider value={[visible, setVisible]}>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
{...props}
|
{...others}
|
||||||
key={schema.name}
|
key={schema.name}
|
||||||
eventKey={schema.name}
|
eventKey={schema.name}
|
||||||
icon={<IconPicker type={icon} />}
|
icon={<IconPicker type={icon} />}
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
|
await run();
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -210,37 +326,53 @@ Menu.DesignableBar = (props) => {
|
|||||||
修改标题
|
修改标题
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
const s = insertAfter({
|
const s = insertAfter({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
key: uid(),
|
|
||||||
title: uid(),
|
title: uid(),
|
||||||
'x-component': 'Menu.SubMenu',
|
'x-component': 'Menu.SubMenu',
|
||||||
});
|
});
|
||||||
|
console.log('s.s.s.s', s);
|
||||||
|
if (s['key']) {
|
||||||
|
await request('ui_schemas:create', {
|
||||||
|
method: 'post',
|
||||||
|
data: s.toJSON(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
新建分组
|
新建分组
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
const s = insertAfter({
|
const s = insertAfter({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
key: uid(),
|
|
||||||
title: uid(),
|
title: uid(),
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
});
|
});
|
||||||
|
if (s['key']) {
|
||||||
|
await request('ui_schemas:create', {
|
||||||
|
method: 'post',
|
||||||
|
data: s.toJSON(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
新建菜单
|
新建菜单
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
const s = appendChild({
|
const s = appendChild({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
key: uid(),
|
|
||||||
title: uid(),
|
title: uid(),
|
||||||
'x-component': 'Menu.Item',
|
'x-component': 'Menu.Item',
|
||||||
});
|
});
|
||||||
|
if (s['key']) {
|
||||||
|
await request('ui_schemas:create', {
|
||||||
|
method: 'post',
|
||||||
|
data: s.toJSON(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
在菜单组里新增
|
在菜单组里新增
|
||||||
|
@ -74,4 +74,17 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0 -20px;
|
margin: 0 -20px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-menu-add-new {
|
||||||
|
.ant-menu-item-group-title {
|
||||||
|
line-height: 46px;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
.nb-add-new-icon {
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
width: 46px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer } from '../..';
|
import { SchemaRenderer } from '../..';
|
||||||
import { Table } from '../';
|
import { Table, useTableCreateAction } from '../';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { createForm } from '@formily/core';
|
import { createForm } from '@formily/core';
|
||||||
import { ISchema, observer } from '@formily/react';
|
import { ISchema, observer } from '@formily/react';
|
||||||
@ -8,9 +8,9 @@ import { ISchema, observer } from '@formily/react';
|
|||||||
function useAction() {
|
function useAction() {
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
alert('自定义')
|
alert('自定义');
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
@ -93,8 +93,8 @@ const schema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -109,35 +109,23 @@ const schema: ISchema = {
|
|||||||
drawer1: {
|
drawer1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '抽屉标题',
|
title: '抽屉标题',
|
||||||
|
'x-decorator': 'Form',
|
||||||
'x-component': 'Action.Modal',
|
'x-component': 'Action.Modal',
|
||||||
'x-component-props': {},
|
'x-component-props': {
|
||||||
|
useOkAction: '{{ Table.useTableCreateAction }}',
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
field1: {
|
||||||
name: 'form',
|
type: 'string',
|
||||||
type: 'object',
|
title: '字段1',
|
||||||
'x-component': 'Form',
|
'x-decorator': 'FormItem',
|
||||||
properties: {
|
'x-component': 'Input',
|
||||||
field1: {
|
},
|
||||||
type: 'string',
|
field2: {
|
||||||
title: '字段1',
|
type: 'string',
|
||||||
'x-decorator': 'FormItem',
|
title: '字段2',
|
||||||
'x-component': 'Input',
|
'x-decorator': 'FormItem',
|
||||||
},
|
'x-component': 'Input',
|
||||||
field2: {
|
|
||||||
type: 'string',
|
|
||||||
title: '字段2',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: 'void',
|
|
||||||
title: '提交',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ Table.useTableCreateAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -154,22 +142,6 @@ const schema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// [`a_${uid()}`]: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'Table.ActionBar',
|
|
||||||
// 'x-component-props': {
|
|
||||||
// align: 'bottom',
|
|
||||||
// },
|
|
||||||
// properties: {
|
|
||||||
// pagination: {
|
|
||||||
// type: 'void',
|
|
||||||
// 'x-component': 'Table.Pagination',
|
|
||||||
// 'x-component-props': {
|
|
||||||
// defaultPageSize: 5,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
[`a_${uid()}`]: {
|
[`a_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Table.ActionBar',
|
'x-component': 'Table.ActionBar',
|
||||||
@ -256,7 +228,6 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '查看',
|
title: '查看',
|
||||||
|
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
@ -318,38 +289,26 @@ const schema: ISchema = {
|
|||||||
drawer1: {
|
drawer1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '编辑表单',
|
title: '编辑表单',
|
||||||
|
"x-decorator": 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
useValues: '{{ Table.useTableRow }}',
|
||||||
|
},
|
||||||
'x-component': 'Action.Modal',
|
'x-component': 'Action.Modal',
|
||||||
'x-component-props': {},
|
'x-component-props': {
|
||||||
|
useOkAction: '{{ Table.useTableUpdateAction }}',
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
field1: {
|
||||||
name: 'form',
|
type: 'string',
|
||||||
type: 'void',
|
title: '字段1',
|
||||||
'x-component': 'Form',
|
'x-decorator': 'FormItem',
|
||||||
'x-component-props': {
|
'x-component': 'Input',
|
||||||
useValues: '{{ Table.useTableRow }}',
|
},
|
||||||
},
|
field2: {
|
||||||
properties: {
|
type: 'string',
|
||||||
field1: {
|
title: '字段2',
|
||||||
type: 'string',
|
'x-decorator': 'FormItem',
|
||||||
title: '字段1',
|
'x-component': 'Input',
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
field2: {
|
|
||||||
type: 'string',
|
|
||||||
title: '字段2',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: 'void',
|
|
||||||
title: '提交',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ Table.useTableUpdateAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -371,7 +330,7 @@ const schema: ISchema = {
|
|||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '操作 1',
|
title: '操作 1',
|
||||||
'x-component': 'Action',
|
'x-component': 'Menu.Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction,
|
useAction,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
@ -380,7 +339,7 @@ const schema: ISchema = {
|
|||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '操作 2',
|
title: '操作 2',
|
||||||
'x-component': 'Action',
|
'x-component': 'Menu.Action',
|
||||||
'x-default-action': true,
|
'x-default-action': true,
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction,
|
useAction,
|
||||||
@ -390,8 +349,7 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '查看',
|
title: '查看',
|
||||||
'x-component': 'Action',
|
'x-component': 'Menu.Action',
|
||||||
// 'x-default-action': true,
|
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
drawer1: {
|
drawer1: {
|
||||||
@ -446,44 +404,32 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '修改',
|
title: '修改',
|
||||||
'x-component': 'Action',
|
'x-component': 'Menu.Action',
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
drawer1: {
|
drawer1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '编辑表单',
|
title: '编辑表单',
|
||||||
|
"x-decorator": 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
useValues: '{{ Table.useTableRow }}',
|
||||||
|
},
|
||||||
'x-component': 'Action.Modal',
|
'x-component': 'Action.Modal',
|
||||||
'x-component-props': {},
|
'x-component-props': {
|
||||||
|
useOkAction: '{{ Table.useTableUpdateAction }}',
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
field1: {
|
||||||
name: 'form',
|
type: 'string',
|
||||||
type: 'void',
|
title: '字段1',
|
||||||
'x-component': 'Form',
|
'x-decorator': 'FormItem',
|
||||||
'x-component-props': {
|
'x-component': 'Input',
|
||||||
useValues: '{{ Table.useTableRow }}',
|
},
|
||||||
},
|
field2: {
|
||||||
properties: {
|
type: 'string',
|
||||||
field1: {
|
title: '字段2',
|
||||||
type: 'string',
|
'x-decorator': 'FormItem',
|
||||||
title: '字段1',
|
'x-component': 'Input',
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
field2: {
|
|
||||||
type: 'string',
|
|
||||||
title: '字段2',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: 'void',
|
|
||||||
title: '提交',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ Table.useTableUpdateAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -492,7 +438,7 @@ const schema: ISchema = {
|
|||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '删除',
|
title: '删除',
|
||||||
'x-component': 'Action',
|
'x-component': 'Menu.Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction: '{{ Table.useTableDestroyAction }}',
|
useAction: '{{ Table.useTableDestroyAction }}',
|
||||||
},
|
},
|
||||||
@ -511,7 +457,7 @@ const form = createForm({
|
|||||||
export default observer(() => {
|
export default observer(() => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SchemaRenderer scope={{ Table }} form={form} schema={schema} />
|
<SchemaRenderer scope={{ Table, useTableCreateAction }} form={form} schema={schema} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -227,9 +227,11 @@ export function useTableCreateAction() {
|
|||||||
export function useTableUpdateAction() {
|
export function useTableUpdateAction() {
|
||||||
const { field, refresh, params } = useTableContext();
|
const { field, refresh, params } = useTableContext();
|
||||||
const [,setVisible] = useContext(VisibleContext);
|
const [,setVisible] = useContext(VisibleContext);
|
||||||
|
const ctx = useContext(TableRowContext);
|
||||||
const form = useForm();
|
const form = useForm();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
|
field.value[ctx.index] = form.values;
|
||||||
setVisible && setVisible(false);
|
setVisible && setVisible(false);
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
|
@ -2,14 +2,34 @@ import { Model, ModelCtor } from '@nocobase/database';
|
|||||||
import { actions } from '@nocobase/actions';
|
import { actions } from '@nocobase/actions';
|
||||||
|
|
||||||
export default async (ctx: actions.Context, next: actions.Next) => {
|
export default async (ctx: actions.Context, next: actions.Next) => {
|
||||||
const { resourceKey } = ctx.action.params;
|
const { resourceKey, filter } = ctx.action.params;
|
||||||
const UISchema = ctx.db.getModel('ui_schemas');
|
const UISchema = ctx.db.getModel('ui_schemas');
|
||||||
const schema = await UISchema.findByPk(resourceKey);
|
if (resourceKey) {
|
||||||
const property = schema.toProperty();
|
const schema = await UISchema.findByPk(resourceKey);
|
||||||
const properties = await schema.getProperties();
|
const property = schema.toProperty();
|
||||||
if (Object.keys(properties).length) {
|
const properties = await schema.getProperties();
|
||||||
property.properties = properties;
|
if (Object.keys(properties).length) {
|
||||||
|
property.properties = properties;
|
||||||
|
}
|
||||||
|
ctx.body = property;
|
||||||
|
} else {
|
||||||
|
const schemas = await UISchema.findAll(UISchema.parseApiJson({
|
||||||
|
filter,
|
||||||
|
}));
|
||||||
|
let properties = {};
|
||||||
|
for (const schema of schemas) {
|
||||||
|
const property = schema.toProperty();
|
||||||
|
const properties = await schema.getProperties();
|
||||||
|
if (Object.keys(properties).length) {
|
||||||
|
property.properties = properties;
|
||||||
|
}
|
||||||
|
properties[property.name] = property;
|
||||||
|
}
|
||||||
|
ctx.body = {
|
||||||
|
type: 'object',
|
||||||
|
properties,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.body = property;
|
|
||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export class UISchema extends Model {
|
|||||||
|
|
||||||
toProperty() {
|
toProperty() {
|
||||||
const options = this.get('options') || {};
|
const options = this.get('options') || {};
|
||||||
const data = _.omit(this.toJSON(), ['created_at', 'updated_at', 'options', 'parentKey']);
|
const data = _.omit(this.toJSON(), ['created_at', 'updated_at', 'options']);
|
||||||
return { ...data, ...options };
|
return { ...data, ...options };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user