This commit is contained in:
chenos 2021-07-09 23:58:05 +08:00
parent 708afa059c
commit 15fca2b009
10 changed files with 372 additions and 341 deletions

View File

@ -16,6 +16,7 @@ import {
useField,
useFieldSchema,
useForm,
SchemaOptionsContext,
} from '@formily/react';
import { observable } from '@formily/reactive';
import { uid, clone } from '@formily/shared';
@ -58,6 +59,7 @@ import { DragAndDrop } from '../drag-and-drop';
import { CodeOutlined } from '@ant-design/icons';
import Editor from '@monaco-editor/react';
import { get } from 'lodash';
export const BlockContext = createContext({ dragRef: null });
@ -187,10 +189,13 @@ export function addPropertyAfter(target: Schema, data: ISchema) {
export function useDesignable(path?: any) {
const { schema, refresh } = useContext(DesignableContext);
const schemaPath = path || useSchemaPath();
const currentSchema = findPropertyByPath(schema, schemaPath);
const currentSchema = findPropertyByPath(schema, schemaPath) || ({} as Schema);
console.log('useDesignable', { schema, schemaPath, currentSchema });
const options = useContext(SchemaOptionsContext);
const DesignableBar = get(options.components, currentSchema['x-designable-bar']) || (() => null);
return {
schema: currentSchema || ({} as Schema),
DesignableBar,
schema: currentSchema,
refresh,
prepend: (property: ISchema, targetPath?: any): Schema => {
let target = currentSchema;

View File

@ -17,7 +17,7 @@ group:
- 弹出层操作,弹出层可以是 Action.Drawer、Action.Modal、Action.Popover
- 指定容器内打开: Action.Container
- 下拉菜单Action.Dropdown用于收纳多种操作
- 跳转操作Action.Link、Action.URL 和 Action.Route
- 跳转操作Action.Link、Action.URL
Action.Drawer、Action.Modal、Action.Popover 和 Action.Container 需要和 Action 搭配使用

View File

@ -27,23 +27,9 @@ import {
} from '../../components/drag-and-drop';
import cls from 'classnames';
function Blank() {
return null;
}
function useDesignableBar() {
const schema = useFieldSchema();
const options = useContext(SchemaOptionsContext);
const DesignableBar = get(options.components, schema['x-designable-bar']);
return {
DesignableBar: DesignableBar || Blank,
};
}
const DraggableBlock = (props) => {
const { children, ...others } = props;
const { DesignableBar } = useDesignableBar();
const { DesignableBar } = useDesignable();
const { isDragging, dragRef, previewRef, isOver, onTopHalf, dropRef } =
useBlockDragAndDrop();
const schema = useFieldSchema();
@ -102,9 +88,22 @@ const DraggableBlock = (props) => {
};
const Block = (props) => {
const { DesignableBar } = useDesignable();
const [active, setActive] = useState(false);
return (
<div className={cls('nb-grid-block', 'designable-form-item')}>
<div
onMouseEnter={(e) => {
setActive(true);
console.log('e.onMouseEnter', new Date().toString());
}}
onMouseLeave={(e) => {
setActive(false);
console.log('e.onMouseLeave', new Date().toString());
}}
className={cls('nb-grid-block', 'designable-form-item', { active })}
>
{props.children}
<DesignableBar />
</div>
);
};

View File

@ -28,14 +28,20 @@ const schema = {
{
id: 1,
interface: 'string',
type: 'string',
dataType: 'string',
name: 'title',
ui: {
title: '标题',
},
},
{
id: 2,
type: 'text',
dataType: 'text',
interface: 'textarea',
name: 'content',
ui: {
title: '内容',
},
},
],
},

View File

@ -11,296 +11,9 @@ import {
import { ArrayCollapse } from '@formily/antd';
import { uid } from '@formily/shared';
import '@formily/antd/lib/form-tab/style';
import { Collapse, Button, Dropdown, Menu } from 'antd';
const interfaces = new Map<string, ISchema>();
interfaces.set('string', {
type: 'object',
default: {
type: 'string',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Input',
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
title: '字段名称',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
title: '字段标识',
required: true,
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
type: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
});
interfaces.set('textarea', {
type: 'object',
default: {
type: 'text',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Input.TextArea',
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
type: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
});
interfaces.set('subTable', {
type: 'object',
default: {
type: 'string',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Select',
enum: [],
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
type: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
{ label: 'HasMany', value: 'hasMany' },
],
},
'children': {
type: 'array',
title: '子表格字段',
'x-decorator': 'FormItem',
'x-component': 'DatabaseField',
},
// 'ui.required': {
// type: 'string',
// title: '必填',
// 'x-decorator': 'FormItem',
// 'x-component': 'Checkbox',
// },
},
});
interfaces.set('select', {
type: 'object',
default: {
type: 'string',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Select',
enum: [],
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
type: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.enum': {
type: 'array',
title: '可选项',
'x-decorator': 'FormItem',
'x-component': 'ArrayTable',
'x-component-props': {
pagination: false,
// scroll: { x: '100%' },
},
items: {
type: 'object',
properties: {
column1: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 50, title: '', align: 'center' },
properties: {
sort: {
type: 'void',
'x-component': 'ArrayTable.SortHandle',
},
},
},
column2: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '选项值' },
properties: {
value: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column3: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '选项' },
properties: {
label: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column4: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '颜色' },
properties: {
color: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'ColorSelect',
},
},
},
column5: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
title: '',
dataIndex: 'operations',
fixed: 'right',
},
properties: {
item: {
type: 'void',
'x-component': 'FormItem',
properties: {
remove: {
type: 'void',
'x-component': 'ArrayTable.Remove',
},
},
},
},
},
},
},
properties: {
add: {
type: 'void',
'x-component': 'ArrayTable.Addition',
title: '添加可选项',
},
},
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
});
import { Collapse, Button, Dropdown, Menu, Tag } from 'antd';
import { interfaces } from './interfaces';
import { DeleteOutlined } from '@ant-design/icons';
export const DatabaseField: any = observer((props) => {
const field = useField<Formily.Core.Models.ArrayField>();
@ -308,9 +21,13 @@ export const DatabaseField: any = observer((props) => {
const [activeKey, setActiveKey] = useState(null);
return (
<div>
<Collapse activeKey={activeKey} onChange={(key) => {
setActiveKey(key);
}} accordion>
<Collapse
activeKey={activeKey}
onChange={(key) => {
setActiveKey(key);
}}
accordion
>
{field.value?.map((item, index) => {
const schema = interfaces.get(item.interface);
console.log({ schema });
@ -332,31 +49,39 @@ export const DatabaseField: any = observer((props) => {
// ]}
header={
<>
{item.ui && item.ui.title}
{' '}
{item.name}
{(item.ui && item.ui.title) || <i style={{color: 'rgba(0, 0, 0, 0.25)'}}></i>}{' '}
<Tag>{schema.title}</Tag>
</>
}
extra={[
<DeleteOutlined
onClick={() => {
field.remove(index);
}}
/>,
]}
key={item.id}
>
<RecursionField
key={`${item.id}_${index}`}
name={index}
schema={new Schema({
type: 'object',
properties: {
layout: {
type: 'void',
'x-component': 'FormLayout',
'x-component-props': {
layout: 'vertical',
// labelCol: 4,
// wrapperCol: 20,
schema={
new Schema({
type: 'object',
properties: {
layout: {
type: 'void',
'x-component': 'FormLayout',
'x-component-props': {
layout: 'vertical',
// labelCol: 4,
// wrapperCol: 20,
},
properties: schema.properties,
},
properties: schema.properties,
},
},
})}
})
}
/>
</Collapse.Panel>
);
@ -369,7 +94,7 @@ export const DatabaseField: any = observer((props) => {
}}
overlay={
<Menu
onClick={info => {
onClick={(info) => {
const schema = interfaces.get(info.key);
if (!schema) {
return;
@ -378,25 +103,20 @@ export const DatabaseField: any = observer((props) => {
id: uid(),
name: uid(),
interface: info.key,
...schema.default
...schema.default,
};
field.push(data);
setActiveKey(data.id);
console.log('info.key', info.key, schema);
}}
>
<Menu.Item key={'string'}></Menu.Item>
<Menu.Item key={'textarea'}></Menu.Item>
<Menu.Item key={'select'}></Menu.Item>
<Menu.Item key={'subTable'}></Menu.Item>
{Array.from(interfaces).map(([key, schema]) => (
<Menu.Item key={key}>{schema.title}</Menu.Item>
))}
</Menu>
}
>
<Button
block
type={'dashed'}
style={{ marginTop: 10 }}
>
<Button block type={'dashed'} style={{ marginTop: 10 }}>
</Button>
</Dropdown>

View File

@ -0,0 +1,13 @@
import { ISchema } from '@formily/react';
import { select } from './select';
import { string } from './string';
import { subTable } from './subTable';
import { textarea } from './textarea';
export const interfaces = new Map<string, ISchema>();
interfaces.set('select', select);
interfaces.set('string', string);
interfaces.set('subTable', subTable);
interfaces.set('textarea', textarea);

View File

@ -0,0 +1,140 @@
import { ISchema } from '@formily/react';
export const select: ISchema = {
type: 'object',
title: '下拉选择',
default: {
dataType: 'string',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Select',
enum: [],
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
dataType: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.enum': {
type: 'array',
title: '可选项',
'x-decorator': 'FormItem',
'x-component': 'ArrayTable',
'x-component-props': {
pagination: false,
// scroll: { x: '100%' },
},
items: {
type: 'object',
properties: {
column1: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { width: 50, title: '', align: 'center' },
properties: {
sort: {
type: 'void',
'x-component': 'ArrayTable.SortHandle',
},
},
},
column2: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '选项值' },
properties: {
value: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column3: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '选项' },
properties: {
label: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
},
column4: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': { title: '颜色' },
properties: {
color: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'ColorSelect',
},
},
},
column5: {
type: 'void',
'x-component': 'ArrayTable.Column',
'x-component-props': {
title: '',
dataIndex: 'operations',
fixed: 'right',
},
properties: {
item: {
type: 'void',
'x-component': 'FormItem',
properties: {
remove: {
type: 'void',
'x-component': 'ArrayTable.Remove',
},
},
},
},
},
},
},
properties: {
add: {
type: 'void',
'x-component': 'ArrayTable.Addition',
title: '添加可选项',
},
},
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
};

View File

@ -0,0 +1,49 @@
import { ISchema } from '@formily/react';
export const string: ISchema = {
type: 'object',
title: '单行文本',
default: {
dataType: 'string',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Input',
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
title: '字段名称',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
title: '字段标识',
required: true,
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
dataType: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
};

View File

@ -0,0 +1,50 @@
import { ISchema } from '@formily/react';
export const subTable: ISchema = {
type: 'object',
title: '子表格',
default: {
// name,
ui: {
type: 'string',
// title,
'x-component': 'Select',
enum: [],
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
dataType: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
{ label: 'HasMany', value: 'hasMany' },
],
},
'children': {
type: 'array',
title: '子表格字段',
'x-decorator': 'FormItem',
'x-component': 'DatabaseField',
},
},
};

View File

@ -0,0 +1,49 @@
import { ISchema } from '@formily/react';
export const textarea: ISchema = {
type: 'object',
title: '多行文本',
default: {
dataType: 'text',
// name,
ui: {
type: 'string',
// title,
'x-component': 'Input.TextArea',
} as ISchema,
},
properties: {
'ui.title': {
type: 'string',
required: true,
title: '字段名称',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
name: {
type: 'string',
required: true,
title: '字段标识',
'x-disabled': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
dataType: {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
],
},
'ui.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
};