import React, { Children, createContext, useContext, useEffect, useState, } from 'react'; import { FormDialog, FormLayout } from '@formily/antd'; import { connect, observer, mapProps, mapReadPretty, useField, useFieldSchema, RecursionField, Schema, ISchema, useForm, } from '@formily/react'; import { Menu, MenuProps, MenuItemProps, SubMenuProps, DividerProps, Dropdown, Modal, Button, Spin, Switch, Checkbox, } from 'antd'; import { MenuOutlined, GroupOutlined, PlusOutlined, LinkOutlined, AppstoreAddOutlined, EditOutlined, DeleteOutlined, ArrowRightOutlined, SettingOutlined, ArrowUpOutlined, ArrowDownOutlined, LoadingOutlined, DownOutlined, DatabaseOutlined, } from '@ant-design/icons'; import { createCollectionField, createOrUpdateCollection, createSchema, removeSchema, useDesignable, useSchemaPath, } from '../'; import { uid } from '@formily/shared'; import { getSchemaPath, SchemaField } from '../../components/schema-renderer'; import { cloneDeep } from 'lodash'; import { options } from '../database-field/interfaces'; import './style.less'; import IconPicker from '../../components/icon-picker'; import { barChartConfig, columnChartConfig } from './chart'; import { isGridRowOrCol } from '../grid'; import { useCollectionContext, useCollectionsContext, useDisplayedMapContext, } from '../../constate'; import SwitchMenuItem from '../../components/SwitchMenuItem'; const generateGridBlock = (schema: ISchema) => { const name = schema.name || uid(); return { type: 'void', name: uid(), 'x-component': 'Grid.Row', properties: { [uid()]: { type: 'void', 'x-component': 'Grid.Col', properties: { [name]: schema, }, }, }, }; }; const isGrid = (schema: Schema) => { return schema['x-component'] === 'Grid'; }; const isGridBlock = (schema: Schema) => { if (schema.parent['x-component'] !== 'Grid.Col') { return false; } // Grid.Col 里有多少 Block if (Object.keys(schema.parent.properties).length > 1) { return false; } // 有多少 Grid.Row if (Object.keys(schema.parent.parent.properties).length > 1) { return false; } return true; }; function generateCardItemSchema(component) { const defaults = { 'Markdown.Void': { type: 'void', default: '这是一段演示文字,**支持使用 Markdown 语法**', 'x-designable-bar': 'Markdown.Void.DesignableBar', 'x-decorator': 'CardItem', 'x-read-pretty': true, 'x-component': 'Markdown.Void', }, 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() }, ], 'x-component-props': { rowKey: 'id', dragSort: true, showIndex: true, refreshRequestOnChange: true, pagination: { pageSize: 10, }, }, properties: { [uid()]: { type: 'void', 'x-component': 'Table.ActionBar', 'x-designable-bar': 'Table.ActionBar.DesignableBar', properties: { [uid()]: { type: 'void', title: '筛选', 'x-decorator': 'AddNew.Displayed', 'x-decorator-props': { displayName: 'filter', }, 'x-align': 'left', 'x-component': 'Table.Filter', 'x-designable-bar': 'Table.Filter.DesignableBar', 'x-component-props': { fieldNames: [], }, }, [uid()]: { type: 'void', name: 'action1', title: '新增', 'x-align': 'right', 'x-decorator': 'AddNew.Displayed', 'x-decorator-props': { displayName: 'create', }, 'x-component': 'Action', 'x-designable-bar': 'Table.Action.DesignableBar', properties: { modal: { type: 'void', title: '新增数据', 'x-decorator': 'Form', 'x-component': 'Action.Modal', 'x-component-props': { useOkAction: '{{ Table.useTableCreateAction }}', }, properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, }, }, }, }, }, [uid()]: { type: 'void', name: 'action1', title: '删除', 'x-align': 'right', 'x-decorator': 'AddNew.Displayed', 'x-decorator-props': { displayName: 'destroy', }, 'x-component': 'Action', 'x-designable-bar': 'Table.Action.DesignableBar', 'x-component-props': { useAction: '{{ Table.useTableDestroyAction }}', }, }, }, }, [uid()]: { type: 'void', title: '操作', 'x-component': 'Table.Column', 'x-component-props': { className: 'nb-table-operation', }, 'x-designable-bar': 'Table.OperationDesignableBar', properties: { [uid()]: { type: 'void', 'x-component': 'Action.Dropdown', 'x-component-props': { buttonProps: { icon: 'EllipsisOutlined', }, }, properties: { [uid()]: { type: 'void', title: '操作 1', 'x-component': 'Menu.Action', 'x-component-props': { style: { minWidth: 150, }, disabled: true, }, }, [uid()]: { type: 'void', name: 'action1', title: '查看', 'x-component': 'Menu.Action', 'x-designable-bar': 'Table.Action.DesignableBar', properties: { [uid()]: { type: 'void', title: '查看', 'x-component': 'Action.Modal', 'x-component-props': { bodyStyle: { background: '#f0f2f5', paddingTop: 0, }, }, properties: { [uid()]: { type: 'void', 'x-component': 'Tabs', properties: { [uid()]: { type: 'void', 'x-component': 'Tabs.TabPane', 'x-component-props': { tab: 'Tab1', }, properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.PaneItem', }, }, }, }, }, }, }, }, }, }, [uid()]: { type: 'void', title: '编辑', 'x-component': 'Menu.Action', 'x-designable-bar': 'Table.Action.DesignableBar', properties: { [uid()]: { type: 'void', title: '编辑数据', 'x-decorator': 'Form', 'x-decorator-props': { useResource: '{{ Table.useResource }}', useValues: '{{ Table.useTableRowRecord }}', }, 'x-component': 'Action.Modal', 'x-component-props': { useOkAction: '{{ Table.useTableUpdateAction }}', }, properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, }, }, }, }, }, [uid()]: { type: 'void', title: '删除', 'x-component': 'Menu.Action', 'x-component-props': { useAction: '{{ Table.useTableDestroyAction }}', }, }, }, }, }, }, }, }, Form: { type: 'void', name: uid(), 'x-decorator': 'CardItem', 'x-component': 'Form', 'x-component-props': { showDefaultButtons: true, }, 'x-designable-bar': 'Form.DesignableBar', properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, }, }, }, 'Chart.Column': { type: 'void', 'x-decorator': 'CardItem', 'x-component': 'Chart.Column', 'x-designable-bar': 'Chart.DesignableBar', 'x-component-props': { config: cloneDeep(columnChartConfig), }, }, 'Chart.Bar': { type: 'void', 'x-decorator': 'CardItem', 'x-component': 'Chart.Bar', 'x-designable-bar': 'Chart.DesignableBar', 'x-component-props': { config: cloneDeep(barChartConfig), }, }, }; 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 { collections = [], loading, refresh } = useCollectionsContext(); return ( { console.log('onVisibleChange', visible); }} overlay={ { let data: ISchema; let collectionName = null; if (['addNewTable', 'addNewForm'].includes(info.key)) { const values = await FormDialog(`新建数据表`, () => { return ( ); }).open({ initialValues: { name: `t_${uid()}`, fields: [], }, }); await createOrUpdateCollection(values); refresh(); data = generateCardItemSchema( info.key === 'addNewTable' ? 'Table' : 'Form', ); collectionName = values.name; } else if (info.key.startsWith('collection.')) { const keys = info.key.split('.'); const component = keys.pop(); const tableName = keys.pop(); collectionName = tableName; data = generateCardItemSchema(component); console.log('info.keyPath', component, tableName); } else { data = generateCardItemSchema(info.key); console.log('generateCardItemSchema', data, info.key); } if (schema['key']) { data['key'] = uid(); } if (collectionName) { data['x-component-props'] = data['x-component-props'] || {}; data['x-component-props']['resource'] = collectionName; data['x-component-props']['collectionName'] = collectionName; } 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); } }} > {[ { key: 'Table', title: '表格', icon: 'TableOutlined' }, { key: 'Form', title: '表单', icon: 'FormOutlined' }, { key: 'Calendar', title: '日历', icon: 'CalendarOutlined', disabled: true, }, { key: 'Kanban', title: '看板', icon: 'CreditCardOutlined', disabled: true, }, ].map((view) => ( } disabled={view.disabled} key={view.key} title={view.title} > {collections?.map((item) => ( {item.title} ))} } key={`addNew${view.key}`}> 新建数据表 ))} } > Markdown } > 富文本 } > 柱状图 } > 条形图 } > 折线图 } > 饼图 模板1 新建模板 } > {ghost ? ( ) : ( )} ); }); AddNew.FormItem = observer((props: any) => { const { ghost, defaultAction } = props; const { schema, insertBefore, insertAfter, appendChild, deepRemove } = useDesignable(); const path = useSchemaPath(); const { collection, fields, refresh } = useCollectionContext(); const [visible, setVisible] = useState(false); const displayed = useDisplayedMapContext(); return ( {fields?.map((field) => ( { if (!checked) { const s: any = displayed.get(field.name); const p = getSchemaPath(s); const removed = deepRemove(p); if (!removed) { console.log('getSchemaPath', p, removed); return; } const last = removed.pop(); displayed.remove(field.name); if (isGridRowOrCol(last)) { await removeSchema(last); } return; } let data: ISchema = { key: uid(), type: 'void', 'x-decorator': 'Form.Field.Item', 'x-designable-bar': 'Form.Field.DesignableBar', 'x-component': 'Form.Field', 'x-component-props': { fieldName: field.name, }, }; 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); } }} /> ))} {options.map( (option) => option.children.length > 0 && ( {option.children.map((item) => ( { setVisible(false); const values = await FormDialog(`新增字段`, () => { return ( ); }).open({ initialValues: { interface: item.name, ...item.default, key: uid(), name: `f_${uid()}`, }, }); await createCollectionField(collection?.name, values); await refresh(); let data: ISchema = cloneDeep(values.uiSchema); data['name'] = values.name; data['referenceKey'] = data['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); } }} > {item.title} ))} ), )} {/* */} { let data: ISchema = { type: 'void', default: '这是一段演示文字,**支持使用 Markdown 语法**', 'x-designable-bar': 'Markdown.Void.DesignableBar', 'x-decorator': 'FormItem', 'x-read-pretty': true, 'x-component': 'Markdown.Void', }; 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]); } console.log('ISchema', schema, data, path); await createSchema(s); } setVisible(false); }} > 添加说明文字 } > {ghost ? ( ) : ( )} ); }); AddNew.PaneItem = observer((props: any) => { const { ghost, defaultAction } = props; const { schema, insertBefore, insertAfter, appendChild } = useDesignable(); const path = useSchemaPath(); const [visible, setVisible] = useState(false); return ( } onClick={async () => { let data: ISchema = { type: 'void', name: uid(), 'x-decorator': 'CardItem', 'x-component': 'Form', 'x-read-pretty': true, 'x-component-props': { useResource: '{{ Table.useResource }}', useValues: '{{ Table.useTableRowRecord }}', }, 'x-designable-bar': 'Form.DesignableBar', properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, }, }, }; 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); } setVisible(false); }} style={{ minWidth: 150 }} > 详情 } onClick={async () => { let data: ISchema = { type: 'void', name: uid(), 'x-decorator': 'CardItem', 'x-component': 'Form', 'x-component-props': { useResource: '{{ Table.useResource }}', useValues: '{{ Table.useTableRowRecord }}', showDefaultButtons: true, }, 'x-designable-bar': 'Form.DesignableBar', properties: { [uid()]: { type: 'void', 'x-component': 'Grid', 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, }, }, }; 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); } setVisible(false); }} > 表单 } > 日志 }> 评论 } onClick={async () => { let data: ISchema = { key: uid(), type: 'void', default: '这是一段演示文字,**支持使用 Markdown 语法**', 'x-designable-bar': 'Markdown.Void.DesignableBar', 'x-decorator': 'CardItem', 'x-read-pretty': true, 'x-component': 'Markdown.Void', }; 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); } setVisible(false); }} > Markdown } > {ghost ? ( ) : ( )} ); }); AddNew.Displayed = observer((props: any) => { const { displayName, children } = props; const displayed = useDisplayedMapContext(); const { schema } = useDesignable(); useEffect(() => { if (displayName) { displayed.set(displayName, schema); } }, [displayName, schema]); return children; }); export default AddNew;