updates
This commit is contained in:
parent
97ca17bc10
commit
e8399e167e
@ -17,7 +17,7 @@ import {
|
||||
useHistory,
|
||||
Redirect,
|
||||
} from 'react-router-dom';
|
||||
import { SchemaRenderer } from '../../schemas';
|
||||
import { CollectionContextProvider, PageTitleContextProvider, SchemaRenderer, usePageTitleContext } from '../../schemas';
|
||||
import { useRequest } from 'ahooks';
|
||||
import './style.less';
|
||||
|
||||
@ -30,6 +30,7 @@ function LayoutWithMenu({ schema }) {
|
||||
const location = useLocation();
|
||||
const sideMenuRef = useRef();
|
||||
const [activeKey, setActiveKey] = useState(match.params.name);
|
||||
const [,setPageTitle] = usePageTitleContext();
|
||||
const onSelect = (info) => {
|
||||
console.log('LayoutWithMenu', info);
|
||||
if (!info.schema) {
|
||||
@ -39,6 +40,9 @@ function LayoutWithMenu({ schema }) {
|
||||
setActiveKey(null);
|
||||
} else {
|
||||
setActiveKey(info.schema.key);
|
||||
if (info.schema.title) {
|
||||
setPageTitle(info.schema.title);
|
||||
}
|
||||
}
|
||||
};
|
||||
console.log({ match });
|
||||
@ -98,7 +102,13 @@ export function AdminLayout({ route }: any) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
return <LayoutWithMenu schema={data} />;
|
||||
return (
|
||||
<CollectionContextProvider>
|
||||
<PageTitleContextProvider>
|
||||
<LayoutWithMenu schema={data} />
|
||||
</PageTitleContextProvider>
|
||||
</CollectionContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminLayout;
|
||||
|
@ -46,8 +46,10 @@ import { TimePicker } from '../../schemas/time-picker';
|
||||
import { Upload } from '../../schemas/upload';
|
||||
import { FormItem } from '../../schemas/form-item';
|
||||
import { BlockItem } from '../../schemas/block-item';
|
||||
import { CardItem } from '../../schemas/card-item';
|
||||
import { DragAndDrop } from '../../schemas/drag-and-drop';
|
||||
import { TreeSelect } from '../../schemas/tree-select';
|
||||
import { Page } from '../../schemas/page';
|
||||
|
||||
export const BlockContext = createContext({ dragRef: null });
|
||||
|
||||
@ -59,11 +61,14 @@ interface DesignableContextProps {
|
||||
}
|
||||
|
||||
export const SchemaField = createSchemaField({
|
||||
scope: {},
|
||||
scope: {
|
||||
Table,
|
||||
},
|
||||
components: {
|
||||
Card,
|
||||
Div,
|
||||
Space,
|
||||
Page,
|
||||
|
||||
ArrayCollapse,
|
||||
ArrayTable,
|
||||
@ -73,6 +78,7 @@ export const SchemaField = createSchemaField({
|
||||
DragAndDrop,
|
||||
|
||||
BlockItem,
|
||||
CardItem,
|
||||
FormItem,
|
||||
|
||||
Action,
|
||||
@ -173,6 +179,14 @@ function setKeys(schema: ISchema, parentKey = null) {
|
||||
});
|
||||
}
|
||||
|
||||
export function useSchemaComponent(component: string) {
|
||||
if (!component) {
|
||||
return null;
|
||||
}
|
||||
const options = useContext(SchemaOptionsContext);
|
||||
return get(options.components, component);
|
||||
}
|
||||
|
||||
export function useDesignable(path?: any) {
|
||||
const { schema = new Schema({}), refresh } = useContext(DesignableContext);
|
||||
const schemaPath = path || useSchemaPath();
|
||||
|
@ -46,9 +46,17 @@ import {
|
||||
DownOutlined,
|
||||
DatabaseOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { createSchema, useDesignable, useSchemaPath } from '../';
|
||||
import {
|
||||
createOrUpdateCollection,
|
||||
createSchema,
|
||||
request,
|
||||
useCollectionContext,
|
||||
useDesignable,
|
||||
useSchemaPath,
|
||||
} from '../';
|
||||
import { uid } from '@formily/shared';
|
||||
import { request } from '../../demos/api';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { SchemaField } from '../../components/schema-renderer';
|
||||
|
||||
const generateGridBlock = (schema: ISchema) => {
|
||||
const name = schema.name || uid();
|
||||
@ -68,6 +76,10 @@ const generateGridBlock = (schema: ISchema) => {
|
||||
};
|
||||
};
|
||||
|
||||
const isGrid = (schema: Schema) => {
|
||||
return schema['x-component'] === 'Grid';
|
||||
};
|
||||
|
||||
const isGridBlock = (schema: Schema) => {
|
||||
if (schema.parent['x-component'] !== 'Grid.Col') {
|
||||
return false;
|
||||
@ -83,14 +95,519 @@ const isGridBlock = (schema: Schema) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
function generateCardItemSchema(component) {
|
||||
const defaults = {
|
||||
Markdown: {
|
||||
type: 'string',
|
||||
default: '这是一段演示文字',
|
||||
'x-designable-bar': 'Markdown.DesignableBar',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-read-pretty': true,
|
||||
'x-component': 'Markdown',
|
||||
'x-component-props': {
|
||||
savedInSchema: true,
|
||||
},
|
||||
},
|
||||
Table: {
|
||||
type: 'array',
|
||||
'x-designable-bar': 'Table.DesignableBar',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Table',
|
||||
default: [
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
{ key: uid(), field1: uid(), field2: uid() },
|
||||
],
|
||||
'x-component-props': {
|
||||
rowKey: 'key',
|
||||
},
|
||||
properties: {
|
||||
[`action_bar_${uid()}`]: {
|
||||
type: 'void',
|
||||
'x-component': 'Table.ActionBar',
|
||||
properties: {
|
||||
action1: {
|
||||
type: 'void',
|
||||
name: 'action1',
|
||||
title: '筛选',
|
||||
'x-component': 'Action',
|
||||
properties: {
|
||||
popover1: {
|
||||
type: 'void',
|
||||
title: '弹窗标题',
|
||||
'x-decorator': 'Form',
|
||||
'x-component': 'Action.Popover',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
filter: {
|
||||
name: 'filter',
|
||||
type: 'object',
|
||||
'x-component': 'Filter',
|
||||
properties: {
|
||||
column1: {
|
||||
type: 'void',
|
||||
title: '字段1',
|
||||
'x-component': 'Filter.Column',
|
||||
'x-component-props': {
|
||||
operations: [
|
||||
{ label: '等于', value: 'eq' },
|
||||
{ label: '不等于', value: 'ne' },
|
||||
],
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
type: 'string',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
column2: {
|
||||
type: 'void',
|
||||
title: '字段2',
|
||||
'x-component': 'Filter.Column',
|
||||
'x-component-props': {
|
||||
operations: [
|
||||
{ label: '大于', value: 'gt' },
|
||||
{ label: '小于', value: 'lt' },
|
||||
{
|
||||
label: '非空',
|
||||
value: 'notNull',
|
||||
noValue: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
type: 'number',
|
||||
'x-component': 'InputNumber',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action2: {
|
||||
type: 'void',
|
||||
name: 'action1',
|
||||
title: '新增',
|
||||
'x-component': 'Action',
|
||||
'x-designable-bar': 'Action.DesignableBar',
|
||||
properties: {
|
||||
drawer1: {
|
||||
type: 'void',
|
||||
title: '抽屉标题',
|
||||
'x-decorator': 'Form',
|
||||
'x-component': 'Action.Modal',
|
||||
'x-component-props': {
|
||||
useOkAction: '{{ Table.useTableCreateAction }}',
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
type: 'string',
|
||||
title: '字段1',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
field2: {
|
||||
type: 'string',
|
||||
title: '字段2',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
action3: {
|
||||
type: 'void',
|
||||
name: 'action1',
|
||||
title: '删除',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ Table.useTableDestroyAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[`a_${uid()}`]: {
|
||||
type: 'void',
|
||||
'x-component': 'Table.ActionBar',
|
||||
'x-component-props': {
|
||||
align: 'bottom',
|
||||
},
|
||||
properties: {
|
||||
pagination: {
|
||||
type: 'void',
|
||||
'x-component': 'Table.Pagination',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
[`column_${uid()}`]: {
|
||||
type: 'void',
|
||||
title: '排序',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
sort: {
|
||||
type: 'void',
|
||||
'x-component': 'Table.SortHandle',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`column_${uid()}`]: {
|
||||
type: 'void',
|
||||
title: '序号',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
index: {
|
||||
type: 'void',
|
||||
'x-component': 'Table.Index',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`column_${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-read-pretty': true,
|
||||
'x-decorator-props': {
|
||||
feedbackLayout: 'popover',
|
||||
},
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`column_${uid()}`]: {
|
||||
type: 'void',
|
||||
title: '字段2',
|
||||
'x-component': 'Table.Column',
|
||||
'x-designable-bar': 'Table.Column.DesignableBar',
|
||||
properties: {
|
||||
field2: {
|
||||
type: 'string',
|
||||
// title: '字段2',
|
||||
required: true,
|
||||
'x-read-pretty': true,
|
||||
'x-decorator-props': {
|
||||
feedbackLayout: 'popover',
|
||||
},
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`column_${uid()}`]: {
|
||||
type: 'void',
|
||||
title: '操作',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
name: 'action1',
|
||||
title: '查看',
|
||||
'x-component': 'Action',
|
||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||
properties: {
|
||||
drawer1: {
|
||||
type: 'void',
|
||||
title: '查看',
|
||||
'x-component': 'Action.Modal',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs',
|
||||
properties: {
|
||||
tab1: {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs.TabPane',
|
||||
'x-component-props': {
|
||||
tab: 'Tab1',
|
||||
},
|
||||
properties: {
|
||||
aaa: {
|
||||
type: 'string',
|
||||
title: 'AAA',
|
||||
'x-decorator': 'FormItem',
|
||||
required: true,
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
tab2: {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs.TabPane',
|
||||
'x-component-props': {
|
||||
tab: 'Tab2',
|
||||
},
|
||||
properties: {
|
||||
bbb: {
|
||||
type: 'string',
|
||||
title: 'BBB',
|
||||
'x-decorator': 'FormItem',
|
||||
required: true,
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
name: 'action1',
|
||||
title: '修改',
|
||||
'x-component': 'Action',
|
||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||
properties: {
|
||||
drawer1: {
|
||||
type: 'void',
|
||||
title: '编辑表单',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues: '{{ Table.useTableRow }}',
|
||||
},
|
||||
'x-component': 'Action.Modal',
|
||||
'x-component-props': {
|
||||
useOkAction: '{{ Table.useTableUpdateAction }}',
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
type: 'string',
|
||||
title: '字段1',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
field2: {
|
||||
type: 'string',
|
||||
title: '字段2',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
title: '删除',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ Table.useTableDestroyAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Form: {
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Form',
|
||||
'x-designable-bar': 'Form.DesignableBar',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-component-props': {
|
||||
addNewComponent: 'AddNew.FormItem',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return defaults[component];
|
||||
}
|
||||
|
||||
function generateFormItemSchema(component) {
|
||||
const defaults = {
|
||||
Markdown: {
|
||||
type: 'string',
|
||||
title: uid(),
|
||||
'x-designable-bar': 'Markdown.DesignableBar',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Markdown',
|
||||
'x-component-props': {},
|
||||
},
|
||||
};
|
||||
return defaults[component];
|
||||
}
|
||||
|
||||
const dbSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
title: {
|
||||
type: 'string',
|
||||
title: '数据表名称',
|
||||
required: true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
title: '数据表标识',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
fields: {
|
||||
type: 'array',
|
||||
title: '数据表字段',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'DatabaseField',
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const AddNew = () => null;
|
||||
|
||||
AddNew.CardItem = observer((props: any) => {
|
||||
const { ghost, defaultAction } = props;
|
||||
const { schema, insertBefore, insertAfter, appendChild } = useDesignable();
|
||||
const path = useSchemaPath();
|
||||
const { data: collections = [], loading, run } = useRequest('collections:findAll', {
|
||||
formatResult: (result) => result?.data,
|
||||
});
|
||||
console.log({ collections });
|
||||
return (
|
||||
<Dropdown
|
||||
overlayStyle={{
|
||||
minWidth: 200,
|
||||
}}
|
||||
onVisibleChange={(visible) => {
|
||||
if (visible) {
|
||||
run();
|
||||
}
|
||||
console.log('onVisibleChange', visible);
|
||||
}}
|
||||
placement={'bottomCenter'}
|
||||
overlay={
|
||||
<Menu
|
||||
onClick={async (info) => {
|
||||
let data: ISchema;
|
||||
if (['addNewTable', 'addNewForm'].includes(info.key)) {
|
||||
const values = await FormDialog(`新建数据表`, () => {
|
||||
return (
|
||||
<FormLayout layout={'vertical'}>
|
||||
<SchemaField schema={dbSchema} />
|
||||
</FormLayout>
|
||||
);
|
||||
}).open({
|
||||
initialValues: {
|
||||
name: `t_${uid()}`,
|
||||
fields: [],
|
||||
},
|
||||
});
|
||||
await createOrUpdateCollection(values);
|
||||
data = generateCardItemSchema(
|
||||
info.key === 'addNewTable' ? 'Table' : 'Form',
|
||||
);
|
||||
} else if (info.key !== 'Markdown') {
|
||||
const keys = info.key.split('.');
|
||||
const component = keys.shift();
|
||||
const tableName = keys.join('.');
|
||||
data = generateCardItemSchema(component);
|
||||
console.log('info.keyPath', component, tableName);
|
||||
} else {
|
||||
data = generateCardItemSchema(info.key);
|
||||
}
|
||||
if (schema['key']) {
|
||||
data['key'] = uid();
|
||||
}
|
||||
if (isGridBlock(schema)) {
|
||||
path.pop();
|
||||
path.pop();
|
||||
data = generateGridBlock(data);
|
||||
} else if (isGrid(schema)) {
|
||||
data = generateGridBlock(data);
|
||||
}
|
||||
if (data) {
|
||||
let s;
|
||||
if (isGrid(schema)) {
|
||||
s = appendChild(data, [...path]);
|
||||
} else if (defaultAction === 'insertAfter') {
|
||||
s = insertAfter(data, [...path]);
|
||||
} else {
|
||||
s = insertBefore(data, [...path]);
|
||||
}
|
||||
await createSchema(s);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Menu.SubMenu key={'Table'} title={'新建表格'}>
|
||||
<Menu.ItemGroup key={'table-select'} title={'选择数据表'}>
|
||||
{collections.map((item) => (
|
||||
<Menu.Item key={`Table.${item.name}`}>{item.title}</Menu.Item>
|
||||
))}
|
||||
</Menu.ItemGroup>
|
||||
<Menu.Divider></Menu.Divider>
|
||||
<Menu.Item key={'addNewTable'}>新建数据表</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
<Menu.SubMenu key={'Form'} title={'新建表单'}>
|
||||
<Menu.ItemGroup key={'form-select'} title={'选择数据表'}>
|
||||
{collections.map((item) => (
|
||||
<Menu.Item key={`Form.${item.name}`}>{item.title}</Menu.Item>
|
||||
))}
|
||||
</Menu.ItemGroup>
|
||||
<Menu.Divider></Menu.Divider>
|
||||
<Menu.Item key={'addNewForm'}>新建数据表</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
<Menu.Item key={'Markdown'}>新建 Markdown</Menu.Item>
|
||||
<Menu.SubMenu key={'Ref'} title={'引用模板'}>
|
||||
<Menu.ItemGroup key={'form-select'} title={'选择模板'}>
|
||||
<Menu.Item key={'Ref.name1'}>模板1</Menu.Item>
|
||||
</Menu.ItemGroup>
|
||||
<Menu.Divider></Menu.Divider>
|
||||
<Menu.Item key={'addNewRef'}>新建模板</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
{ghost ? (
|
||||
<PlusOutlined />
|
||||
) : (
|
||||
<Button block type={'dashed'} icon={<PlusOutlined />}></Button>
|
||||
)}
|
||||
</Dropdown>
|
||||
);
|
||||
});
|
||||
|
||||
AddNew.BlockItem = observer((props: any) => {
|
||||
const { ghost, defaultAction } = props;
|
||||
const { schema, insertBefore, insertAfter } = useDesignable();
|
||||
const path = useSchemaPath();
|
||||
return (
|
||||
<Dropdown
|
||||
overlayStyle={{
|
||||
minWidth: 200,
|
||||
}}
|
||||
placement={'bottomCenter'}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.SubMenu title={'新建表格'}>
|
||||
@ -113,7 +630,7 @@ AddNew.BlockItem = observer((props: any) => {
|
||||
type: 'void',
|
||||
title: uid(),
|
||||
'x-designable-bar': 'BlockItem.DesignableBar',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Markdown',
|
||||
};
|
||||
if (schema['key']) {
|
||||
@ -141,7 +658,11 @@ AddNew.BlockItem = observer((props: any) => {
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
{ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
|
||||
{ghost ? (
|
||||
<PlusOutlined />
|
||||
) : (
|
||||
<Button block type={'dashed'} icon={<PlusOutlined />}></Button>
|
||||
)}
|
||||
</Dropdown>
|
||||
);
|
||||
});
|
||||
@ -152,6 +673,10 @@ AddNew.FormItem = observer((props: any) => {
|
||||
const path = useSchemaPath();
|
||||
return (
|
||||
<Dropdown
|
||||
overlayStyle={{
|
||||
minWidth: 200,
|
||||
}}
|
||||
placement={'bottomCenter'}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.ItemGroup title={'选择已有字段'}>
|
||||
@ -159,25 +684,24 @@ AddNew.FormItem = observer((props: any) => {
|
||||
style={{
|
||||
minWidth: 150,
|
||||
}}
|
||||
onClick={() => {
|
||||
let data: ISchema = {
|
||||
type: 'void',
|
||||
title: uid(),
|
||||
'x-designable-bar': 'FormItem.DesignableBar',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Markdown',
|
||||
};
|
||||
onClick={async () => {
|
||||
let data: ISchema = generateFormItemSchema('Markdown');
|
||||
if (schema['key']) {
|
||||
data['key'] = uid();
|
||||
}
|
||||
if (isGridBlock(schema)) {
|
||||
path.pop();
|
||||
path.pop();
|
||||
data = generateGridBlock(data);
|
||||
}
|
||||
if (data) {
|
||||
let s;
|
||||
if (defaultAction === 'insertAfter') {
|
||||
insertAfter(data, [...path]);
|
||||
s = insertAfter(data, [...path]);
|
||||
} else {
|
||||
insertBefore(data, [...path]);
|
||||
s = insertBefore(data, [...path]);
|
||||
}
|
||||
await createSchema(s);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -219,7 +743,11 @@ AddNew.FormItem = observer((props: any) => {
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
{ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
|
||||
{ghost ? (
|
||||
<PlusOutlined />
|
||||
) : (
|
||||
<Button block type={'dashed'} icon={<PlusOutlined />}></Button>
|
||||
)}
|
||||
</Dropdown>
|
||||
);
|
||||
});
|
||||
|
@ -113,17 +113,6 @@ export const BlockItem: any = observer((props) => {
|
||||
return React.createElement(uid ? DraggableBlock : Block, props);
|
||||
});
|
||||
|
||||
// export const BlockItem: any = connect((props) => {
|
||||
// const { children, ...others } = props;
|
||||
// const { DesignableBar } = useDesignableBar();
|
||||
// return (
|
||||
// <div {...others} style={{marginBottom: 24}} className={'designable-form-item'}>
|
||||
// {children}
|
||||
// <DesignableBar />
|
||||
// </div>
|
||||
// );
|
||||
// });
|
||||
|
||||
BlockItem.DesignableBar = () => {
|
||||
const field = useField();
|
||||
const { schema, refresh } = useDesignable();
|
||||
|
32
packages/client/src/schemas/card-item/index.tsx
Normal file
32
packages/client/src/schemas/card-item/index.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {
|
||||
connect,
|
||||
mapProps,
|
||||
mapReadPretty,
|
||||
observer,
|
||||
SchemaOptionsContext,
|
||||
useField,
|
||||
useFieldSchema,
|
||||
} from '@formily/react';
|
||||
import { FormItem as FormilyFormItem } from '@formily/antd';
|
||||
import { Card, Dropdown, Menu, Space } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||
// import './style.less';
|
||||
import get from 'lodash/get';
|
||||
import { GridBlockContext } from '../grid';
|
||||
import { uid } from '@formily/shared';
|
||||
import { useDesignable } from '../';
|
||||
import { AddNew } from '../add-new';
|
||||
import { BlockItem } from '../block-item';
|
||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||
|
||||
export const CardItem: any = connect((props) => {
|
||||
return (
|
||||
<BlockItem>
|
||||
<Card bordered={false} {...props}>
|
||||
{props.children}
|
||||
</Card>
|
||||
</BlockItem>
|
||||
);
|
||||
});
|
@ -39,7 +39,7 @@ import Modal from 'antd/lib/modal/Modal';
|
||||
import { clone, cloneDeep, get } from 'lodash';
|
||||
import { useEffect } from 'react';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { createOrUpdateCollection, deleteCollection } from '..';
|
||||
import { createOrUpdateCollection, deleteCollection, useCollectionContext } from '..';
|
||||
|
||||
export const DatabaseCollection = observer((props) => {
|
||||
const field = useField<Formily.Core.Models.ArrayField>();
|
||||
@ -49,6 +49,7 @@ export const DatabaseCollection = observer((props) => {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const form = useForm();
|
||||
const [newValue, setNewValue] = useState('');
|
||||
const { refresh } = useCollectionContext();
|
||||
|
||||
const { run, loading } = useRequest('collections:findAll', {
|
||||
formatResult: (result) => result?.data,
|
||||
@ -125,6 +126,7 @@ export const DatabaseCollection = observer((props) => {
|
||||
setOpen(false);
|
||||
setNewValue('');
|
||||
await createOrUpdateCollection(data);
|
||||
await refresh();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -166,6 +168,7 @@ export const DatabaseCollection = observer((props) => {
|
||||
}
|
||||
if (item.name) {
|
||||
await deleteCollection(item.name);
|
||||
await refresh();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@ -188,6 +191,7 @@ export const DatabaseCollection = observer((props) => {
|
||||
await form.validate(`${field.address.entire}.${activeIndex}.*`);
|
||||
delete field.value[activeIndex]['unsaved'];
|
||||
await createOrUpdateCollection(field.value[activeIndex]);
|
||||
await refresh();
|
||||
message.success('保存成功');
|
||||
} catch (error) {}
|
||||
}}
|
||||
|
@ -8,14 +8,18 @@ import {
|
||||
SchemaExpressionScopeContext,
|
||||
FormProvider,
|
||||
ISchema,
|
||||
useField,
|
||||
} from '@formily/react';
|
||||
import { useSchemaPath, SchemaField, useDesignable } from '../';
|
||||
import { useSchemaPath, SchemaField, useDesignable, removeSchema } from '../';
|
||||
import get from 'lodash/get';
|
||||
import { Dropdown, Menu } from 'antd';
|
||||
import { MenuOutlined } from '@ant-design/icons';
|
||||
import { Dropdown, Menu, Space } from 'antd';
|
||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||
import cls from 'classnames';
|
||||
import { FormLayout } from '@formily/antd';
|
||||
import './style.less';
|
||||
import AddNew from '../add-new';
|
||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||
import { isGridRowOrCol } from '../grid';
|
||||
|
||||
export const Form: any = observer((props: any) => {
|
||||
const { useValues = () => ({}), ...others } = props;
|
||||
@ -61,21 +65,59 @@ export const Form: any = observer((props: any) => {
|
||||
|
||||
Form.__Decorator = ({ children }) => children;
|
||||
|
||||
Form.DesignableBar = (props) => {
|
||||
const { active } = props;
|
||||
Form.DesignableBar = observer((props) => {
|
||||
const field = useField();
|
||||
const { schema, refresh, deepRemove } = useDesignable();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { dragRef } = useContext(DraggableBlockContext);
|
||||
return (
|
||||
<div className={cls('designable-bar', { active })}>
|
||||
<div className={'designable-bar-actions'}>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>表单配置</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined />
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div className={cls('designable-bar', { active: visible })}>
|
||||
<span
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className={cls('designable-bar-actions', { active: visible })}
|
||||
>
|
||||
<Space size={'small'}>
|
||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||
{dragRef && <DragOutlined ref={dragRef} />}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
visible={visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setVisible(visible);
|
||||
}}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key={'update'}
|
||||
onClick={() => {
|
||||
field.readPretty = false;
|
||||
}}
|
||||
>
|
||||
编辑Markdown
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Item
|
||||
key={'delete'}
|
||||
onClick={async () => {
|
||||
const removed = deepRemove();
|
||||
// console.log({ removed })
|
||||
const last = removed.pop();
|
||||
if (isGridRowOrCol(last)) {
|
||||
await removeSchema(last);
|
||||
}
|
||||
}}
|
||||
>
|
||||
删除当前区块
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined />
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -14,6 +14,9 @@ const schema: ISchema = {
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-component': 'Grid',
|
||||
"x-component-props": {
|
||||
addNewComponent: 'AddNew.CardItem',
|
||||
},
|
||||
properties: {
|
||||
[`row_${uid()}`]: {
|
||||
type: 'void',
|
||||
|
@ -30,6 +30,7 @@ import {
|
||||
useDragDropUID,
|
||||
DragDropManagerProvider,
|
||||
} from '../../components/drag-and-drop';
|
||||
import { useSchemaComponent } from '../../components/schema-renderer';
|
||||
|
||||
const ColumnSizeContext = createContext(null);
|
||||
|
||||
@ -37,7 +38,7 @@ export const GridBlockContext = createContext({
|
||||
dragRef: null,
|
||||
});
|
||||
|
||||
function isGridRowOrCol(schema: ISchema) {
|
||||
export function isGridRowOrCol(schema: ISchema) {
|
||||
return ['Grid.Row', 'Grid.Col'].includes(schema['x-component']);
|
||||
}
|
||||
|
||||
@ -81,11 +82,14 @@ const ColDivider = (props: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Grid: any = observer((props) => {
|
||||
export const Grid: any = observer((props: any) => {
|
||||
const { addNewComponent } = props;
|
||||
const AddNewComponent = useSchemaComponent(addNewComponent);
|
||||
const ref = useRef();
|
||||
const schema = useFieldSchema();
|
||||
// const schema = useFieldSchema();
|
||||
const gridPath = useSchemaPath();
|
||||
const {
|
||||
schema,
|
||||
schema: designableSchema,
|
||||
insertAfter,
|
||||
prepend,
|
||||
@ -162,6 +166,7 @@ export const Grid: any = observer((props) => {
|
||||
</>
|
||||
);
|
||||
})}
|
||||
{AddNewComponent && <AddNewComponent />}
|
||||
</div>
|
||||
</DragDropManagerProvider>
|
||||
);
|
||||
@ -169,9 +174,10 @@ export const Grid: any = observer((props) => {
|
||||
|
||||
Grid.Row = observer((props) => {
|
||||
const field = useField();
|
||||
const schema = useFieldSchema();
|
||||
// const schema = useFieldSchema();
|
||||
const rowPath = useSchemaPath();
|
||||
const {
|
||||
schema,
|
||||
schema: designableSchema,
|
||||
refresh,
|
||||
insertAfter,
|
||||
|
@ -1,18 +1,50 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { ISchema, observer, Schema, useField } from '@formily/react';
|
||||
import constate from 'constate';
|
||||
import { useState } from 'react';
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { extend } from 'umi-request';
|
||||
import { isVoidField } from '@formily/core';
|
||||
import { useRequest } from 'ahooks';
|
||||
|
||||
export * from '../components/schema-renderer';
|
||||
|
||||
export function mapReadPretty(component, readPrettyProps) {
|
||||
return function (target) {
|
||||
return observer(
|
||||
(props) => {
|
||||
const field = useField()
|
||||
if (!isVoidField(field) && field?.pattern === 'readPretty') {
|
||||
return React.createElement(component, {
|
||||
...readPrettyProps,
|
||||
...props,
|
||||
})
|
||||
}
|
||||
return React.createElement(target, props)
|
||||
},
|
||||
{
|
||||
forwardRef: true,
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
export const VisibleContext = createContext(null);
|
||||
export const DesignableBarContext = createContext(null);
|
||||
|
||||
const [PageTitleContextProvider, usePageTitleContext] = constate(() => {
|
||||
return useState(null);
|
||||
});
|
||||
|
||||
export { PageTitleContextProvider, usePageTitleContext };
|
||||
|
||||
export function useDefaultAction() {
|
||||
return {
|
||||
async run () {}
|
||||
}
|
||||
async run() {},
|
||||
};
|
||||
}
|
||||
|
||||
import { extend } from 'umi-request';
|
||||
|
||||
export const request = extend({
|
||||
prefix: 'http://localhost:23003/api/',
|
||||
timeout: 1000,
|
||||
@ -31,7 +63,7 @@ export async function deleteCollection(name) {
|
||||
params: {
|
||||
filter: {
|
||||
name,
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -44,7 +76,7 @@ export async function createSchema(schema: ISchema) {
|
||||
method: 'post',
|
||||
data: schema.toJSON(),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export async function updateSchema(schema: ISchema) {
|
||||
if (!schema['key']) {
|
||||
@ -52,9 +84,9 @@ export async function updateSchema(schema: ISchema) {
|
||||
}
|
||||
return await request(`ui_schemas:update/${schema.key}`, {
|
||||
method: 'post',
|
||||
data: schema.toJSON(),
|
||||
data: Schema.isSchemaInstance(schema) ? schema.toJSON() : schema,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export async function removeSchema(schema: ISchema) {
|
||||
if (!schema['key']) {
|
||||
@ -65,7 +97,15 @@ export async function removeSchema(schema: ISchema) {
|
||||
params: {
|
||||
filter: {
|
||||
key: schema['key'],
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const [CollectionContextProvider, useCollectionContext] = constate(() => {
|
||||
return useRequest('collections:findAll', {
|
||||
formatResult: (result) => result?.data,
|
||||
});
|
||||
});
|
||||
|
||||
export { CollectionContextProvider, useCollectionContext };
|
||||
|
@ -33,7 +33,6 @@ const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
input: {
|
||||
interface: 'string',
|
||||
type: 'string',
|
||||
title: `编辑模式`,
|
||||
name: 'name1',
|
||||
@ -76,3 +75,58 @@ export default () => {
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Markdown.DesignableBar
|
||||
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { SchemaRenderer } from '../';
|
||||
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
markdown1: {
|
||||
type: 'string',
|
||||
title: `简易Markdown`,
|
||||
default: '这是一段示例文案',
|
||||
'x-read-pretty': true,
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Markdown',
|
||||
'x-designable-bar': 'Markdown.DesignableBar',
|
||||
'x-component-props': {
|
||||
savedInSchema: true,
|
||||
// ellipsis: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
markdown1: {
|
||||
type: 'string',
|
||||
title: `简易Markdown`,
|
||||
default: '这是一段示例文案',
|
||||
'x-read-pretty': true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Markdown',
|
||||
'x-designable-bar': 'Markdown.DesignableBar',
|
||||
'x-component-props': {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<div>
|
||||
<h3>区块项</h3>
|
||||
<SchemaRenderer schema={schema1} />
|
||||
<h3>表单项</h3>
|
||||
<SchemaRenderer schema={schema2} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
@ -1,15 +1,53 @@
|
||||
import React from 'react';
|
||||
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react';
|
||||
import { Input as AntdInput } from 'antd';
|
||||
import {
|
||||
connect,
|
||||
mapProps,
|
||||
mapReadPretty,
|
||||
observer,
|
||||
useField,
|
||||
useFieldSchema,
|
||||
} from '@formily/react';
|
||||
import { Button, Dropdown, Input as AntdInput, Menu, Space } from 'antd';
|
||||
import { InputProps, TextAreaProps } from 'antd/lib/input';
|
||||
import { Display } from '../display';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import { LoadingOutlined, MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||
import micromark from 'micromark';
|
||||
import { useDesignable } from '../../components/schema-renderer';
|
||||
import { useContext, useState } from 'react';
|
||||
import AddNew from '../add-new';
|
||||
import cls from 'classnames';
|
||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||
import { uid } from '@formily/shared';
|
||||
import { removeSchema, updateSchema } from '..';
|
||||
import { isGridRowOrCol } from '../grid';
|
||||
|
||||
export const Markdown = connect(
|
||||
export const Markdown: any = connect(
|
||||
(props) => {
|
||||
const schema = useFieldSchema();
|
||||
return <AntdInput.TextArea defaultValue={schema.name} {...props}/>
|
||||
const { schema } = useDesignable();
|
||||
const field = useField<any>();
|
||||
const { savedInSchema, ...others } = props;
|
||||
console.log('Markdown', props);
|
||||
return savedInSchema ? (
|
||||
<div className={'mb-markdown'} style={{ position: 'relative' }}>
|
||||
<AntdInput.TextArea autoSize={{ minRows: 3 }} {...others} />
|
||||
<Button
|
||||
style={{ position: 'absolute', bottom: 5, right: 5 }}
|
||||
type={'primary'}
|
||||
onClick={async () => {
|
||||
field.readPretty = true;
|
||||
schema['default'] = field.value;
|
||||
await updateSchema({
|
||||
key: schema['key'],
|
||||
default: field.value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<AntdInput.TextArea autoSize={{ minRows: 1 }} {...others} />
|
||||
);
|
||||
},
|
||||
mapProps((props: any, field) => {
|
||||
return {
|
||||
@ -26,6 +64,7 @@ export const Markdown = connect(
|
||||
};
|
||||
}),
|
||||
mapReadPretty((props) => {
|
||||
console.log('Markdown', props);
|
||||
let text = props.value;
|
||||
let value = (
|
||||
<div dangerouslySetInnerHTML={{ __html: micromark(text || '') }} />
|
||||
@ -34,4 +73,61 @@ export const Markdown = connect(
|
||||
}),
|
||||
);
|
||||
|
||||
Markdown.DesignableBar = observer((props) => {
|
||||
const field = useField();
|
||||
const { schema, refresh, deepRemove } = useDesignable();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { dragRef } = useContext(DraggableBlockContext);
|
||||
return (
|
||||
<div className={cls('designable-bar', { active: visible })}>
|
||||
<span
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className={cls('designable-bar-actions', { active: visible })}
|
||||
>
|
||||
<Space size={'small'}>
|
||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||
{dragRef && <DragOutlined ref={dragRef} />}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
visible={visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setVisible(visible);
|
||||
}}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key={'update'}
|
||||
onClick={() => {
|
||||
field.readPretty = false;
|
||||
}}
|
||||
>
|
||||
修改 Markdown
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Item
|
||||
key={'delete'}
|
||||
onClick={async () => {
|
||||
const removed = deepRemove();
|
||||
// console.log({ removed })
|
||||
const last = removed.pop();
|
||||
if (isGridRowOrCol(last)) {
|
||||
await removeSchema(last);
|
||||
}
|
||||
}}
|
||||
>
|
||||
删除当前区块
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined />
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Markdown;
|
||||
|
@ -1,71 +1,59 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
|
||||
export const defaultSchemas = {
|
||||
MixMenu: {
|
||||
type: 'void',
|
||||
'x-component': 'Menu',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component-props': {
|
||||
sideMenuRef: '{{ sideMenuRef }}',
|
||||
mode: 'mix',
|
||||
theme: 'dark',
|
||||
// onSelect: '{{ onSelect }}',
|
||||
export function generateDefaultSchema(component) {
|
||||
const defaultSchemas: { [key: string]: ISchema } = {
|
||||
MixMenu: {
|
||||
type: 'void',
|
||||
'x-component': 'Menu',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component-props': {
|
||||
sideMenuRef: '{{ sideMenuRef }}',
|
||||
mode: 'mix',
|
||||
theme: 'dark',
|
||||
// onSelect: '{{ onSelect }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
'Menu.Item': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Item',
|
||||
},
|
||||
'Menu.Link': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Link',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-component': 'Grid',
|
||||
properties: {
|
||||
[`row_${uid()}`]: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Row',
|
||||
'x-component-props': {
|
||||
locked: true,
|
||||
},
|
||||
properties: {
|
||||
[`col_${uid()}`]: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'AddNew.BlockItem',
|
||||
},
|
||||
},
|
||||
'Menu.Item': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Item',
|
||||
},
|
||||
'Menu.Link': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Link',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Page',
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-component-props': {
|
||||
addNewComponent: 'AddNew.CardItem',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'Menu.URL': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.URL',
|
||||
},
|
||||
'Menu.SubMenu': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.SubMenu',
|
||||
},
|
||||
'Menu.Action': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Action',
|
||||
},
|
||||
};
|
||||
|
||||
export default defaultSchemas;
|
||||
},
|
||||
},
|
||||
'Menu.URL': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.URL',
|
||||
},
|
||||
'Menu.SubMenu': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.SubMenu',
|
||||
},
|
||||
'Menu.Action': {
|
||||
type: 'void',
|
||||
'x-designable-bar': 'Menu.DesignableBar',
|
||||
'x-component': 'Menu.Action',
|
||||
},
|
||||
};
|
||||
return defaultSchemas[component];
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ import './style.less';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { findPropertyByPath, getSchemaPath, useSchemaPath } from '../../';
|
||||
import { request } from '../';
|
||||
import defaultSchemas from './defaultSchemas';
|
||||
import { generateDefaultSchema } from './defaultSchemas';
|
||||
import _, { cloneDeep, get, isNull } from 'lodash';
|
||||
import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
|
||||
import deepmerge from 'deepmerge';
|
||||
@ -369,7 +369,7 @@ Menu.AddNew = observer((props: any) => {
|
||||
</FormLayout>
|
||||
);
|
||||
}).open();
|
||||
const defaults = cloneDeep(defaultSchemas[info.key]);
|
||||
const defaults = generateDefaultSchema(info.key);
|
||||
const data = appendChild(deepmerge(defaults, values));
|
||||
await createSchema(data);
|
||||
}}
|
||||
@ -568,7 +568,7 @@ Menu.DesignableBar = (props) => {
|
||||
insertBefore,
|
||||
appendChild,
|
||||
};
|
||||
const defaults = cloneDeep(defaultSchemas[type]);
|
||||
const defaults = generateDefaultSchema(type);
|
||||
const data = methods[method](deepmerge(defaults, values));
|
||||
await createSchema(data);
|
||||
}}
|
||||
@ -711,11 +711,12 @@ Menu.DesignableBar = (props) => {
|
||||
insertBefore,
|
||||
appendChild,
|
||||
};
|
||||
const data = schema.toJSON();
|
||||
remove();
|
||||
const source = methods[values.method](
|
||||
schema.toJSON(),
|
||||
data,
|
||||
values.path,
|
||||
);
|
||||
remove();
|
||||
await updateSchema(source);
|
||||
}}
|
||||
>
|
||||
|
18
packages/client/src/schemas/page/index.tsx
Normal file
18
packages/client/src/schemas/page/index.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { PageHeader as AntdPageHeader } from 'antd';
|
||||
import { observer } from '@formily/react';
|
||||
import { usePageTitleContext } from '..';
|
||||
|
||||
export const Page = observer((props) => {
|
||||
const { children, ...others } = props;
|
||||
const [pageTitle] = usePageTitleContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<AntdPageHeader ghost={false} title={pageTitle} {...others} />
|
||||
<div style={{margin: 24}}>
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
@ -25,7 +25,7 @@ import constate from 'constate';
|
||||
import useRequest from '@ahooksjs/use-request';
|
||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
|
||||
import { uid, clone } from '@formily/shared';
|
||||
import { MenuOutlined } from '@ant-design/icons';
|
||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
SortableHandle,
|
||||
SortableContainer,
|
||||
@ -34,6 +34,8 @@ import {
|
||||
import cls from 'classnames';
|
||||
import { getSchemaPath, useDesignable, useSchemaPath, VisibleContext } from '../';
|
||||
import './style.less';
|
||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||
import AddNew from '../add-new';
|
||||
|
||||
interface TableRowProps {
|
||||
index: number;
|
||||
@ -632,4 +634,56 @@ Table.Action.DesignableBar = () => {
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Table.DesignableBar = observer((props) => {
|
||||
const field = useField();
|
||||
const { schema, refresh, deepRemove } = useDesignable();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { dragRef } = useContext(DraggableBlockContext);
|
||||
return (
|
||||
<div className={cls('designable-bar', { active: visible })}>
|
||||
<span
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className={cls('designable-bar-actions', { active: visible })}
|
||||
>
|
||||
<Space size={'small'}>
|
||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||
{dragRef && <DragOutlined ref={dragRef} />}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
visible={visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setVisible(visible);
|
||||
}}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key={'update'}
|
||||
onClick={() => {
|
||||
field.readPretty = false;
|
||||
}}
|
||||
>
|
||||
编辑Markdown
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
<Menu.Item
|
||||
key={'delete'}
|
||||
onClick={() => {
|
||||
deepRemove();
|
||||
}}
|
||||
>
|
||||
删除当前区块
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined />
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import { Model } from '@nocobase/database';
|
||||
import deepmerge from 'deepmerge';
|
||||
|
||||
export class UISchema extends Model {
|
||||
static async create(value?: any, options?: any): Promise<any> {
|
||||
@ -33,7 +34,7 @@ export class UISchema extends Model {
|
||||
];
|
||||
const attrs = _.pick(data, keys);
|
||||
const options = _.omit(data, keys);
|
||||
return { ...attrs, options: {...options, ...opts} };
|
||||
return { ...attrs, options: deepmerge(opts, options) };
|
||||
}
|
||||
|
||||
static properties2children(properties = []) {
|
||||
|
Loading…
Reference in New Issue
Block a user