action bar
This commit is contained in:
parent
7dd9fbf213
commit
c3d2c3cd28
40
packages/client/src/components/SwitchMenuItem.tsx
Normal file
40
packages/client/src/components/SwitchMenuItem.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Menu, Switch } from 'antd';
|
||||||
|
|
||||||
|
export interface SwitchMenuItemProps {
|
||||||
|
onChange?: any;
|
||||||
|
title?: any;
|
||||||
|
checked?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SwitchMenuItem(props: SwitchMenuItemProps) {
|
||||||
|
const { onChange } = props;
|
||||||
|
const [checked, setChecked] = useState(props.checked);
|
||||||
|
useEffect(() => {
|
||||||
|
setChecked(props.checked);
|
||||||
|
}, [props.checked]);
|
||||||
|
return (
|
||||||
|
<Menu.Item
|
||||||
|
style={{ minWidth: 150 }}
|
||||||
|
onClick={async () => {
|
||||||
|
setChecked((checked) => {
|
||||||
|
onChange(!checked);
|
||||||
|
return !checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{props.title}</span>
|
||||||
|
<Switch checked={checked} size={'small'} />
|
||||||
|
</div>
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SwitchMenuItem;
|
@ -69,6 +69,7 @@ import {
|
|||||||
useCollectionsContext,
|
useCollectionsContext,
|
||||||
useDisplayedMapContext,
|
useDisplayedMapContext,
|
||||||
} from '../../constate';
|
} from '../../constate';
|
||||||
|
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
||||||
|
|
||||||
const generateGridBlock = (schema: ISchema) => {
|
const generateGridBlock = (schema: ISchema) => {
|
||||||
const name = schema.name || uid();
|
const name = schema.name || uid();
|
||||||
@ -149,6 +150,12 @@ function generateCardItemSchema(component) {
|
|||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
title: '筛选',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'filter',
|
||||||
|
},
|
||||||
|
'x-align': 'left',
|
||||||
'x-component': 'Table.Filter',
|
'x-component': 'Table.Filter',
|
||||||
'x-designable-bar': 'Table.Filter.DesignableBar',
|
'x-designable-bar': 'Table.Filter.DesignableBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
@ -159,6 +166,11 @@ function generateCardItemSchema(component) {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '新增',
|
title: '新增',
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'create',
|
||||||
|
},
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
@ -186,6 +198,11 @@ function generateCardItemSchema(component) {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'action1',
|
name: 'action1',
|
||||||
title: '删除',
|
title: '删除',
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'destroy',
|
||||||
|
},
|
||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-designable-bar': 'Table.Action.DesignableBar',
|
'x-designable-bar': 'Table.Action.DesignableBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
@ -201,6 +218,7 @@ function generateCardItemSchema(component) {
|
|||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
className: 'nb-table-operation',
|
className: 'nb-table-operation',
|
||||||
},
|
},
|
||||||
|
'x-designable-bar': 'Table.OperationDesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -578,32 +596,6 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
function SwitchField(props) {
|
|
||||||
const { field, onChange } = props;
|
|
||||||
const [checked, setChecked] = useState(props.checked);
|
|
||||||
useEffect(() => {
|
|
||||||
setChecked(props.checked);
|
|
||||||
}, [props.checked]);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
setChecked((checked) => {
|
|
||||||
onChange(!checked);
|
|
||||||
return !checked;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{field.uiSchema.title}</span>
|
|
||||||
<Switch checked={checked} size={'small'} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddNew.FormItem = observer((props: any) => {
|
AddNew.FormItem = observer((props: any) => {
|
||||||
const { ghost, defaultAction } = props;
|
const { ghost, defaultAction } = props;
|
||||||
const { schema, insertBefore, insertAfter, appendChild, deepRemove } =
|
const { schema, insertBefore, insertAfter, appendChild, deepRemove } =
|
||||||
@ -624,57 +616,56 @@ AddNew.FormItem = observer((props: any) => {
|
|||||||
<Menu>
|
<Menu>
|
||||||
<Menu.ItemGroup className={'display-fields'} title={`字段展示`}>
|
<Menu.ItemGroup className={'display-fields'} title={`字段展示`}>
|
||||||
{fields?.map((field) => (
|
{fields?.map((field) => (
|
||||||
<Menu.Item key={field.key}>
|
<SwitchMenuItem
|
||||||
<SwitchField
|
key={field.key}
|
||||||
field={field}
|
title={field?.uiSchema?.title}
|
||||||
checked={displayed.has(field.name)}
|
checked={displayed.has(field.name)}
|
||||||
onChange={async (checked) => {
|
onChange={async (checked) => {
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
const s: any = displayed.get(field.name);
|
const s: any = displayed.get(field.name);
|
||||||
const p = getSchemaPath(s);
|
const p = getSchemaPath(s);
|
||||||
const removed = deepRemove(p);
|
const removed = deepRemove(p);
|
||||||
if (!removed) {
|
if (!removed) {
|
||||||
console.log('getSchemaPath', p, removed);
|
console.log('getSchemaPath', p, removed);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const last = removed.pop();
|
|
||||||
displayed.remove(field.name);
|
|
||||||
if (isGridRowOrCol(last)) {
|
|
||||||
await removeSchema(last);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let data: ISchema = {
|
const last = removed.pop();
|
||||||
key: uid(),
|
displayed.remove(field.name);
|
||||||
type: 'void',
|
if (isGridRowOrCol(last)) {
|
||||||
'x-decorator': 'Form.Field.Item',
|
await removeSchema(last);
|
||||||
'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) {
|
return;
|
||||||
let s;
|
}
|
||||||
if (isGrid(schema)) {
|
let data: ISchema = {
|
||||||
s = appendChild(data, [...path]);
|
key: uid(),
|
||||||
} else if (defaultAction === 'insertAfter') {
|
type: 'void',
|
||||||
s = insertAfter(data, [...path]);
|
'x-decorator': 'Form.Field.Item',
|
||||||
} else {
|
'x-designable-bar': 'Form.Field.DesignableBar',
|
||||||
s = insertBefore(data, [...path]);
|
'x-component': 'Form.Field',
|
||||||
}
|
'x-component-props': {
|
||||||
await createSchema(s);
|
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);
|
||||||
/>
|
}
|
||||||
</Menu.Item>
|
}}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
@ -968,4 +959,16 @@ AddNew.PaneItem = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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;
|
export default AddNew;
|
||||||
|
@ -56,8 +56,4 @@ export const linkTo: ISchema = {
|
|||||||
'x-component': 'Checkbox',
|
'x-component': 'Checkbox',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
operations: [
|
|
||||||
{ label: '等于', value: 'eq' },
|
|
||||||
{ label: '不等于', value: 'ne' },
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
|
FormProvider,
|
||||||
|
ISchema,
|
||||||
observer,
|
observer,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
Schema,
|
Schema,
|
||||||
useField,
|
useField,
|
||||||
useForm,
|
useForm,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Pagination, Table as AntdTable } from 'antd';
|
import { Pagination, Popover, Table as AntdTable } from 'antd';
|
||||||
import { findIndex, forIn, range, set } from 'lodash';
|
import { findIndex, forIn, range, set } from 'lodash';
|
||||||
import React, { Fragment, useEffect, useState } from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
@ -22,8 +24,12 @@ import { CSS } from '@dnd-kit/utilities';
|
|||||||
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
|
import { Select, Dropdown, Menu, Switch, Button, Space } from 'antd';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import {
|
||||||
import { options } from '../database-field/interfaces';
|
getSchemaPath,
|
||||||
|
SchemaField,
|
||||||
|
SchemaRenderer,
|
||||||
|
} from '../../components/schema-renderer';
|
||||||
|
import { interfaces, options } from '../database-field/interfaces';
|
||||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||||
import AddNew from '../add-new';
|
import AddNew from '../add-new';
|
||||||
import { isGridRowOrCol } from '../grid';
|
import { isGridRowOrCol } from '../grid';
|
||||||
@ -35,6 +41,9 @@ import {
|
|||||||
useDisplayedMapContext,
|
useDisplayedMapContext,
|
||||||
} from '../../constate';
|
} from '../../constate';
|
||||||
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
import { useResource as useGeneralResource } from '../../hooks/useResource';
|
||||||
|
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
|
||||||
const SyntheticListenerMapContext = createContext(null);
|
const SyntheticListenerMapContext = createContext(null);
|
||||||
|
|
||||||
@ -247,6 +256,7 @@ const useTableColumns = () => {
|
|||||||
schema,
|
schema,
|
||||||
props: { rowKey },
|
props: { rowKey },
|
||||||
} = useTable();
|
} = useTable();
|
||||||
|
const { designable } = useDesignable();
|
||||||
|
|
||||||
const { getField } = useCollectionContext();
|
const { getField } = useCollectionContext();
|
||||||
|
|
||||||
@ -284,40 +294,18 @@ const useTableColumns = () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.concat([
|
.concat(
|
||||||
{
|
designable
|
||||||
title: <AddColumn />,
|
? [
|
||||||
dataIndex: 'addnew',
|
{
|
||||||
},
|
title: <AddColumn />,
|
||||||
]);
|
dataIndex: 'addnew',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function SwitchField(props) {
|
|
||||||
const { field, onChange } = props;
|
|
||||||
const [checked, setChecked] = useState(props.checked);
|
|
||||||
useEffect(() => {
|
|
||||||
setChecked(props.checked);
|
|
||||||
}, [props.checked]);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
setChecked((checked) => {
|
|
||||||
onChange(!checked);
|
|
||||||
return !checked;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>{field.uiSchema.title}</span>
|
|
||||||
<Switch checked={checked} size={'small'} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AddColumn() {
|
function AddColumn() {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { appendChild, remove } = useDesignable();
|
const { appendChild, remove } = useDesignable();
|
||||||
@ -333,31 +321,29 @@ function AddColumn() {
|
|||||||
<Menu>
|
<Menu>
|
||||||
<Menu.ItemGroup className={'display-fields'} title={'字段展示'}>
|
<Menu.ItemGroup className={'display-fields'} title={'字段展示'}>
|
||||||
{fields.map((field) => (
|
{fields.map((field) => (
|
||||||
<Menu.Item style={{ minWidth: 150 }}>
|
<SwitchMenuItem
|
||||||
<SwitchField
|
title={field?.uiSchema?.title}
|
||||||
checked={displayed.has(field.name)}
|
checked={displayed.has(field.name)}
|
||||||
field={field}
|
onChange={async (checked) => {
|
||||||
onChange={async (checked) => {
|
if (checked) {
|
||||||
if (checked) {
|
const data = appendChild({
|
||||||
const data = appendChild({
|
type: 'void',
|
||||||
type: 'void',
|
'x-component': 'Table.Column',
|
||||||
'x-component': 'Table.Column',
|
'x-component-props': {
|
||||||
'x-component-props': {
|
fieldName: field.name,
|
||||||
fieldName: field.name,
|
},
|
||||||
},
|
'x-designable-bar': 'Table.Column.DesignableBar',
|
||||||
'x-designable-bar': 'Table.Column.DesignableBar',
|
});
|
||||||
});
|
await createSchema(data);
|
||||||
await createSchema(data);
|
} else {
|
||||||
} else {
|
const s: any = displayed.get(field.name);
|
||||||
const s: any = displayed.get(field.name);
|
const p = getSchemaPath(s);
|
||||||
const p = getSchemaPath(s);
|
const removed = remove(p);
|
||||||
const removed = remove(p);
|
await removeSchema(removed);
|
||||||
await removeSchema(removed);
|
displayed.remove(field.name);
|
||||||
displayed.remove(field.name);
|
}
|
||||||
}
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</Menu.Item>
|
|
||||||
))}
|
))}
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
@ -382,7 +368,9 @@ function AddColumn() {
|
|||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button size={'small'} type={'dashed'} icon={<PlusOutlined />}></Button>
|
<Button type={'dashed'} icon={<PlusOutlined />}>
|
||||||
|
配置字段
|
||||||
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -582,7 +570,7 @@ const useTotal = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Table.Pagination = observer(() => {
|
Table.Pagination = observer(() => {
|
||||||
const { field, service, pagination, setPagination, props } = useTable();
|
const { service, pagination, setPagination, props } = useTable();
|
||||||
if (!pagination || Object.keys(pagination).length === 0) {
|
if (!pagination || Object.keys(pagination).length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -590,7 +578,7 @@ Table.Pagination = observer(() => {
|
|||||||
const total = useTotal();
|
const total = useTotal();
|
||||||
const { page = 1 } = pagination;
|
const { page = 1 } = pagination;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={{ marginTop: 16 }}>
|
||||||
<Pagination
|
<Pagination
|
||||||
{...pagination}
|
{...pagination}
|
||||||
showSizeChanger
|
showSizeChanger
|
||||||
@ -617,8 +605,90 @@ Table.Pagination = observer(() => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function generateActionSchema(type) {
|
||||||
|
const actions: { [key: string]: ISchema } = {
|
||||||
|
filter: {
|
||||||
|
key: uid(),
|
||||||
|
name: uid(),
|
||||||
|
type: 'void',
|
||||||
|
title: '筛选',
|
||||||
|
'x-align': 'left',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'filter',
|
||||||
|
},
|
||||||
|
'x-component': 'Table.Filter',
|
||||||
|
'x-designable-bar': 'Table.Filter.DesignableBar',
|
||||||
|
'x-component-props': {
|
||||||
|
fieldNames: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
export: {},
|
||||||
|
create: {
|
||||||
|
key: uid(),
|
||||||
|
type: 'void',
|
||||||
|
name: uid(),
|
||||||
|
title: '新增',
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'AddNew.Displayed',
|
||||||
|
'x-decorator-props': {
|
||||||
|
displayName: 'create',
|
||||||
|
},
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
'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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
destroy: {
|
||||||
|
key: uid(),
|
||||||
|
type: 'void',
|
||||||
|
name: uid(),
|
||||||
|
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 }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: {},
|
||||||
|
};
|
||||||
|
return actions[type];
|
||||||
|
}
|
||||||
|
|
||||||
function AddActionButton() {
|
function AddActionButton() {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const displayed = useDisplayedMapContext();
|
||||||
|
const { appendChild, remove } = useDesignable();
|
||||||
|
const { schema, designable } = useDesignable();
|
||||||
|
if (!designable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
@ -626,25 +696,31 @@ function AddActionButton() {
|
|||||||
onVisibleChange={setVisible}
|
onVisibleChange={setVisible}
|
||||||
overlay={
|
overlay={
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.ItemGroup title={'要展示的操作'}>
|
<Menu.ItemGroup title={'操作展示'}>
|
||||||
{[
|
{[
|
||||||
{ title: '筛选', key: 'filter' },
|
{ title: '筛选', name: 'filter' },
|
||||||
{ title: '导出', key: 'export' },
|
// { title: '导出', name: 'export' },
|
||||||
{ title: '新增', key: 'create' },
|
{ title: '新增', name: 'create' },
|
||||||
{ title: '删除', key: 'destroy' },
|
{ title: '删除', name: 'destroy' },
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<Menu.Item style={{ minWidth: 150 }}>
|
<SwitchMenuItem
|
||||||
<div
|
key={item.name}
|
||||||
style={{
|
checked={displayed.has(item.name)}
|
||||||
display: 'flex',
|
title={item.title}
|
||||||
alignItems: 'center',
|
onChange={async (checked) => {
|
||||||
justifyContent: 'space-between',
|
if (!checked) {
|
||||||
}}
|
const s = displayed.get(item.name) as Schema;
|
||||||
>
|
const path = getSchemaPath(s);
|
||||||
<span>{item.title}</span>
|
displayed.remove(item.name);
|
||||||
<Switch size={'small'} defaultChecked />
|
const removed = remove(path);
|
||||||
</div>
|
await removeSchema(removed);
|
||||||
</Menu.Item>
|
} else {
|
||||||
|
const s = generateActionSchema(item.name);
|
||||||
|
const data = appendChild(s);
|
||||||
|
await createSchema(data);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
@ -656,28 +732,233 @@ function AddActionButton() {
|
|||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button type={'dashed'} icon={<PlusOutlined />}>
|
<Button style={{ marginLeft: 8 }} type={'dashed'} icon={<PlusOutlined />}>
|
||||||
配置操作
|
配置操作
|
||||||
</Button>
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Actions(props: any) {
|
||||||
|
const { align = 'left' } = props;
|
||||||
|
const { schema, designable } = useDesignable();
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
{schema.mapProperties((s) => {
|
||||||
|
const currentAlign = s['x-align'] || 'left';
|
||||||
|
if (currentAlign !== align) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <RecursionField name={s.name} schema={s} />;
|
||||||
|
})}
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Table.ActionBar = observer((props: any) => {
|
Table.ActionBar = observer((props: any) => {
|
||||||
const { align = 'top' } = props;
|
const { align = 'top' } = props;
|
||||||
const { schema, designable } = useDesignable();
|
const { schema, designable } = useDesignable();
|
||||||
const designableBar = schema['x-designable-bar'];
|
const designableBar = schema['x-designable-bar'];
|
||||||
console.log('Table.ActionBar', schema);
|
console.log('Table.ActionBar', { schema });
|
||||||
return (
|
return (
|
||||||
<div className={cls('nb-action-bar', `align-${align}`)}>
|
<DisplayedMapProvider>
|
||||||
<Space>
|
<div className={cls('nb-action-bar', `align-${align}`)}>
|
||||||
{props.children}
|
<div>
|
||||||
{designable && designableBar && <AddActionButton />}
|
<Actions align={'left'} />
|
||||||
</Space>
|
</div>
|
||||||
</div>
|
<div style={{ marginLeft: 'auto' }}>
|
||||||
|
<Actions align={'right'} />
|
||||||
|
</div>
|
||||||
|
<AddActionButton />
|
||||||
|
</div>
|
||||||
|
</DisplayedMapProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Table.Filter = observer((props: any) => {
|
||||||
|
const { fieldNames = [] } = props;
|
||||||
|
const { schema, DesignableBar } = useDesignable();
|
||||||
|
const form = useMemo(() => createForm(), []);
|
||||||
|
const { fields = [] } = useCollectionContext();
|
||||||
|
const fields2properties = (fields: any[]) => {
|
||||||
|
const properties = {};
|
||||||
|
fields.forEach((field, index) => {
|
||||||
|
if (fieldNames?.length && !fieldNames.includes(field.name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fieldOption = interfaces.get(field.interface);
|
||||||
|
if (!fieldOption.operations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
properties[`column${index}`] = {
|
||||||
|
type: 'void',
|
||||||
|
title: field?.uiSchema?.title,
|
||||||
|
'x-component': 'Filter.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
operations: fieldOption.operations,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
[field.name]: {
|
||||||
|
...field.uiSchema,
|
||||||
|
title: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return properties;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
trigger={['click']}
|
||||||
|
placement={'bottomLeft'}
|
||||||
|
content={
|
||||||
|
<div>
|
||||||
|
<FormProvider form={form}>
|
||||||
|
<SchemaField
|
||||||
|
schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
filter: {
|
||||||
|
type: 'object',
|
||||||
|
'x-component': 'Filter',
|
||||||
|
properties: fields2properties(fields),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormProvider>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button>
|
||||||
|
{schema.title}
|
||||||
|
<DesignableBar />
|
||||||
|
</Button>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.Filter.DesignableBar = () => {
|
||||||
|
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const displayed = useDisplayedMapContext();
|
||||||
|
const { fields } = useCollectionContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.ItemGroup title={'筛选字段'}>
|
||||||
|
{fields
|
||||||
|
.filter((field) => {
|
||||||
|
const option = interfaces.get(field.interface);
|
||||||
|
return option.operations?.length;
|
||||||
|
})
|
||||||
|
.map((field) => (
|
||||||
|
<SwitchMenuItem
|
||||||
|
title={field?.uiSchema?.title}
|
||||||
|
checked={true}
|
||||||
|
onChange={async (checked) => {}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.Item
|
||||||
|
onClick={(e) => {
|
||||||
|
schema.title = uid();
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
修改名称和图标
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const displayName =
|
||||||
|
schema?.['x-decorator-props']?.['displayName'];
|
||||||
|
const data = remove();
|
||||||
|
await removeSchema(data);
|
||||||
|
if (displayName) {
|
||||||
|
displayed.remove(displayName);
|
||||||
|
}
|
||||||
|
setVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Table.OperationDesignableBar = () => {
|
||||||
|
const { schema, remove, refresh, insertAfter } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const isPopup = Object.keys(schema.properties || {}).length > 0;
|
||||||
|
const inActionBar = schema.parent['x-component'] === 'Table.ActionBar';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.ItemGroup title={'操作展示'}>
|
||||||
|
{[
|
||||||
|
{ title: '查看', name: 'view' },
|
||||||
|
{ title: '编辑', name: 'update' },
|
||||||
|
{ title: '删除', name: 'destroy' },
|
||||||
|
].map((item) => (
|
||||||
|
<SwitchMenuItem
|
||||||
|
key={item.name}
|
||||||
|
title={item.title}
|
||||||
|
onChange={async (checked) => {}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.SubMenu title={'自定义'}>
|
||||||
|
<Menu.Item style={{ minWidth: 120 }}>函数操作</Menu.Item>
|
||||||
|
<Menu.Item>弹窗表单</Menu.Item>
|
||||||
|
<Menu.Item>复杂弹窗</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Table.Action = () => null;
|
Table.Action = () => null;
|
||||||
|
|
||||||
Table.Action.DesignableBar = () => {
|
Table.Action.DesignableBar = () => {
|
||||||
@ -685,7 +966,7 @@ Table.Action.DesignableBar = () => {
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const isPopup = Object.keys(schema.properties || {}).length > 0;
|
const isPopup = Object.keys(schema.properties || {}).length > 0;
|
||||||
const inActionBar = schema.parent['x-component'] === 'Table.ActionBar';
|
const inActionBar = schema.parent['x-component'] === 'Table.ActionBar';
|
||||||
|
const displayed = useDisplayedMapContext();
|
||||||
return (
|
return (
|
||||||
<div className={cls('designable-bar', { active: visible })}>
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
<span
|
<span
|
||||||
@ -725,17 +1006,27 @@ Table.Action.DesignableBar = () => {
|
|||||||
内打开
|
内打开
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)}
|
)}
|
||||||
{inActionBar ? (
|
{!inActionBar && (
|
||||||
<Menu.Item>放置在右侧</Menu.Item>
|
|
||||||
) : (
|
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
点击表格行时触发
|
点击表格行时触发
|
||||||
<Switch size={'small'} defaultChecked />
|
<Switch size={'small'} defaultChecked />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item>删除</Menu.Item>
|
<Menu.Item
|
||||||
|
onClick={async () => {
|
||||||
|
const displayName =
|
||||||
|
schema?.['x-decorator-props']?.['displayName'];
|
||||||
|
const data = remove();
|
||||||
|
await removeSchema(data);
|
||||||
|
if (displayName) {
|
||||||
|
displayed.remove(displayName);
|
||||||
|
}
|
||||||
|
setVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
&.align-bottom {
|
&.align-bottom {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
th.nb-table-operation,
|
th.nb-table-operation,
|
||||||
|
Loading…
Reference in New Issue
Block a user