updates...

This commit is contained in:
chenos 2021-07-23 12:34:15 +08:00
parent 07fa09e412
commit 19cbcd1e94
41 changed files with 1031 additions and 338 deletions

View File

@ -1,6 +1,6 @@
{ {
"watch": ["packages/", ".env"], "watch": ["packages/", ".env"],
"ignore": ["packages/app"], "ignore": ["packages/app", "packages/client"],
"ext": "ts", "ext": "ts",
"exec": "ts-node -r dotenv/config ./packages/api/src/index.ts" "exec": "ts-node -r dotenv/config ./packages/api/src/index.ts"
} }

View File

@ -1,21 +1,60 @@
import React, { useEffect } from 'react'; import 'antd/dist/antd.css'
import { useRequest } from 'ahooks';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { useMemo } from 'react';
import { import {
RouteSwitch, MemoryRouter as Router,
useGlobalAction, } from 'react-router-dom';
loadBlocks, import {
loadTemplates, createRouteSwitch,
templates, AdminLayout,
AuthLayout,
RouteSchemaRenderer,
} from '@nocobase/client'; } from '@nocobase/client';
import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request';
loadBlocks(); const request = extend({
loadTemplates(); prefix: 'http://localhost:23003/api/',
timeout: 1000,
});
// console.log = () => {}
const RouteSwitch = createRouteSwitch({
components: {
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
},
});
const App = () => {
const { data, loading } = useRequest('routes:getAccessible', {
formatResult: (result) => result?.data,
});
if (loading) {
return <Spin/>
}
return (
<div>
{/* <Router initialEntries={['/admin']}> */}
<RouteSwitch routes={data} />
{/* </Router> */}
</div>
);
};
export default function IndexPage() { export default function IndexPage() {
const { data, loading } = useGlobalAction('routes:getAccessible'); return (
console.log({ data }); <UseRequestProvider
if (loading) { value={{
return <Spin />; requestMethod: (service) => request(service),
} }}
return <RouteSwitch components={templates} routes={data} />; >
<App />
</UseRequestProvider>
);
} }

View File

