feat: improve code
This commit is contained in:
parent
257488ebad
commit
de2b7cab75
@ -22,6 +22,7 @@ export function AdminLayout(props: any) {
|
|||||||
const [schema, setSchema] = useState({});
|
const [schema, setSchema] = useState({});
|
||||||
const onSelect = ({ item }) => {
|
const onSelect = ({ item }) => {
|
||||||
const schema = item.props.schema;
|
const schema = item.props.schema;
|
||||||
|
console.log('onSelect', schema);
|
||||||
setSchema(schema);
|
setSchema(schema);
|
||||||
setTitle(schema.title);
|
setTitle(schema.title);
|
||||||
history.push(`/admin/${schema['x-uid']}`);
|
history.push(`/admin/${schema['x-uid']}`);
|
||||||
@ -30,7 +31,7 @@ export function AdminLayout(props: any) {
|
|||||||
const result = useSystemSettings();
|
const result = useSystemSettings();
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Header style={{ position: 'relative', paddingLeft: 0 }}>
|
<Layout.Header style={{ height: 46, lineHeight: '46px', position: 'relative', paddingLeft: 0 }}>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
<div style={{ display: 'inline-flex', color: '#fff', padding: '0 24px' }}>{result?.data?.data?.title}</div>
|
<div style={{ display: 'inline-flex', color: '#fff', padding: '0 24px' }}>{result?.data?.data?.title}</div>
|
||||||
<RemoteSchemaComponent
|
<RemoteSchemaComponent
|
||||||
@ -74,7 +75,7 @@ export function AdminLayout(props: any) {
|
|||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Sider style={{ display: 'none' }} theme={'light'} ref={sideMenuRef}></Layout.Sider>
|
<Layout.Sider style={{ display: 'none' }} theme={'light'} ref={sideMenuRef}></Layout.Sider>
|
||||||
<Layout.Content>
|
<Layout.Content style={{ minHeight: 'calc(100vh - 46px)' }}>
|
||||||
<RemoteSchemaComponent onlyRenderProperties uid={match.params.name} />
|
<RemoteSchemaComponent onlyRenderProperties uid={match.params.name} />
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import { useField } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../';
|
||||||
|
|
||||||
|
export const MenuDesigner = () => {
|
||||||
|
const field = useField();
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner>
|
||||||
|
<SchemaSettings.Item>编辑</SchemaSettings.Item>
|
||||||
|
<SchemaSettings.Divider />
|
||||||
|
<SchemaSettings.Remove />
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
@ -1,13 +1,121 @@
|
|||||||
import { DesktopOutlined } from '@ant-design/icons';
|
import { css } from '@emotion/css';
|
||||||
import { observer, RecursionField, Schema, SchemaExpressionScopeContext, useFieldSchema } from '@formily/react';
|
import {
|
||||||
|
observer,
|
||||||
|
RecursionField,
|
||||||
|
Schema,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
|
useField,
|
||||||
|
useFieldSchema
|
||||||
|
} from '@formily/react';
|
||||||
import { Menu as AntdMenu } from 'antd';
|
import { Menu as AntdMenu } from 'antd';
|
||||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { createDesignable, DndContext, SortableItem, useComponent, useDesignable, useDesigner } from '../..';
|
||||||
|
import { Icon, useAPIClient } from '../../../';
|
||||||
|
import { MenuDesigner } from './Menu.Designer';
|
||||||
import { findKeysByUid, findMenuItem } from './util';
|
import { findKeysByUid, findMenuItem } from './util';
|
||||||
|
|
||||||
|
const subMenuDesignerCss = css`
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -34px;
|
||||||
|
padding: 0 34px 0 24px;
|
||||||
|
width: calc(100% + 58px);
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-action-link {
|
||||||
|
> .general-schema-designer {
|
||||||
|
top: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: rgba(241, 139, 98, 0.06);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: #f18b62;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const designerCss = css`
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: -20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
width: calc(100% + 40px);
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nb-action-link {
|
||||||
|
> .general-schema-designer {
|
||||||
|
top: -10px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: rgba(241, 139, 98, 0.06);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: #f18b62;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
type ComposedMenu = React.FC<any> & {
|
type ComposedMenu = React.FC<any> & {
|
||||||
Item?: React.FC<any>;
|
Item?: React.FC<any>;
|
||||||
|
URL?: React.FC<any>;
|
||||||
SubMenu?: React.FC<any>;
|
SubMenu?: React.FC<any>;
|
||||||
|
Designer?: React.FC<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MenuModeContext = createContext(null);
|
const MenuModeContext = createContext(null);
|
||||||
@ -22,6 +130,8 @@ const useSideMenuRef = () => {
|
|||||||
return scope[scopeKey];
|
return scope[scopeKey];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MenuItemDesignerContext = createContext(null);
|
||||||
|
|
||||||
export const Menu: ComposedMenu = observer((props) => {
|
export const Menu: ComposedMenu = observer((props) => {
|
||||||
let {
|
let {
|
||||||
onSelect,
|
onSelect,
|
||||||
@ -32,7 +142,11 @@ export const Menu: ComposedMenu = observer((props) => {
|
|||||||
defaultOpenKeys: dOpenKeys,
|
defaultOpenKeys: dOpenKeys,
|
||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
|
const Designer = useDesigner();
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
|
const { refresh } = useDesignable();
|
||||||
|
const api = useAPIClient();
|
||||||
|
const Initializer = useComponent(schema['x-initializer']);
|
||||||
const sideMenuRef = useSideMenuRef();
|
const sideMenuRef = useSideMenuRef();
|
||||||
const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(() => {
|
const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(() => {
|
||||||
if (dSelectedKeys) {
|
if (dSelectedKeys) {
|
||||||
@ -70,17 +184,31 @@ export const Menu: ComposedMenu = observer((props) => {
|
|||||||
if (!sideMenuElement) {
|
if (!sideMenuElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sideMenuElement.style.display = sideMenuSchema?.properties ? 'block' : 'none';
|
sideMenuElement.style.display = sideMenuSchema?.['x-component'] === 'Menu.SubMenu' ? 'block' : 'none';
|
||||||
}, [sideMenuSchema?.properties, sideMenuRef]);
|
}, [sideMenuSchema?.name, sideMenuRef]);
|
||||||
return (
|
return (
|
||||||
|
<DndContext>
|
||||||
|
<MenuItemDesignerContext.Provider value={Designer}>
|
||||||
<MenuModeContext.Provider value={mode}>
|
<MenuModeContext.Provider value={mode}>
|
||||||
<AntdMenu
|
<AntdMenu
|
||||||
{...others}
|
{...others}
|
||||||
|
style={{
|
||||||
|
width: mode === 'mix' ? '100%' : undefined,
|
||||||
|
}}
|
||||||
|
className={css`
|
||||||
|
.ant-menu-item:hover {
|
||||||
|
> .ant-menu-title-content > div {
|
||||||
|
.general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
onSelect={(info: any) => {
|
onSelect={(info: any) => {
|
||||||
const s = schema.properties[info.key];
|
const s = schema.properties[info.key];
|
||||||
if (mode === 'mix') {
|
if (mode === 'mix') {
|
||||||
setSideMenuSchema(s);
|
setSideMenuSchema(s);
|
||||||
if (!s?.properties) {
|
if (s['x-component'] !== 'Menu.SubMenu') {
|
||||||
onSelect && onSelect(info);
|
onSelect && onSelect(info);
|
||||||
} else {
|
} else {
|
||||||
const menuItemSchema = findMenuItem(s);
|
const menuItemSchema = findMenuItem(s);
|
||||||
@ -113,11 +241,12 @@ export const Menu: ComposedMenu = observer((props) => {
|
|||||||
defaultSelectedKeys={defaultSelectedKeys}
|
defaultSelectedKeys={defaultSelectedKeys}
|
||||||
>
|
>
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
|
{Initializer && <Initializer style={{ background: 'none', marginTop: 7, marginLeft: 8 }} />}
|
||||||
</AntdMenu>
|
</AntdMenu>
|
||||||
{loading
|
{loading
|
||||||
? null
|
? null
|
||||||
: mode === 'mix' &&
|
: mode === 'mix' &&
|
||||||
sideMenuSchema?.properties &&
|
sideMenuSchema?.['x-component'] === 'Menu.SubMenu' &&
|
||||||
sideMenuRef?.current?.firstChild &&
|
sideMenuRef?.current?.firstChild &&
|
||||||
createPortal(
|
createPortal(
|
||||||
<MenuModeContext.Provider value={'inline'}>
|
<MenuModeContext.Provider value={'inline'}>
|
||||||
@ -128,40 +257,117 @@ export const Menu: ComposedMenu = observer((props) => {
|
|||||||
onSelect={(info) => {
|
onSelect={(info) => {
|
||||||
onSelect && onSelect(info);
|
onSelect && onSelect(info);
|
||||||
}}
|
}}
|
||||||
|
className={css`
|
||||||
|
.ant-menu-item {
|
||||||
|
> .ant-menu-title-content {
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -16px;
|
||||||
|
padding: 0 16px 0 24px;
|
||||||
|
> div {
|
||||||
|
> .general-schema-designer {
|
||||||
|
right: 6px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-menu-submenu-title {
|
||||||
|
.ant-menu-title-content {
|
||||||
|
margin-left: -24px;
|
||||||
|
margin-right: -34px;
|
||||||
|
padding: 0 34px 0 24px;
|
||||||
|
> div {
|
||||||
|
> .general-schema-designer {
|
||||||
|
right: 6px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
<RecursionField schema={sideMenuSchema} onlyRenderProperties />
|
<RecursionField schema={sideMenuSchema} onlyRenderProperties />
|
||||||
|
{Initializer && (
|
||||||
|
<Initializer
|
||||||
|
style={{ margin: 8 }}
|
||||||
|
insert={(s) => {
|
||||||
|
console.log('createDesignable', s);
|
||||||
|
const dn = createDesignable({
|
||||||
|
api,
|
||||||
|
refresh,
|
||||||
|
current: sideMenuSchema,
|
||||||
|
});
|
||||||
|
dn.loadAPIClientEvents();
|
||||||
|
dn.insertAdjacent('beforeEnd', s);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</AntdMenu>
|
</AntdMenu>
|
||||||
</MenuModeContext.Provider>,
|
</MenuModeContext.Provider>,
|
||||||
sideMenuRef.current.firstChild,
|
sideMenuRef.current.firstChild,
|
||||||
)}
|
)}
|
||||||
</MenuModeContext.Provider>
|
</MenuModeContext.Provider>
|
||||||
|
</MenuItemDesignerContext.Provider>
|
||||||
|
</DndContext>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Menu.Item = observer((props) => {
|
Menu.Item = observer((props) => {
|
||||||
|
const { icon, ...others } = props;
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
return (
|
return (
|
||||||
<AntdMenu.Item {...props} icon={<DesktopOutlined />} key={schema.name} eventKey={schema.name} schema={schema}>
|
<AntdMenu.Item {...others} key={schema.name} eventKey={schema.name} schema={schema}>
|
||||||
|
<SortableItem className={designerCss}>
|
||||||
|
<Icon type={icon} style={{ marginRight: 5 }} />
|
||||||
{schema.title}
|
{schema.title}
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
|
</AntdMenu.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Menu.URL = observer((props) => {
|
||||||
|
const { icon, ...others } = props;
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const field = useField();
|
||||||
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
|
return (
|
||||||
|
<AntdMenu.Item {...others} key={schema.name} eventKey={schema.name} schema={schema} onClick={() => {
|
||||||
|
window.open(props.href, '_blank');
|
||||||
|
}}>
|
||||||
|
<SortableItem className={designerCss}>
|
||||||
|
<Icon style={{ marginRight: 5 }} type={icon} />
|
||||||
|
{schema.title}
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Menu.SubMenu = observer((props) => {
|
Menu.SubMenu = observer((props) => {
|
||||||
|
const { icon, ...others } = props;
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
|
const field = useField();
|
||||||
const mode = useContext(MenuModeContext);
|
const mode = useContext(MenuModeContext);
|
||||||
|
const Designer = useContext(MenuItemDesignerContext);
|
||||||
if (mode === 'mix') {
|
if (mode === 'mix') {
|
||||||
return <Menu.Item {...props} />;
|
return <Menu.Item {...props} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<AntdMenu.SubMenu
|
<AntdMenu.SubMenu
|
||||||
{...props}
|
{...others}
|
||||||
icon={<DesktopOutlined />}
|
|
||||||
title={schema.title}
|
|
||||||
key={schema.name}
|
key={schema.name}
|
||||||
eventKey={schema.name}
|
eventKey={schema.name}
|
||||||
|
title={
|
||||||
|
<SortableItem className={subMenuDesignerCss}>
|
||||||
|
<Icon style={{ marginRight: 5 }} type={icon} />
|
||||||
|
{field.title}
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<RecursionField schema={schema} onlyRenderProperties />
|
<RecursionField schema={schema} onlyRenderProperties />
|
||||||
</AntdMenu.SubMenu>
|
</AntdMenu.SubMenu>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Menu.Designer = MenuDesigner;
|
||||||
|
@ -0,0 +1,204 @@
|
|||||||
|
import { FormDialog, FormLayout } from '@formily/antd';
|
||||||
|
import { observer, SchemaOptionsContext } from '@formily/react';
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SchemaComponent, SchemaComponentOptions } from '../../..';
|
||||||
|
import { SchemaInitializer } from '../../../../schema-initializer';
|
||||||
|
|
||||||
|
export const MenuItemInitializer = observer((props: any) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
insert={props.insert}
|
||||||
|
style={props.style}
|
||||||
|
{...props}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Group'),
|
||||||
|
component: GroupItem,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Page'),
|
||||||
|
component: PageMenuItem,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Link'),
|
||||||
|
component: LinkMenuItem,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{t('Add menu item')}
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemWrap = SchemaInitializer.itemWrap;
|
||||||
|
|
||||||
|
export const GroupItem = itemWrap((props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const options = useContext(SchemaOptionsContext);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
{...props}
|
||||||
|
onClick={async () => {
|
||||||
|
const values = await FormDialog('添加分组', () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaComponent
|
||||||
|
schema={{
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: '分组标题',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
title: '图标',
|
||||||
|
'x-component': 'IconPicker',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormLayout>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
}).open({
|
||||||
|
initialValues: {},
|
||||||
|
});
|
||||||
|
const { title, icon } = values;
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
title,
|
||||||
|
'x-component': 'Menu.SubMenu',
|
||||||
|
'x-component-props': {
|
||||||
|
icon,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PageMenuItem = itemWrap((props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const options = useContext(SchemaOptionsContext);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
{...props}
|
||||||
|
onClick={async () => {
|
||||||
|
const values = await FormDialog('添加页面', () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaComponent
|
||||||
|
schema={{
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: '页面标题',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
title: '图标',
|
||||||
|
'x-component': 'IconPicker',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormLayout>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
}).open({
|
||||||
|
initialValues: {},
|
||||||
|
});
|
||||||
|
const { title, icon } = values;
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
title,
|
||||||
|
'x-component': 'Menu.Item',
|
||||||
|
'x-component-props': {
|
||||||
|
icon,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
page: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
'x-async': true,
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-item-initializer': 'BlockInitializer',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const LinkMenuItem = itemWrap((props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const options = useContext(SchemaOptionsContext);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
{...props}
|
||||||
|
onClick={async () => {
|
||||||
|
const values = await FormDialog('添加链接', () => {
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaComponent
|
||||||
|
schema={{
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: '链接文字',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
href: {
|
||||||
|
title: '链接',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
title: '图标',
|
||||||
|
'x-component': 'IconPicker',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormLayout>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
}).open({
|
||||||
|
initialValues: {},
|
||||||
|
});
|
||||||
|
const { title, href, icon } = values;
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
title,
|
||||||
|
'x-component': 'Menu.URL',
|
||||||
|
'x-component-props': {
|
||||||
|
icon,
|
||||||
|
href,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
@ -1,3 +1,4 @@
|
|||||||
export * from './Menu';
|
export * from './Menu';
|
||||||
|
export * from './MenuItemInitializer';
|
||||||
export * from './util';
|
export * from './util';
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
import { message } from 'antd';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
@ -92,6 +93,7 @@ export class Designable {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
message.success('配置保存成功!', 0.2);
|
||||||
});
|
});
|
||||||
this.on('patch', async ({ schema }) => {
|
this.on('patch', async ({ schema }) => {
|
||||||
refresh();
|
refresh();
|
||||||
@ -104,6 +106,7 @@ export class Designable {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
message.success('配置保存成功!', 0.2);
|
||||||
});
|
});
|
||||||
this.on('remove', async ({ removed }) => {
|
this.on('remove', async ({ removed }) => {
|
||||||
refresh();
|
refresh();
|
||||||
@ -113,6 +116,7 @@ export class Designable {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
message.success('配置保存成功!', 0.2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { useFieldSchema } from '@formily/react';
|
import { useFieldSchema } from '@formily/react';
|
||||||
import { useComponent } from '.';
|
import { useComponent, useDesignable } from '.';
|
||||||
|
|
||||||
const Def = () => null;
|
const Def = () => null;
|
||||||
|
|
||||||
export const useDesigner = () => {
|
export const useDesigner = () => {
|
||||||
|
const { designable } = useDesignable();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
return useComponent(fieldSchema['x-designer'], Def);
|
const component = useComponent(fieldSchema['x-designer'], Def);
|
||||||
|
return designable ? component : Def;
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ export const MarkdownBlock = itemWrap((props) => {
|
|||||||
'x-component': 'Markdown.Void',
|
'x-component': 'Markdown.Void',
|
||||||
'x-editable': false,
|
'x-editable': false,
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
content: '# Markdown content',
|
content: t('This is a demo text, **supports Markdown syntax**.'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
@ -17,7 +17,7 @@ export const SchemaInitializer = () => null;
|
|||||||
|
|
||||||
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
||||||
const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, style, ...others } = props;
|
const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, style, ...others } = props;
|
||||||
let { insertAdjacent, findComponent } = useDesignable();
|
let { insertAdjacent, findComponent, designable } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const insertSchema = (schema) => {
|
const insertSchema = (schema) => {
|
||||||
if (props.insert) {
|
if (props.insert) {
|
||||||
@ -81,7 +81,9 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
|||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('others', others);
|
if (!designable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -6,7 +6,7 @@ import { DragHandler, useDesignable } from '../schema-component';
|
|||||||
import { SchemaSettings } from './SchemaSettings';
|
import { SchemaSettings } from './SchemaSettings';
|
||||||
|
|
||||||
export const GeneralSchemaDesigner = (props: any) => {
|
export const GeneralSchemaDesigner = (props: any) => {
|
||||||
const { dn } = useDesignable();
|
const { dn, designable } = useDesignable();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const schemaSettingsProps = {
|
const schemaSettingsProps = {
|
||||||
@ -14,6 +14,9 @@ export const GeneralSchemaDesigner = (props: any) => {
|
|||||||
field,
|
field,
|
||||||
fieldSchema,
|
fieldSchema,
|
||||||
};
|
};
|
||||||
|
if (!designable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={'general-schema-designer'}>
|
<div className={'general-schema-designer'}>
|
||||||
<div className={'general-schema-designer-icons'}>
|
<div className={'general-schema-designer-icons'}>
|
||||||
|
@ -20,6 +20,8 @@ export class UiRoutesStoragePlugin extends Plugin {
|
|||||||
uiSchema: {
|
uiSchema: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Menu',
|
'x-component': 'Menu',
|
||||||
|
'x-designer': 'Menu.Designer',
|
||||||
|
'x-initializer': 'MenuItemInitializer',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
mode: 'mix',
|
mode: 'mix',
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
|
Loading…
Reference in New Issue
Block a user