updates
This commit is contained in:
parent
2606f28059
commit
97ca17bc10
@ -47,6 +47,7 @@ import { Upload } from '../../schemas/upload';
|
|||||||
import { FormItem } from '../../schemas/form-item';
|
import { FormItem } from '../../schemas/form-item';
|
||||||
import { BlockItem } from '../../schemas/block-item';
|
import { BlockItem } from '../../schemas/block-item';
|
||||||
import { DragAndDrop } from '../../schemas/drag-and-drop';
|
import { DragAndDrop } from '../../schemas/drag-and-drop';
|
||||||
|
import { TreeSelect } from '../../schemas/tree-select';
|
||||||
|
|
||||||
export const BlockContext = createContext({ dragRef: null });
|
export const BlockContext = createContext({ dragRef: null });
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ export const SchemaField = createSchemaField({
|
|||||||
ArrayCollapse,
|
ArrayCollapse,
|
||||||
ArrayTable,
|
ArrayTable,
|
||||||
FormLayout,
|
FormLayout,
|
||||||
|
TreeSelect,
|
||||||
|
|
||||||
DragAndDrop,
|
DragAndDrop,
|
||||||
|
|
||||||
@ -175,15 +177,21 @@ export function useDesignable(path?: any) {
|
|||||||
const { schema = new Schema({}), refresh } = useContext(DesignableContext);
|
const { schema = new Schema({}), refresh } = useContext(DesignableContext);
|
||||||
const schemaPath = path || useSchemaPath();
|
const schemaPath = path || useSchemaPath();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const currentSchema =
|
let currentSchema =
|
||||||
findPropertyByPath(schema, schemaPath) || ({} as Schema);
|
findPropertyByPath(schema, schemaPath) || ({} as Schema);
|
||||||
|
if (!currentSchema) {
|
||||||
|
currentSchema = fieldSchema;
|
||||||
|
}
|
||||||
|
if (Object.keys(currentSchema).length === 0) {
|
||||||
|
currentSchema = fieldSchema;
|
||||||
|
}
|
||||||
// console.log('useDesignable', { schema, schemaPath, currentSchema });
|
// console.log('useDesignable', { schema, schemaPath, currentSchema });
|
||||||
const options = useContext(SchemaOptionsContext);
|
const options = useContext(SchemaOptionsContext);
|
||||||
const DesignableBar =
|
const DesignableBar =
|
||||||
get(options.components, currentSchema['x-designable-bar']) || (() => null);
|
get(options.components, currentSchema['x-designable-bar']) || (() => null);
|
||||||
return {
|
return {
|
||||||
DesignableBar,
|
DesignableBar,
|
||||||
schema: currentSchema || fieldSchema,
|
schema: currentSchema,
|
||||||
refresh,
|
refresh,
|
||||||
prepend: (property: ISchema, targetPath?: any): Schema => {
|
prepend: (property: ISchema, targetPath?: any): Schema => {
|
||||||
let target = currentSchema;
|
let target = currentSchema;
|
||||||
|
@ -42,6 +42,12 @@ import {
|
|||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
GroupOutlined,
|
GroupOutlined,
|
||||||
LinkOutlined,
|
LinkOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
ArrowUpOutlined,
|
||||||
|
ArrowDownOutlined,
|
||||||
|
ArrowRightOutlined,
|
||||||
|
DragOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { IconPicker } from '../../components/icon-picker';
|
import { IconPicker } from '../../components/icon-picker';
|
||||||
import {
|
import {
|
||||||
@ -54,12 +60,13 @@ import {
|
|||||||
import { useMount } from 'ahooks';
|
import { useMount } from 'ahooks';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { findPropertyByPath, useSchemaPath } from '@nocobase/client/lib';
|
import { findPropertyByPath, getSchemaPath, useSchemaPath } from '../../';
|
||||||
import { request } from '../';
|
import { request } from '../';
|
||||||
import defaultSchemas from './defaultSchemas';
|
import defaultSchemas from './defaultSchemas';
|
||||||
import _, { cloneDeep, get, isNull } from 'lodash';
|
import _, { cloneDeep, get, isNull } from 'lodash';
|
||||||
import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
|
import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
|
||||||
import deepmerge from 'deepmerge';
|
import deepmerge from 'deepmerge';
|
||||||
|
import { onFieldChange } from '@formily/core';
|
||||||
|
|
||||||
export const MenuModeContext = createContext(null);
|
export const MenuModeContext = createContext(null);
|
||||||
|
|
||||||
@ -91,6 +98,8 @@ const SideMenu = (props: any) => {
|
|||||||
export const Menu: any = observer((props: any) => {
|
export const Menu: any = observer((props: any) => {
|
||||||
const { mode, onSelect, sideMenuRef, ...others } = props;
|
const { mode, onSelect, sideMenuRef, ...others } = props;
|
||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
console.log('Menu.schema', schema, fieldSchema);
|
||||||
const [selectedKey, setSelectedKey] = useState(null);
|
const [selectedKey, setSelectedKey] = useState(null);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const path = useSchemaPath();
|
const path = useSchemaPath();
|
||||||
@ -134,7 +143,9 @@ export const Menu: any = observer((props: any) => {
|
|||||||
<Menu.AddNew key={uid()} path={path}>
|
<Menu.AddNew key={uid()} path={path}>
|
||||||
{/* <PlusOutlined className={'nb-add-new-icon'} /> */}
|
{/* <PlusOutlined className={'nb-add-new-icon'} /> */}
|
||||||
<Button
|
<Button
|
||||||
className={`nb-add-new-menu-item menu-mode-${mode === 'mix' ? 'horizontal' : mode}`}
|
className={`nb-add-new-menu-item menu-mode-${
|
||||||
|
mode === 'mix' ? 'horizontal' : mode
|
||||||
|
}`}
|
||||||
block
|
block
|
||||||
type={mode == 'inline' ? 'dashed' : 'primary'}
|
type={mode == 'inline' ? 'dashed' : 'primary'}
|
||||||
>
|
>
|
||||||
@ -386,7 +397,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
const schemas = {
|
const schemas = {
|
||||||
'Menu.Action': {
|
'Menu.Action': {
|
||||||
icon: <MenuOutlined />,
|
icon: <MenuOutlined />,
|
||||||
title: '修改菜单项',
|
title: '菜单项',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -408,7 +419,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
},
|
},
|
||||||
'Menu.Item': {
|
'Menu.Item': {
|
||||||
icon: <MenuOutlined />,
|
icon: <MenuOutlined />,
|
||||||
title: '修改菜单项',
|
title: '菜单项',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -430,7 +441,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
},
|
},
|
||||||
'Menu.Link': {
|
'Menu.Link': {
|
||||||
icon: <MenuOutlined />,
|
icon: <MenuOutlined />,
|
||||||
title: '修改菜单项',
|
title: '菜单项',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -452,7 +463,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
},
|
},
|
||||||
'Menu.SubMenu': {
|
'Menu.SubMenu': {
|
||||||
icon: <GroupOutlined />,
|
icon: <GroupOutlined />,
|
||||||
title: '修改菜单分组',
|
title: '菜单分组',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -474,7 +485,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
},
|
},
|
||||||
'Menu.URL': {
|
'Menu.URL': {
|
||||||
icon: <LinkOutlined />,
|
icon: <LinkOutlined />,
|
||||||
title: '修改自定义链接',
|
title: '自定义链接',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -505,9 +516,11 @@ Menu.DesignableBar = (props) => {
|
|||||||
|
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { schema, remove, refresh, insertAfter, appendChild } = useDesignable();
|
const { schema, remove, refresh, insertAfter, insertBefore, appendChild } =
|
||||||
|
useDesignable();
|
||||||
const formConfig = schemas[schema['x-component']];
|
const formConfig = schemas[schema['x-component']];
|
||||||
console.log({ formConfig, schema })
|
const isSubMenu = schema['x-component'] === 'Menu.SubMenu';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
<div
|
<div
|
||||||
@ -521,26 +534,62 @@ Menu.DesignableBar = (props) => {
|
|||||||
overlayStyle={{
|
overlayStyle={{
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
}}
|
}}
|
||||||
// visible={visible}
|
|
||||||
// onVisibleChange={(visible) => {
|
|
||||||
// setVisible(visible);
|
|
||||||
// }}
|
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
overlay={
|
overlay={
|
||||||
<AntdMenu>
|
<AntdMenu
|
||||||
|
onClick={async (info) => {
|
||||||
|
if (['update', 'move', 'delete'].includes(info.key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const methodLabels = {
|
||||||
|
insertBefore: '之前',
|
||||||
|
insertAfter: '之后',
|
||||||
|
appendChild: '里',
|
||||||
|
};
|
||||||
|
const keys = info.key.split('.');
|
||||||
|
const method = keys.shift();
|
||||||
|
const type = keys.join('.');
|
||||||
|
const config = schemas[type];
|
||||||
|
if (!config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const values = await FormDialog(
|
||||||
|
`在「${schema.title}」${methodLabels[method]}新建${config.title}`,
|
||||||
|
() => {
|
||||||
|
return (
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaField schema={config.schema} />
|
||||||
|
</FormLayout>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).open();
|
||||||
|
const methods = {
|
||||||
|
insertAfter,
|
||||||
|
insertBefore,
|
||||||
|
appendChild,
|
||||||
|
};
|
||||||
|
const defaults = cloneDeep(defaultSchemas[type]);
|
||||||
|
const data = methods[method](deepmerge(defaults, values));
|
||||||
|
await createSchema(data);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
|
key={'update'}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const initialValues = {};
|
const initialValues = {};
|
||||||
Object.keys(formConfig.schema.properties).forEach((name) => {
|
Object.keys(formConfig.schema.properties).forEach((name) => {
|
||||||
_.set(initialValues, name, get(schema, name));
|
_.set(initialValues, name, get(schema, name));
|
||||||
});
|
});
|
||||||
const values = await FormDialog(formConfig.title, () => {
|
const values = await FormDialog(
|
||||||
return (
|
`修改${formConfig.title}`,
|
||||||
<FormLayout layout={'vertical'}>
|
() => {
|
||||||
<SchemaField schema={formConfig.schema} />
|
return (
|
||||||
</FormLayout>
|
<FormLayout layout={'vertical'}>
|
||||||
);
|
<SchemaField schema={formConfig.schema} />
|
||||||
}).open({
|
</FormLayout>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).open({
|
||||||
initialValues,
|
initialValues,
|
||||||
});
|
});
|
||||||
if (values.title) {
|
if (values.title) {
|
||||||
@ -553,50 +602,203 @@ Menu.DesignableBar = (props) => {
|
|||||||
field.componentProps['icon'] = icon;
|
field.componentProps['icon'] = icon;
|
||||||
refresh();
|
refresh();
|
||||||
await updateSchema(schema);
|
await updateSchema(schema);
|
||||||
// const title = uid();
|
|
||||||
// field.componentProps['icon'] = 'DeleteOutlined';
|
|
||||||
|
|
||||||
// schema['x-component-props']['icon'] = 'DeleteOutlined';
|
|
||||||
// schema.title = title;
|
|
||||||
// refresh();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{formConfig.title}
|
<EditOutlined /> 修改{formConfig.title}
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
|
key={'move'}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const s = insertAfter({
|
let menuSchema: Schema;
|
||||||
...defaultSchemas['Menu.Link'],
|
let parent = schema.parent;
|
||||||
title: uid(),
|
while (parent) {
|
||||||
|
if (parent['x-component'] === 'Menu') {
|
||||||
|
menuSchema = parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({ menuSchema })
|
||||||
|
|
||||||
|
const toTreeData = (s: Schema) => {
|
||||||
|
const items = [];
|
||||||
|
Object.keys(s.properties || {}).forEach((name) => {
|
||||||
|
const current = s.properties[name];
|
||||||
|
if (
|
||||||
|
!(current['x-component'] as string).startsWith('Menu.')
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if (current.name === schema.name) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
items.push({
|
||||||
|
key: current['key'] || current.name,
|
||||||
|
label: current.title,
|
||||||
|
title: current.title,
|
||||||
|
value: getSchemaPath(current).join('.'),
|
||||||
|
children: toTreeData(current),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataSource = toTreeData(menuSchema);
|
||||||
|
|
||||||
|
const values = await FormDialog(
|
||||||
|
`将「${schema.title}」移动到`,
|
||||||
|
() => {
|
||||||
|
return (
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaField
|
||||||
|
schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: 'string',
|
||||||
|
title: '目标位置',
|
||||||
|
enum: dataSource,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'TreeSelect',
|
||||||
|
},
|
||||||
|
method: {
|
||||||
|
type: 'string',
|
||||||
|
default: 'insertAfter',
|
||||||
|
enum: [
|
||||||
|
{ label: '之后', value: 'insertAfter' },
|
||||||
|
{ label: '之前', value: 'insertBefore' },
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormLayout>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).open({
|
||||||
|
effects(form) {
|
||||||
|
onFieldChange('path', (field) => {
|
||||||
|
const target = findPropertyByPath(
|
||||||
|
schema.root,
|
||||||
|
// @ts-ignore
|
||||||
|
field.value,
|
||||||
|
);
|
||||||
|
console.log({ field });
|
||||||
|
field.query('method').take((f) => {
|
||||||
|
// @ts-ignore
|
||||||
|
// f.value = 'insertAfter';
|
||||||
|
// @ts-ignore
|
||||||
|
f.dataSource =
|
||||||
|
target['x-component'] === 'Menu.SubMenu'
|
||||||
|
? [
|
||||||
|
{ label: '之后', value: 'insertAfter' },
|
||||||
|
{ label: '之前', value: 'insertBefore' },
|
||||||
|
{ label: '组里', value: 'appendChild' },
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ label: '之后', value: 'insertAfter' },
|
||||||
|
{ label: '之前', value: 'insertBefore' },
|
||||||
|
];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
await createSchema(s);
|
const methods = {
|
||||||
|
insertAfter,
|
||||||
|
insertBefore,
|
||||||
|
appendChild,
|
||||||
|
};
|
||||||
|
const source = methods[values.method](
|
||||||
|
schema.toJSON(),
|
||||||
|
values.path,
|
||||||
|
);
|
||||||
|
remove();
|
||||||
|
await updateSchema(source);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
新建菜单项
|
<DragOutlined /> 移动到
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
<AntdMenu.Item
|
<AntdMenu.Divider />
|
||||||
onClick={async () => {
|
<AntdMenu.SubMenu
|
||||||
const s = insertAfter({
|
key={'insertBefore'}
|
||||||
...defaultSchemas['Menu.SubMenu'],
|
icon={<ArrowUpOutlined />}
|
||||||
title: uid(),
|
title={'当前菜单项之前'}
|
||||||
});
|
|
||||||
await createSchema(s);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
新建菜单分组
|
<AntdMenu.Item
|
||||||
</AntdMenu.Item>
|
key={'insertBefore.Menu.Link'}
|
||||||
<AntdMenu.Item
|
icon={<MenuOutlined />}
|
||||||
onClick={async () => {
|
>
|
||||||
const s = appendChild({
|
新建菜单项
|
||||||
...defaultSchemas['Menu.Link'],
|
</AntdMenu.Item>
|
||||||
title: uid(),
|
<AntdMenu.Item
|
||||||
});
|
key={'insertBefore.Menu.SubMenu'}
|
||||||
await createSchema(s);
|
icon={<GroupOutlined />}
|
||||||
}}
|
>
|
||||||
|
新建菜单分组
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'insertBefore.Menu.URL'}
|
||||||
|
icon={<LinkOutlined />}
|
||||||
|
>
|
||||||
|
添加自定义链接
|
||||||
|
</AntdMenu.Item>
|
||||||
|
</AntdMenu.SubMenu>
|
||||||
|
<AntdMenu.SubMenu
|
||||||
|
key={'insertAfter'}
|
||||||
|
icon={<ArrowDownOutlined />}
|
||||||
|
title={'当前菜单项之后'}
|
||||||
>
|
>
|
||||||
在菜单组里新增
|
<AntdMenu.Item
|
||||||
</AntdMenu.Item>
|
key={'insertAfter.Menu.Link'}
|
||||||
|
icon={<MenuOutlined />}
|
||||||
|
>
|
||||||
|
新建菜单项
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'insertAfter.Menu.SubMenu'}
|
||||||
|
icon={<GroupOutlined />}
|
||||||
|
>
|
||||||
|
新建菜单分组
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'insertAfter.Menu.URL'}
|
||||||
|
icon={<LinkOutlined />}
|
||||||
|
>
|
||||||
|
添加自定义链接
|
||||||
|
</AntdMenu.Item>
|
||||||
|
</AntdMenu.SubMenu>
|
||||||
|
{isSubMenu && (
|
||||||
|
<AntdMenu.SubMenu
|
||||||
|
key={'appendChild'}
|
||||||
|
icon={<ArrowRightOutlined />}
|
||||||
|
title={'当前菜单分组里'}
|
||||||
|
>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'appendChild.Menu.Link'}
|
||||||
|
icon={<MenuOutlined />}
|
||||||
|
>
|
||||||
|
新建菜单项
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'appendChild.Menu.SubMenu'}
|
||||||
|
icon={<GroupOutlined />}
|
||||||
|
>
|
||||||
|
新建菜单分组
|
||||||
|
</AntdMenu.Item>
|
||||||
|
<AntdMenu.Item
|
||||||
|
key={'appendChild.Menu.URL'}
|
||||||
|
icon={<LinkOutlined />}
|
||||||
|
>
|
||||||
|
添加自定义链接
|
||||||
|
</AntdMenu.Item>
|
||||||
|
</AntdMenu.SubMenu>
|
||||||
|
)}
|
||||||
|
<AntdMenu.Divider />
|
||||||
<AntdMenu.Item
|
<AntdMenu.Item
|
||||||
|
key={'delete'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '删除菜单',
|
title: '删除菜单',
|
||||||
@ -608,7 +810,7 @@ Menu.DesignableBar = (props) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
删除菜单
|
<DeleteOutlined /> 删除
|
||||||
</AntdMenu.Item>
|
</AntdMenu.Item>
|
||||||
</AntdMenu>
|
</AntdMenu>
|
||||||
}
|
}
|
||||||
|
27
packages/client/src/schemas/tree-select/index.tsx
Normal file
27
packages/client/src/schemas/tree-select/index.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { connect, mapReadPretty, mapProps } from '@formily/react'
|
||||||
|
import { TreeSelect as AntdTreeSelect } from 'antd'
|
||||||
|
import { Display } from '../display'
|
||||||
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
|
export const TreeSelect = connect(
|
||||||
|
AntdTreeSelect,
|
||||||
|
mapProps(
|
||||||
|
{
|
||||||
|
dataSource: 'treeData',
|
||||||
|
},
|
||||||
|
(props, field) => {
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
suffixIcon:
|
||||||
|
field?.['loading'] || field?.['validating'] ? (
|
||||||
|
<LoadingOutlined />
|
||||||
|
) : (
|
||||||
|
props.suffixIcon
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
mapReadPretty(Display.TreeSelect)
|
||||||
|
)
|
||||||
|
|
||||||
|
export default TreeSelect
|
@ -7,12 +7,12 @@ export const create = async (ctx: actions.Context, next: actions.Next) => {
|
|||||||
const values = cloneDeep(ctx.action.params.values);
|
const values = cloneDeep(ctx.action.params.values);
|
||||||
ctx.action.mergeParams(
|
ctx.action.mergeParams(
|
||||||
{
|
{
|
||||||
values: omit(values, [
|
values: cloneDeep(omit(values, [
|
||||||
'__insertAfter__',
|
'__insertAfter__',
|
||||||
'__insertBefore__',
|
'__insertBefore__',
|
||||||
'__prepend__',
|
'__prepend__',
|
||||||
'_isJSONSchemaObject',
|
'_isJSONSchemaObject',
|
||||||
]),
|
])),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
payload: 'replace',
|
payload: 'replace',
|
||||||
@ -22,24 +22,11 @@ export const create = async (ctx: actions.Context, next: actions.Next) => {
|
|||||||
const sticky = values['__prepend__'];
|
const sticky = values['__prepend__'];
|
||||||
const targetKey = values['__insertAfter__'] || values['__insertBefore__'];
|
const targetKey = values['__insertAfter__'] || values['__insertBefore__'];
|
||||||
if (sticky || targetKey) {
|
if (sticky || targetKey) {
|
||||||
console.log({
|
const body = ctx.body;
|
||||||
associatedKey: values.parentKey,
|
|
||||||
resourceKey: ctx.body.key,
|
|
||||||
values: sticky ? {
|
|
||||||
field: 'sort',
|
|
||||||
sticky: true,
|
|
||||||
} : {
|
|
||||||
field: 'sort',
|
|
||||||
insertAfter: !!values['__insertAfter__'],
|
|
||||||
target: {
|
|
||||||
key: targetKey,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
ctx.action.mergeParams(
|
ctx.action.mergeParams(
|
||||||
{
|
{
|
||||||
associatedKey: values.parentKey,
|
associatedKey: values.parentKey,
|
||||||
resourceKey: ctx.body.key,
|
resourceKey: body.key,
|
||||||
values: sticky ? {
|
values: sticky ? {
|
||||||
field: 'sort',
|
field: 'sort',
|
||||||
sticky: true,
|
sticky: true,
|
||||||
@ -56,8 +43,58 @@ export const create = async (ctx: actions.Context, next: actions.Next) => {
|
|||||||
payload: 'replace',
|
payload: 'replace',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
await next();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const update = async (ctx: actions.Context, next: actions.Next) => {
|
||||||
|
const values = cloneDeep(ctx.action.params.values);
|
||||||
|
ctx.action.mergeParams(
|
||||||
|
{
|
||||||
|
values: cloneDeep(omit(values, [
|
||||||
|
'__insertAfter__',
|
||||||
|
'__insertBefore__',
|
||||||
|
'__prepend__',
|
||||||
|
'_isJSONSchemaObject',
|
||||||
|
])),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
payload: 'replace',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await actions.common.update(ctx, async () => { });
|
||||||
|
const sticky = values['__prepend__'];
|
||||||
|
const targetKey = values['__insertAfter__'] || values['__insertBefore__'];
|
||||||
|
if (sticky || targetKey) {
|
||||||
|
const body = ctx.body;
|
||||||
|
ctx.action.mergeParams(
|
||||||
|
{
|
||||||
|
associatedKey: values.parentKey,
|
||||||
|
resourceKey: body.key,
|
||||||
|
values: sticky ? {
|
||||||
|
field: 'sort',
|
||||||
|
sticky: true,
|
||||||
|
target: {},
|
||||||
|
} : {
|
||||||
|
field: 'sort',
|
||||||
|
insertAfter: !!values['__insertAfter__'],
|
||||||
|
target: {
|
||||||
|
key: targetKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
payload: 'replace',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
console.log(ctx.action.params.values);
|
||||||
|
await middlewares.associated(ctx, async () => { });
|
||||||
|
await sort(ctx, async () => { });
|
||||||
|
console.log(ctx.body.toJSON());
|
||||||
}
|
}
|
||||||
await next();
|
await next();
|
||||||
};
|
};
|
||||||
|
@ -4,16 +4,10 @@ import { Model } from '@nocobase/database';
|
|||||||
export class UISchema extends Model {
|
export class UISchema extends Model {
|
||||||
static async create(value?: any, options?: any): Promise<any> {
|
static async create(value?: any, options?: any): Promise<any> {
|
||||||
// console.log({ value });
|
// console.log({ value });
|
||||||
const attributes = this.toAttributes(value);
|
const attributes = this.toAttributes(_.cloneDeep(value));
|
||||||
|
console.log({ attributes })
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const model: Model = await super.create(attributes, options);
|
const model: Model = await super.create(attributes, options);
|
||||||
if (value['__prepend__']) {
|
|
||||||
console.log('__prepend__', model.parentKey);
|
|
||||||
} else if (value['__insertAfter__']) {
|
|
||||||
console.log('__insertAfter__', model.parentKey);
|
|
||||||
} else if (value['__insertBefore__']) {
|
|
||||||
console.log('__insertBefore__', model.parentKey);
|
|
||||||
}
|
|
||||||
if (!attributes.children) {
|
if (!attributes.children) {
|
||||||
attributes.children = this.properties2children(attributes.properties);
|
attributes.children = this.properties2children(attributes.properties);
|
||||||
await model.updateAssociation('children', attributes.children, options);
|
await model.updateAssociation('children', attributes.children, options);
|
||||||
@ -22,14 +16,15 @@ export class UISchema extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(key?: any, value?: any, options?: any): Promise<any> {
|
async update(key?: any, value?: any, options?: any): Promise<any> {
|
||||||
|
const opts = this.get('options') || {};
|
||||||
if (typeof key === 'object') {
|
if (typeof key === 'object') {
|
||||||
const attributes = UISchema.toAttributes(key);
|
const attributes = UISchema.toAttributes(key, opts);
|
||||||
return super.update(attributes, value, options);
|
return super.update(attributes, value, options);
|
||||||
}
|
}
|
||||||
return super.update(key, value, options);
|
return super.update(key, value, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static toAttributes(value = {}): any {
|
static toAttributes(value = {}, opts = {}): any {
|
||||||
const data = _.cloneDeep(value);
|
const data = _.cloneDeep(value);
|
||||||
const keys = [
|
const keys = [
|
||||||
'properties',
|
'properties',
|
||||||
@ -38,7 +33,7 @@ export class UISchema extends Model {
|
|||||||
];
|
];
|
||||||
const attrs = _.pick(data, keys);
|
const attrs = _.pick(data, keys);
|
||||||
const options = _.omit(data, keys);
|
const options = _.omit(data, keys);
|
||||||
return { ...attrs, options };
|
return { ...attrs, options: {...options, ...opts} };
|
||||||
}
|
}
|
||||||
|
|
||||||
static properties2children(properties = []) {
|
static properties2children(properties = []) {
|
||||||
|
@ -2,7 +2,7 @@ import path from 'path';
|
|||||||
import { Application } from '@nocobase/server';
|
import { Application } from '@nocobase/server';
|
||||||
import { registerModels, Table } from '@nocobase/database';
|
import { registerModels, Table } from '@nocobase/database';
|
||||||
import * as models from './models';
|
import * as models from './models';
|
||||||
import { create, getTree } from './actions';
|
import { create, update, getTree } from './actions';
|
||||||
|
|
||||||
export default async function (this: Application, options = {}) {
|
export default async function (this: Application, options = {}) {
|
||||||
const database = this.database;
|
const database = this.database;
|
||||||
@ -13,5 +13,6 @@ export default async function (this: Application, options = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.resourcer.registerActionHandler('ui_schemas:create', create);
|
this.resourcer.registerActionHandler('ui_schemas:create', create);
|
||||||
|
this.resourcer.registerActionHandler('ui_schemas:update', update);
|
||||||
this.resourcer.registerActionHandler('ui_schemas:getTree', getTree);
|
this.resourcer.registerActionHandler('ui_schemas:getTree', getTree);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user