@ -1,4 +1,4 @@
import { SchemaRenderer } from '@nocobase/client/lib'; import { SchemaRenderer } from '../../';
import React from 'react'; import React from 'react';
export default () => { export default () => {

View File

@ -92,7 +92,7 @@ function LayoutWithMenu({ schema }) {
theme={'light'} theme={'light'}
width={200} width={200}
></Layout.Sider> ></Layout.Sider>
<Layout.Content> <Layout.Content style={{ minHeight: 'calc(100vh - 46px)' }}>
{activeKey && <Content activeKey={activeKey} />} {activeKey && <Content activeKey={activeKey} />}
</Layout.Content> </Layout.Content>
</Layout> </Layout>

View File

@ -19,9 +19,10 @@ import { useMemo } from 'react';
import { CodeOutlined } from '@ant-design/icons'; import { CodeOutlined } from '@ant-design/icons';
import Editor from '@monaco-editor/react'; import Editor from '@monaco-editor/react';
import { ArrayCollapse, ArrayTable, FormLayout, FormItem as FormilyFormItem } from '@formily/antd'; import { ArrayCollapse, FormLayout, FormItem as FormilyFormItem } from '@formily/antd';
import { Space, Card, Modal, Spin } from 'antd'; import { Space, Card, Modal, Spin } from 'antd';
import { ArrayTable } from '../../schemas/array-table';
import { Action } from '../../schemas/action'; import { Action } from '../../schemas/action';
import { AddNew } from '../../schemas/add-new'; import { AddNew } from '../../schemas/add-new';
import { Cascader } from '../../schemas/cascader'; import { Cascader } from '../../schemas/cascader';

View File

@ -727,58 +727,61 @@ AddNew.FormItem = observer((props: any) => {
</Menu.ItemGroup> </Menu.ItemGroup>
<Menu.Divider /> <Menu.Divider />
<Menu.SubMenu title={'新建字段'}> <Menu.SubMenu title={'新建字段'}>
{options.map((option) => ( {options.map(
<Menu.ItemGroup title={option.label}> (option) =>
{option.children.map((item) => ( option.children.length > 0 && (
<Menu.Item <Menu.ItemGroup title={option.label}>
style={{ minWidth: 150 }} {option.children.map((item) => (
key={item.name} <Menu.Item
onClick={async () => { style={{ minWidth: 150 }}
setVisible(false); key={item.name}
const values = await FormDialog(`新增字段`, () => { onClick={async () => {
return ( setVisible(false);
<FormLayout layout={'vertical'}> const values = await FormDialog(`新增字段`, () => {
<SchemaField schema={item} /> return (
</FormLayout> <FormLayout layout={'vertical'}>
); <SchemaField schema={item} />
}).open({ </FormLayout>
initialValues: { );
...item.default, }).open({
key: uid(), initialValues: {
name: `f_${uid()}`, ...item.default,
}, key: uid(),
}); name: `f_${uid()}`,
await createCollectionField(resource.name, values); },
await refresh(); });
let data: ISchema = cloneDeep(values.uiSchema); await createCollectionField(resource.name, values);
data['name'] = values.name; await refresh();
data['referenceKey'] = data['key']; let data: ISchema = cloneDeep(values.uiSchema);
data['key'] = uid(); data['name'] = values.name;
if (isGridBlock(schema)) { data['referenceKey'] = data['key'];
path.pop(); data['key'] = uid();
path.pop(); if (isGridBlock(schema)) {
data = generateGridBlock(data); path.pop();
} else if (isGrid(schema)) { path.pop();
data = generateGridBlock(data); data = generateGridBlock(data);
} } else if (isGrid(schema)) {
if (data) { data = generateGridBlock(data);
let s; }
if (isGrid(schema)) { if (data) {
s = appendChild(data, [...path]); let s;
} else if (defaultAction === 'insertAfter') { if (isGrid(schema)) {
s = insertAfter(data, [...path]); s = appendChild(data, [...path]);
} else { } else if (defaultAction === 'insertAfter') {
s = insertBefore(data, [...path]); s = insertAfter(data, [...path]);
} } else {
await createSchema(s); s = insertBefore(data, [...path]);
} }
}} await createSchema(s);
> }
{item.title} }}
</Menu.Item> >
))} {item.title}
</Menu.ItemGroup> </Menu.Item>
))} ))}
</Menu.ItemGroup>
),
)}
</Menu.SubMenu> </Menu.SubMenu>
{/* <Menu.Divider /> */} {/* <Menu.Divider /> */}
<Menu.Item <Menu.Item

View File

@ -0,0 +1,63 @@
import React from 'react';
import { ArrayTable as Table } from '@formily/antd';
import { useField, Schema } from '@formily/react';
import { Button } from 'antd';
import cls from 'classnames';
import { isValid, uid } from '@formily/shared';
import { PlusOutlined } from '@ant-design/icons';
import { usePrefixCls } from '@formily/antd/lib/__builtins__';
export const ArrayTable = Table;
const getDefaultValue = (defaultValue: any, schema: Schema) => {
if (isValid(defaultValue)) return defaultValue;
if (Array.isArray(schema?.items))
return getDefaultValue(defaultValue, schema.items[0]);
if (schema?.items?.type === 'array') return [];
if (schema?.items?.type === 'boolean') return true;
if (schema?.items?.type === 'date') return '';
if (schema?.items?.type === 'datetime') return '';
if (schema?.items?.type === 'number') return 0;
if (schema?.items?.type === 'object') return {};
if (schema?.items?.type === 'string') return '';
return null;
};
ArrayTable.Addition = (props: any) => {
const { randomValue } = props;
const self = useField();
const array = Table.useArray();
const prefixCls = usePrefixCls('formily-array-base');
if (!array) return null;
if (array.field?.pattern !== 'editable') return null;
return (
<Button
type="dashed"
block
{...props}
className={cls(`${prefixCls}-addition`, props.className)}
onClick={(e) => {
if (array.props?.disabled) return;
const defaultValue = getDefaultValue(props.defaultValue, array.schema);
if (randomValue) {
defaultValue.value = uid();
}
if (props.method === 'unshift') {
array.field?.unshift?.(defaultValue);
array.props?.onAdd?.(0);
} else {
array.field?.push?.(defaultValue);
array.props?.onAdd?.(array?.field?.value?.length - 1);
}
if (props.onClick) {
props.onClick(e);
}
}}
icon={<PlusOutlined />}
>
{props.title || self.title}
</Button>
);
};
export default ArrayTable;

View File

@ -39,7 +39,11 @@ import Modal from 'antd/lib/modal/Modal';
import { clone, cloneDeep, get } from 'lodash'; import { clone, cloneDeep, get } from 'lodash';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { createOrUpdateCollection, deleteCollection, useCollectionContext } from '..'; import {
createOrUpdateCollection,
deleteCollection,
useCollectionContext,
} from '..';
export const DatabaseCollection = observer((props) => { export const DatabaseCollection = observer((props) => {
const field = useField<Formily.Core.Models.ArrayField>(); const field = useField<Formily.Core.Models.ArrayField>();
@ -84,6 +88,10 @@ export const DatabaseCollection = observer((props) => {
<DatabaseOutlined /> <DatabaseOutlined />
</Button> </Button>
<Modal <Modal
bodyStyle={{
overflow: 'auto',
maxHeight: 'calc(100vh - 300px)',
}}
title={ title={
<div style={{ textAlign: 'center' }}> <div style={{ textAlign: 'center' }}>
<Select <Select
@ -139,7 +147,7 @@ export const DatabaseCollection = observer((props) => {
<Select.Option <Select.Option
value={index} value={index}
label={`${item.title || '未命名'}${ label={`${item.title || '未命名'}${
item.unsaved ? ' (未保存)' : '' item.unsaved ? ' (未保存)' : ''
}`} }`}
> >
<div <div
@ -149,7 +157,8 @@ export const DatabaseCollection = observer((props) => {
alignItems: 'center', alignItems: 'center',
}} }}
> >
{item.title || '未命名'} {item.unsaved ? '(未保存)' : ''} {item.title || '未命名'}{' '}
{item.unsaved ? '(未保存)' : ''}
<DeleteOutlined <DeleteOutlined
onClick={async (e) => { onClick={async (e) => {
e.stopPropagation(); e.stopPropagation();
@ -210,10 +219,8 @@ export const DatabaseCollection = observer((props) => {
} }
/> />
{/* <FormConsumer> {/* <FormConsumer>
{form => ( {(form) => <pre>{JSON.stringify(form.values, null, 2)}</pre>}
<pre>{JSON.stringify(form.values, null, 2)}</pre> </FormConsumer> */}
)}
</FormConsumer> */}
</FormLayout> </FormLayout>
)} )}
</Modal> </Modal>
@ -223,11 +230,11 @@ export const DatabaseCollection = observer((props) => {
export const DatabaseField: any = observer((props) => { export const DatabaseField: any = observer((props) => {
const field = useField<Formily.Core.Models.ArrayField>(); const field = useField<Formily.Core.Models.ArrayField>();
useEffect(()=> { useEffect(() => {
if (!field.value) { if (!field.value) {
field.setValue([]); field.setValue([]);
} }
}, []) }, []);
const [activeKey, setActiveKey] = useState(null); const [activeKey, setActiveKey] = useState(null);
console.log('DatabaseField', field); console.log('DatabaseField', field);
return ( return (
@ -241,7 +248,7 @@ export const DatabaseField: any = observer((props) => {
accordion accordion
> >
{field.value?.map((item, index) => { {field.value?.map((item, index) => {
const schema = interfaces.get(item.interface); const schema = cloneDeep(interfaces.get(item.interface));
const path = field.address.concat(index); const path = field.address.concat(index);
const errors = field.form.queryFeedbacks({ const errors = field.form.queryFeedbacks({
type: 'error', type: 'error',
@ -319,13 +326,16 @@ export const DatabaseField: any = observer((props) => {
console.log('info.key', field.value); console.log('info.key', field.value);
}} }}
> >
{options.map((option) => ( {options.map(
<Menu.ItemGroup title={option.label}> (option) =>
{option.children.map((item) => ( option.children.length > 0 && (
<Menu.Item key={item.name}>{item.title}</Menu.Item> <Menu.ItemGroup title={option.label}>
))} {option.children.map((item) => (
</Menu.ItemGroup> <Menu.Item key={item.name}>{item.title}</Menu.Item>
))} ))}
</Menu.ItemGroup>
),
)}
</Menu> </Menu>
} }
> >

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const attachment: ISchema = {
name: 'attachment',
type: 'object',
group: 'media',
title: '附件',
default: {
dataType: 'belongsToMany',
target: 'attachments',
// name,
uiSchema: {
type: 'array',
// title,
'x-component': 'Upload',
'x-decorator': 'FormItem',
'x-designable-bar': 'Upload.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const checkbox: ISchema = {
name: 'checkbox',
type: 'object',
group: 'choices',
order: 1,
title: '勾选',
default: {
dataType: 'boolean',
// name,
uiSchema: {
type: 'boolean',
// title,
'x-component': 'Checkbox',
'x-decorator': 'FormItem',
'x-designable-bar': 'Checkbox.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,30 @@
import { ISchema } from '@formily/react';
import { defaultProps, dataSource } from './properties';
export const checkboxGroup: ISchema = {
name: 'checkboxGroup',
type: 'object',
group: 'choices',
order: 5,
title: '复选框',
default: {
interface: 'checkboxGroup',
dataType: 'json',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Checkbox.Group',
'x-decorator': 'FormItem',
'x-designable-bar': 'Checkbox.Group.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
'uiSchema.enum': dataSource,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,31 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const chinaRegion: ISchema = {
name: 'chinaRegion',
type: 'object',
group: 'choices',
order: 7,
title: '中国行政区划',
default: {
dataType: 'belongsToMany',
target: 'china_regions',
targetKey: 'code',
// name,
uiSchema: {
type: 'array',
// title,
'x-component': 'Cascader',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-designable-bar': 'Cascader.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,31 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const createdAt: ISchema = {
name: 'createdAt',
type: 'object',
group: 'systemInfo',
order: 1,
title: '创建时间',
default: {
dataType: 'date',
field: 'created_at',
// name,
uiSchema: {
type: 'datetime',
// title,
'x-component': 'DatePicker',
'x-component-props': {},
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-designable-bar': 'DatePicker.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,32 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const createdBy: ISchema = {
name: 'createdBy',
type: 'object',
group: 'systemInfo',
order: 3,
title: '创建人',
default: {
dataType: 'belongsTo',
target: 'users',
foreignKey: 'created_by_id',
// name,
uiSchema: {
type: 'object',
// title,
'x-component': 'Select.Drawer',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-read-pretty': true,
'x-designable-bar': 'Select.Drawer.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,29 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const datetime: ISchema = {
name: 'datetime',
type: 'object',
group: 'datetime',
order: 1,
title: '日期',
default: {
dataType: 'date',
// name,
uiSchema: {
type: 'datetime',
// title,
'x-component': 'DatePicker',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-designable-bar': 'DatePicker.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,29 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const email: ISchema = {
name: 'email',
type: 'object',
group: 'basic',
order: 4,
title: '电子邮箱',
default: {
dataType: 'string',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Input',
'x-decorator': 'FormItem',
'x-validator': 'email',
'x-designable-bar': 'Input.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,24 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const icon: ISchema = {
name: 'icon',
type: 'object',
group: 'basic',
order: 8,
title: '图标',
default: {
dataType: 'string',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'IconPicker',
'x-decorator': 'FormItem',
'x-designable-bar': 'IconPicker.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
};

View File

@ -1,10 +1,6 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { set } from 'lodash'; import { set } from 'lodash';
import * as types from './types';
import { select } from './select';
import { string } from './string';
import { subTable } from './subTable';
import { textarea } from './textarea';
export const interfaces = new Map<string, ISchema>(); export const interfaces = new Map<string, ISchema>();
@ -21,20 +17,26 @@ export function registerGroupLabel(key: string, label: string) {
groupLabels[key] = label; groupLabels[key] = label;
} }
registerField('basic', 'string', string); Object.keys(types).forEach((type) => {
registerField('basic', 'textarea', textarea); const schema = types[type];
registerField('choices', 'select', select); registerField(schema.group || 'others', type, { order: 0, ...schema });
registerField('relation', 'subTable', subTable); });
registerGroupLabel('basic', '基本类型'); registerGroupLabel('basic', '基本类型');
registerGroupLabel('choices', '选择类型'); registerGroupLabel('choices', '选择类型');
registerGroupLabel('media', '多媒体类型');
registerGroupLabel('relation', '关系类型'); registerGroupLabel('relation', '关系类型');
registerGroupLabel('systemInfo', '系统信息');
registerGroupLabel('others', '其他类型');
export const options = Object.keys(fields).map((groupName) => { export const options = Object.keys(groupLabels).map(groupName => {
return { return {
label: groupLabels[groupName], label: groupLabels[groupName],
children: Object.keys(fields[groupName]).map((type) => { children: Object.keys(fields[groupName] || {}).map((type) => {
return fields[groupName][type]; return {
}), name: type,
}; ...fields[groupName][type],
};
}).sort((a, b) => a.order - b.order),
}
}); });

View File

@ -0,0 +1,29 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const linkTo: ISchema = {
name: 'linkTo',
type: 'object',
group: 'relation',
order: 1,
title: '关联字段',
default: {
dataType: 'belongsToMany',
// name,
uiSchema: {
type: 'array',
// title,
'x-component': 'Select.Drawer',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-designable-bar': 'Select.Drawer.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,27 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const markdown: ISchema = {
name: 'markdown',
type: 'object',
title: 'Markdown',
group: 'media',
default: {
dataType: 'text',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Markdown',
'x-decorator': 'FormItem',
'x-designable-bar': 'Markdown.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,31 @@
import { ISchema } from '@formily/react';
import { defaultProps, dataSource } from './properties';
export const multipleSelect: ISchema = {
name: 'multipleSelect',
type: 'object',
group: 'choices',
order: 3,
title: '下拉选择(多选)',
default: {
dataType: 'json',
// name,
uiSchema: {
type: 'array',
// title,
'x-component': 'Select',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-designable-bar': 'Select.DesignableBar',
enum: [],
} as ISchema,
},
properties: {
...defaultProps,
'uiSchema.enum': dataSource,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const number: ISchema = {
name: 'number',
type: 'object',
group: 'basic',
order: 5,
title: '数字',
default: {
dataType: 'float',
// name,
uiSchema: {
type: 'number',
// title,
'x-component': 'InputNumber',
'x-decorator': 'FormItem',
'x-designable-bar': 'InputNumber.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const password: ISchema = {
name: 'password',
type: 'object',
group: 'basic',
order: 7,
title: '密码',
default: {
dataType: 'password',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Password',
'x-decorator': 'FormItem',
'x-designable-bar': 'Password.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const percent: ISchema = {
name: 'percent',
type: 'object',
group: 'basic',
order: 6,
title: '百分比',
default: {
dataType: 'float',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'InputNumber',
'x-decorator': 'FormItem',
'x-designable-bar': 'InputNumber.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,29 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const phone: ISchema = {
name: 'phone',
type: 'object',
group: 'basic',
order: 3,
title: '手机号码',
default: {
dataType: 'string',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Input',
'x-decorator': 'FormItem',
"x-validator": 'phone',
'x-designable-bar': 'Input.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,147 @@
import { ISchema } from "@formily/react";
export const dataType: ISchema = {
type: 'string',
title: '数据类型',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'Boolean', value: 'boolean' },
{ label: 'String', value: 'string' },
{ label: 'Text', value: 'text' },
{ label: 'Integer', value: 'integer' },
{ label: 'Float', value: 'float' },
{ label: 'Decimal', value: 'decimal' },
{ label: 'Date', value: 'date' },
{ label: 'DateOnly', value: 'dateonly' },
{ label: 'Time', value: 'time' },
{ label: 'Virtual', value: 'virtual' },
{ label: 'JSON', value: 'json' },
{ label: 'Password', value: 'password' },
{ label: 'HasOne', value: 'hasOne' },
{ label: 'HasMany', value: 'hasMany' },
{ label: 'BelongsTo', value: 'belongsTo' },
{ label: 'BelongsToMany', value: 'belongsToMany' },
],
}
export const dataSource: ISchema = {
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: '选项值' },
"x-hidden": true,
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',
'x-component-props': {
randomValue: true,
},
title: '添加可选项',
},
},
};
export const defaultProps = {
'uiSchema.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,
// 'uiSchema.required': {
// type: 'string',
// title: '必填',
// 'x-decorator': 'FormItem',
// 'x-component': 'Checkbox',
// },
};

View File

@ -0,0 +1,29 @@
import { ISchema } from '@formily/react';
import { defaultProps, dataSource } from './properties';
export const radioGroup: ISchema = {
name: 'radioGroup',
type: 'object',
group: 'choices',
order: 4,
title: '单选框',
default: {
dataType: 'string',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'Radio.Group',
'x-decorator': 'FormItem',
'x-designable-bar': 'Radio.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
'uiSchema.enum': dataSource,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -1,12 +1,13 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { defaultProps, dataSource } from './properties';
export const select: ISchema = { export const select: ISchema = {
name: 'select', name: 'select',
type: 'object', type: 'object',
title: '下拉选择',
group: 'choices', group: 'choices',
order: 2,
title: '下拉选择(单选)',
default: { default: {
interface: 'select',
dataType: 'string', dataType: 'string',
// name, // name,
uiSchema: { uiSchema: {
@ -14,133 +15,13 @@ export const select: ISchema = {
// title, // title,
'x-component': 'Select', 'x-component': 'Select',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-designable-bar': 'Markdown.DesignableBar', 'x-designable-bar': 'Select.DesignableBar',
enum: [], enum: [],
} as ISchema, } as ISchema,
}, },
properties: { properties: {
'uiSchema.title': { ...defaultProps,
type: 'string', 'uiSchema.enum': dataSource,
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' },
],
},
'uiSchema.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: '添加可选项',
},
},
},
'uiSchema.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
}, },
operations: [ operations: [
{ label: '等于', value: 'eq' }, { label: '等于', value: 'eq' },

View File

@ -1,10 +1,12 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const string: ISchema = { export const string: ISchema = {
name: 'string', name: 'string',
type: 'object', type: 'object',
title: '单行文本',
group: 'basic', group: 'basic',
order: 1,
title: '单行文本',
default: { default: {
interface: 'string', interface: 'string',
dataType: 'string', dataType: 'string',
@ -18,38 +20,7 @@ export const string: ISchema = {
} as ISchema, } as ISchema,
}, },
properties: { properties: {
'uiSchema.title': { ...defaultProps,
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' },
],
},
'uiSchema.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
}, },
operations: [ operations: [
{ label: '等于', value: 'eq' }, { label: '等于', value: 'eq' },

View File

@ -1,50 +1,27 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const subTable: ISchema = { export const subTable: ISchema = {
name: 'subTable', name: 'subTable',
type: 'object', type: 'object',
title: '子表格',
group: 'relation', group: 'relation',
order: 2,
title: '子表格',
default: { default: {
interface: 'subTable', dataType: 'hasMany',
// name, // name,
uiSchema: { uiSchema: {
type: 'string', type: 'array',
// title, // title,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Table', 'x-component': 'Table',
'x-designable-bar': 'Markdown.DesignableBar', 'x-component-props': {},
'x-designable-bar': 'Table.DesignableBar',
enum: [], enum: [],
} as ISchema, } as ISchema,
}, },
properties: { properties: {
'uiSchema.title': { ...defaultProps,
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': { 'children': {
type: 'array', type: 'array',
title: '子表格字段', title: '子表格字段',

View File

@ -1,10 +1,12 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const textarea: ISchema = { export const textarea: ISchema = {
name: 'textarea', name: 'textarea',
type: 'object', type: 'object',
title: '多行文本',
group: 'basic', group: 'basic',
order: 2,
title: '多行文本',
default: { default: {
dataType: 'text', dataType: 'text',
// name, // name,
@ -13,42 +15,11 @@ export const textarea: ISchema = {
// title, // title,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Input.TextArea', 'x-component': 'Input.TextArea',
'x-designable-bar': 'Markdown.DesignableBar', 'x-designable-bar': 'Input.DesignableBar',
} as ISchema, } as ISchema,
}, },
properties: { properties: {
'uiSchema.title': { ...defaultProps,
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' },
],
},
'uiSchema.required': {
type: 'string',
title: '必填',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
}, },
operations: [ operations: [
{ label: '等于', value: 'eq' }, { label: '等于', value: 'eq' },

View File

@ -0,0 +1,28 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const time: ISchema = {
name: 'time',
type: 'object',
group: 'datetime',
order: 2,
title: '时间',
default: {
dataType: 'time',
// name,
uiSchema: {
type: 'string',
// title,
'x-component': 'TimePicker',
'x-decorator': 'FormItem',
'x-designable-bar': 'TimePicker.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,24 @@
export * from './attachment';
export * from './checkbox';
export * from './checkboxGroup';
export * from './chinaRegion';
export * from './createdAt';
export * from './createdBy';
export * from './datetime';
export * from './email';
export * from './icon';
export * from './linkTo';
export * from './markdown';
export * from './multipleSelect';
export * from './number';
export * from './password';
export * from './percent';
export * from './phone';
export * from './radioGroup';
export * from './select';
export * from './string';
export * from './subTable';
export * from './textarea';
export * from './time';
export * from './updatedAt';
export * from './updatedBy';

View File

@ -0,0 +1,31 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const updatedAt: ISchema = {
name: 'updatedAt',
type: 'object',
group: 'systemInfo',
order: 2,
title: '最后更新时间',
default: {
dataType: 'date',
field: 'updated_at',
// name,
uiSchema: {
type: 'datetime',
// title,
'x-component': 'DatePicker',
'x-component-props': {},
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-designable-bar': 'DatePicker.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -0,0 +1,32 @@
import { ISchema } from '@formily/react';
import { defaultProps } from './properties';
export const updatedBy: ISchema = {
name: 'updatedBy',
type: 'object',
group: 'systemInfo',
order: 4,
title: '最后修改人',
default: {
dataType: 'belongsTo',
target: 'users',
foreignKey: 'updated_by_id',
// name,
uiSchema: {
type: 'object',
// title,
'x-component': 'Select.Drawer',
'x-component-props': {},
'x-decorator': 'FormItem',
'x-read-pretty': true,
'x-designable-bar': 'Select.Drawer.DesignableBar',
} as ISchema,
},
properties: {
...defaultProps,
},
operations: [
{ label: '等于', value: 'eq' },
{ label: '不等于', value: 'ne' },
],
};

View File

@ -26,6 +26,7 @@ export function generateDefaultSchema(component) {
properties: { properties: {
[uid()]: { [uid()]: {
type: 'void', type: 'void',
async: true,
'x-component': 'Page', 'x-component': 'Page',
properties: { properties: {
[uid()]: { [uid()]: {

View File

@ -86,7 +86,11 @@ const SideMenu = (props: any) => {
<AntdMenu mode={'inline'} onSelect={onSelect}> <AntdMenu mode={'inline'} onSelect={onSelect}>
<RecursionField schema={child} onlyRenderProperties /> <RecursionField schema={child} onlyRenderProperties />
<Menu.AddNew key={uid()} path={[...path, selectedKey]}> <Menu.AddNew key={uid()} path={[...path, selectedKey]}>
<Button className={'nb-add-new-menu-item'} block type={'dashed'}> <Button
block
type={'dashed'}
className={`nb-add-new-menu-item menu-mode-inline`}
>
<PlusOutlined /> <PlusOutlined />
</Button> </Button>
</Menu.AddNew> </Menu.AddNew>
@ -519,8 +523,15 @@ Menu.DesignableBar = (props) => {
const field = useField(); const field = useField();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { designable, schema, remove, refresh, insertAfter, insertBefore, appendChild } = const {
useDesignable(); designable,
schema,
remove,
refresh,
insertAfter,
insertBefore,
appendChild,
} = useDesignable();
const formConfig = schemas[schema['x-component']]; const formConfig = schemas[schema['x-component']];
const isSubMenu = schema['x-component'] === 'Menu.SubMenu'; const isSubMenu = schema['x-component'] === 'Menu.SubMenu';
@ -626,7 +637,7 @@ Menu.DesignableBar = (props) => {
parent = parent.parent; parent = parent.parent;
} }
console.log({ menuSchema }) console.log({ menuSchema });
const toTreeData = (s: Schema) => { const toTreeData = (s: Schema) => {
const items = []; const items = [];
@ -720,10 +731,7 @@ Menu.DesignableBar = (props) => {
}; };
const data = schema.toJSON(); const data = schema.toJSON();
remove(); remove();
const source = methods[values.method]( const source = methods[values.method](data, values.path);
data,
values.path,
);
await updateSchema(source); await updateSchema(source);
}} }}
> >

View File

@ -924,7 +924,12 @@ Table.Action.DesignableBar = () => {
</Menu.Item> </Menu.Item>
)} )}
{inActionBar && <Menu.Item></Menu.Item>} {inActionBar ? (
<Menu.Item></Menu.Item>
) : (
<Menu.Item> &nbsp;&nbsp;<Switch size={'small'} defaultChecked/></Menu.Item>
)}
<Menu.Divider /> <Menu.Divider />
<Menu.Item></Menu.Item> <Menu.Item></Menu.Item>
</Menu> </Menu>

View File

@ -43,10 +43,10 @@ export const create = async (ctx: actions.Context, next: actions.Next) => {
payload: 'replace', payload: 'replace',
}, },
); );
console.log(ctx.action.params.values); // console.log(ctx.action.params.values);
await middlewares.associated(ctx, async () => { }); await middlewares.associated(ctx, async () => { });
await sort(ctx, async () => { }); await sort(ctx, async () => { });
console.log(ctx.body.toJSON()); // console.log(ctx.body.toJSON());
} }
await next(); await next();
}; };
@ -91,10 +91,10 @@ export const update = async (ctx: actions.Context, next: actions.Next) => {
payload: 'replace', payload: 'replace',
}, },
); );
console.log(ctx.action.params.values); // console.log(ctx.action.params.values);
await middlewares.associated(ctx, async () => { }); await middlewares.associated(ctx, async () => { });
await sort(ctx, async () => { }); await sort(ctx, async () => { });
console.log(ctx.body.toJSON()); // console.log(ctx.body.toJSON());
} }
await next(); await next();
}; };
@ -117,7 +117,7 @@ export const getTree = async (ctx: actions.Context, next: actions.Next) => {
sort: ['sort'], sort: ['sort'],
}), }),
); );
console.log({ schemas }); // console.log({ schemas });
let properties = {}; let properties = {};
for (const schema of schemas) { for (const schema of schemas) {
const property = schema.toProperty(); const property = schema.toProperty();

View File

@ -32,6 +32,11 @@ export default {
name: 'options', name: 'options',
defaultValue: {}, defaultValue: {},
}, },
{
type: 'boolean',
name: 'async',
defaultValue: false,
},
{ {
type: 'hasMany', type: 'hasMany',
name: 'children', name: 'children',

View File

@ -69,6 +69,9 @@ export class UISchema extends Model {
async getProperties() { async getProperties() {
const properties = {}; const properties = {};
const children: UISchema[] = await this.getChildren({ const children: UISchema[] = await this.getChildren({
where: {
async: false,
},
order: [['sort', 'asc']], order: [['sort', 'asc']],
}); });
for (const child of children) { for (const child of children) {