diff --git a/packages/client/src/components/admin-layout/index.tsx b/packages/client/src/components/admin-layout/index.tsx
index fa3efbf7a..df3f68b37 100644
--- a/packages/client/src/components/admin-layout/index.tsx
+++ b/packages/client/src/components/admin-layout/index.tsx
@@ -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 ;
}
- return ;
+ return (
+
+
+
+
+
+ );
}
export default AdminLayout;
diff --git a/packages/client/src/components/schema-renderer/index.tsx b/packages/client/src/components/schema-renderer/index.tsx
index 63371ee74..207ae7638 100644
--- a/packages/client/src/components/schema-renderer/index.tsx
+++ b/packages/client/src/components/schema-renderer/index.tsx
@@ -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();
diff --git a/packages/client/src/schemas/add-new/index.tsx b/packages/client/src/schemas/add-new/index.tsx
index d47e69bd0..bc3e2b663 100644
--- a/packages/client/src/schemas/add-new/index.tsx
+++ b/packages/client/src/schemas/add-new/index.tsx
@@ -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 (
+ {
+ if (visible) {
+ run();
+ }
+ console.log('onVisibleChange', visible);
+ }}
+ placement={'bottomCenter'}
+ overlay={
+
+ }
+ >
+ {ghost ? (
+
+ ) : (
+ }>
+ )}
+
+ );
+});
+
AddNew.BlockItem = observer((props: any) => {
const { ghost, defaultAction } = props;
const { schema, insertBefore, insertAfter } = useDesignable();
const path = useSchemaPath();
return (
@@ -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) => {
}
>
- {ghost ? : }>}
+ {ghost ? (
+
+ ) : (
+ }>
+ )}
);
});
@@ -152,6 +673,10 @@ AddNew.FormItem = observer((props: any) => {
const path = useSchemaPath();
return (
@@ -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) => {
}
>
- {ghost ? : }>}
+ {ghost ? (
+
+ ) : (
+ }>
+ )}
);
});
diff --git a/packages/client/src/schemas/block-item/index.tsx b/packages/client/src/schemas/block-item/index.tsx
index e2e77f6e1..45b3394ca 100644
--- a/packages/client/src/schemas/block-item/index.tsx
+++ b/packages/client/src/schemas/block-item/index.tsx
@@ -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 (
-//
-// {children}
-//
-//
-// );
-// });
-
BlockItem.DesignableBar = () => {
const field = useField();
const { schema, refresh } = useDesignable();
diff --git a/packages/client/src/schemas/card-item/index.tsx b/packages/client/src/schemas/card-item/index.tsx
new file mode 100644
index 000000000..a0c3877ce
--- /dev/null
+++ b/packages/client/src/schemas/card-item/index.tsx
@@ -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 (
+
+
+ {props.children}
+
+
+ );
+});
diff --git a/packages/client/src/schemas/database-field/index.tsx b/packages/client/src/schemas/database-field/index.tsx
index d077c4e24..72636f041 100644
--- a/packages/client/src/schemas/database-field/index.tsx
+++ b/packages/client/src/schemas/database-field/index.tsx
@@ -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();
@@ -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();
}}
/>
@@ -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) {}
}}
diff --git a/packages/client/src/schemas/form/index.tsx b/packages/client/src/schemas/form/index.tsx
index 107415e0d..402bfb9bf 100644
--- a/packages/client/src/schemas/form/index.tsx
+++ b/packages/client/src/schemas/form/index.tsx
@@ -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 (
-
-
-
- 表单配置
-
- }
- >
-
-
-
+
+
{
+ e.stopPropagation();
+ }}
+ className={cls('designable-bar-actions', { active: visible })}
+ >
+
+
+ {dragRef && }
+ {
+ setVisible(visible);
+ }}
+ overlay={
+
+ }
+ >
+
+
+
+
);
-};
+});
diff --git a/packages/client/src/schemas/grid/demos/demo1.tsx b/packages/client/src/schemas/grid/demos/demo1.tsx
index ef1acab81..4de3895d5 100644
--- a/packages/client/src/schemas/grid/demos/demo1.tsx
+++ b/packages/client/src/schemas/grid/demos/demo1.tsx
@@ -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',
diff --git a/packages/client/src/schemas/grid/index.tsx b/packages/client/src/schemas/grid/index.tsx
index c881de031..0bf320e8a 100644
--- a/packages/client/src/schemas/grid/index.tsx
+++ b/packages/client/src/schemas/grid/index.tsx
@@ -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 &&
}
);
@@ -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,
diff --git a/packages/client/src/schemas/index.tsx b/packages/client/src/schemas/index.tsx
index f3a3ec3d9..8a4048967 100644
--- a/packages/client/src/schemas/index.tsx
+++ b/packages/client/src/schemas/index.tsx
@@ -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 };
diff --git a/packages/client/src/schemas/markdown/index.md b/packages/client/src/schemas/markdown/index.md
index e1272d22c..e5cc71d61 100644
--- a/packages/client/src/schemas/markdown/index.md
+++ b/packages/client/src/schemas/markdown/index.md
@@ -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 (
+
+
区块项
+
+ 表单项
+
+
+ );
+};
+```
\ No newline at end of file
diff --git a/packages/client/src/schemas/markdown/index.tsx b/packages/client/src/schemas/markdown/index.tsx
index 797985fdb..270fbb4e8 100644
--- a/packages/client/src/schemas/markdown/index.tsx
+++ b/packages/client/src/schemas/markdown/index.tsx
@@ -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
+ const { schema } = useDesignable();
+ const field = useField();
+ const { savedInSchema, ...others } = props;
+ console.log('Markdown', props);
+ return savedInSchema ? (
+
+
+
+
+ ) : (
+
+ );
},
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 = (
@@ -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 (
+
+
{
+ e.stopPropagation();
+ }}
+ className={cls('designable-bar-actions', { active: visible })}
+ >
+
+
+ {dragRef && }
+ {
+ setVisible(visible);
+ }}
+ overlay={
+
+ }
+ >
+
+
+
+
+
+ );
+});
+
export default Markdown;
diff --git a/packages/client/src/schemas/menu/defaultSchemas.ts b/packages/client/src/schemas/menu/defaultSchemas.ts
index dc9fa6e30..1a0bffce3 100644
--- a/packages/client/src/schemas/menu/defaultSchemas.ts
+++ b/packages/client/src/schemas/menu/defaultSchemas.ts
@@ -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];
+}
diff --git a/packages/client/src/schemas/menu/index.tsx b/packages/client/src/schemas/menu/index.tsx
index ec288b98a..d383f0c54 100644
--- a/packages/client/src/schemas/menu/index.tsx
+++ b/packages/client/src/schemas/menu/index.tsx
@@ -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) => {
);
}).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);
}}
>
diff --git a/packages/client/src/schemas/page/index.tsx b/packages/client/src/schemas/page/index.tsx
new file mode 100644
index 000000000..caa109575
--- /dev/null
+++ b/packages/client/src/schemas/page/index.tsx
@@ -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 (
+ <>
+
+
+ {children}
+
+ >
+ );
+});
diff --git a/packages/client/src/schemas/table/index.tsx b/packages/client/src/schemas/table/index.tsx
index ec34214e9..2c8cd59e3 100644
--- a/packages/client/src/schemas/table/index.tsx
+++ b/packages/client/src/schemas/table/index.tsx
@@ -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 = () => {
);
-};
\ No newline at end of file
+};
+
+Table.DesignableBar = observer((props) => {
+ const field = useField();
+ const { schema, refresh, deepRemove } = useDesignable();
+ const [visible, setVisible] = useState(false);
+ const { dragRef } = useContext(DraggableBlockContext);
+ return (
+
+
{
+ e.stopPropagation();
+ }}
+ className={cls('designable-bar-actions', { active: visible })}
+ >
+
+
+ {dragRef && }
+ {
+ setVisible(visible);
+ }}
+ overlay={
+
+ }
+ >
+
+
+
+
+
+ );
+});
diff --git a/packages/plugin-ui-schema/src/models/ui-schema.ts b/packages/plugin-ui-schema/src/models/ui-schema.ts
index 1352d3b15..2f1544f80 100644
--- a/packages/plugin-ui-schema/src/models/ui-schema.ts
+++ b/packages/plugin-ui-schema/src/models/ui-schema.ts
@@ -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 {
@@ -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 = []) {