feat: action bar for the descriptions block
This commit is contained in:
		
							parent
							
								
									41cbb26b2e
								
							
						
					
					
						commit
						8f746ae319
					
				@ -1,3 +1,3 @@
 | 
				
			|||||||
import { createContext } from "react";
 | 
					import { createContext } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const VisibleContext = createContext<any>(null);
 | 
					export const VisibleContext = createContext<any>([]);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										256
									
								
								packages/client/src/schemas/action/ActionBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								packages/client/src/schemas/action/ActionBar.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,256 @@
 | 
				
			|||||||
 | 
					import { DndContext, DragOverlay } from '@dnd-kit/core';
 | 
				
			||||||
 | 
					import { ISchema, observer, RecursionField, Schema } from '@formily/react';
 | 
				
			||||||
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { createSchema, removeSchema, updateSchema } from '..';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  findPropertyByPath,
 | 
				
			||||||
 | 
					  getSchemaPath,
 | 
				
			||||||
 | 
					  useDesignable,
 | 
				
			||||||
 | 
					} from '../../components/schema-renderer';
 | 
				
			||||||
 | 
					import { DisplayedMapProvider, useDisplayedMapContext } from '../../constate';
 | 
				
			||||||
 | 
					import cls from 'classnames';
 | 
				
			||||||
 | 
					import { Button, Dropdown, Menu, Space } from 'antd';
 | 
				
			||||||
 | 
					import SwitchMenuItem from '../../components/SwitchMenuItem';
 | 
				
			||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
 | 
					import { PlusOutlined } from '@ant-design/icons';
 | 
				
			||||||
 | 
					import { Droppable, SortableItem } from '../../components/Sortable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ActionBar = observer((props: any) => {
 | 
				
			||||||
 | 
					  const { align = 'top' } = props;
 | 
				
			||||||
 | 
					  // const { schema, designable } = useDesignable();
 | 
				
			||||||
 | 
					  const { root, schema, insertAfter, remove, appendChild } = useDesignable();
 | 
				
			||||||
 | 
					  const moveToAfter = (path1, path2, extra = {}) => {
 | 
				
			||||||
 | 
					    if (!path1 || !path2) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (path1.join('.') === path2.join('.')) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const data = findPropertyByPath(root, path1);
 | 
				
			||||||
 | 
					    if (!data) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    remove(path1);
 | 
				
			||||||
 | 
					    return insertAfter(
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        ...data.toJSON(),
 | 
				
			||||||
 | 
					        ...extra,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      path2,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [dragOverlayContent, setDragOverlayContent] = useState('');
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <DndContext
 | 
				
			||||||
 | 
					      onDragStart={(event) => {
 | 
				
			||||||
 | 
					        setDragOverlayContent(event.active.data?.current?.title || '');
 | 
				
			||||||
 | 
					        // const previewRef = event.active.data?.current?.previewRef;
 | 
				
			||||||
 | 
					        // if (previewRef) {
 | 
				
			||||||
 | 
					        //   setDragOverlayContent(previewRef?.current?.innerHTML);
 | 
				
			||||||
 | 
					        // } else {
 | 
				
			||||||
 | 
					        //   setDragOverlayContent('');
 | 
				
			||||||
 | 
					        // }
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      onDragEnd={async (event) => {
 | 
				
			||||||
 | 
					        const path1 = event.active?.data?.current?.path;
 | 
				
			||||||
 | 
					        const path2 = event.over?.data?.current?.path;
 | 
				
			||||||
 | 
					        const align = event.over?.data?.current?.align;
 | 
				
			||||||
 | 
					        const draggable = event.over?.data?.current?.draggable;
 | 
				
			||||||
 | 
					        if (!path1 || !path2) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (path1.join('.') === path2.join('.')) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!draggable) {
 | 
				
			||||||
 | 
					          console.log('alignalignalignalign', align);
 | 
				
			||||||
 | 
					          const p = findPropertyByPath(root, path1);
 | 
				
			||||||
 | 
					          if (!p) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          remove(path1);
 | 
				
			||||||
 | 
					          const data = appendChild(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              ...p.toJSON(),
 | 
				
			||||||
 | 
					              'x-align': align,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            path2,
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          await updateSchema(data);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          const data = moveToAfter(path1, path2, {
 | 
				
			||||||
 | 
					            'x-align': align,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await updateSchema(data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <DragOverlay style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}>
 | 
				
			||||||
 | 
					        {dragOverlayContent}
 | 
				
			||||||
 | 
					        {/* <div style={{ transform: 'translateX(-100%)' }} dangerouslySetInnerHTML={{__html: dragOverlayContent}}></div> */}
 | 
				
			||||||
 | 
					      </DragOverlay>
 | 
				
			||||||
 | 
					      <DisplayedMapProvider>
 | 
				
			||||||
 | 
					        <div className={cls('nb-action-bar', `align-${align}`)}>
 | 
				
			||||||
 | 
					          <div style={{ width: '50%' }}>
 | 
				
			||||||
 | 
					            <Actions align={'left'} />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div style={{ marginLeft: 'auto', width: '50%', textAlign: 'right' }}>
 | 
				
			||||||
 | 
					            <Actions align={'right'} />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <AddActionButton />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </DisplayedMapProvider>
 | 
				
			||||||
 | 
					    </DndContext>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function generateActionSchema(type) {
 | 
				
			||||||
 | 
					  const actions: { [key: string]: ISchema } = {
 | 
				
			||||||
 | 
					    update: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      title: '编辑',
 | 
				
			||||||
 | 
					      'x-align': 'right',
 | 
				
			||||||
 | 
					      'x-decorator': 'AddNew.Displayed',
 | 
				
			||||||
 | 
					      'x-decorator-props': {
 | 
				
			||||||
 | 
					        displayName: 'update',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'x-component': 'Action',
 | 
				
			||||||
 | 
					      'x-component-props': {
 | 
				
			||||||
 | 
					        type: 'primary',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'x-action-type': 'update',
 | 
				
			||||||
 | 
					      'x-designable-bar': 'Action.DesignableBar',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        modal: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          title: '编辑数据',
 | 
				
			||||||
 | 
					          'x-decorator': 'Form',
 | 
				
			||||||
 | 
					          'x-decorator-props': {
 | 
				
			||||||
 | 
					            useResource: '{{ Table.useResource }}',
 | 
				
			||||||
 | 
					            useValues: '{{ Table.useTableRowRecord }}',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          'x-component': 'Action.Modal',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            useOkAction: '{{ Table.useTableUpdateAction }}',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            [uid()]: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              'x-component': 'Grid',
 | 
				
			||||||
 | 
					              'x-component-props': {
 | 
				
			||||||
 | 
					                addNewComponent: 'AddNew.FormItem',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    destroy: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      title: '删除',
 | 
				
			||||||
 | 
					      'x-align': 'right',
 | 
				
			||||||
 | 
					      'x-decorator': 'AddNew.Displayed',
 | 
				
			||||||
 | 
					      'x-decorator-props': {
 | 
				
			||||||
 | 
					        displayName: 'destroy',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'x-action-type': 'destroy',
 | 
				
			||||||
 | 
					      'x-component': 'Action',
 | 
				
			||||||
 | 
					      'x-designable-bar': 'Action.DesignableBar',
 | 
				
			||||||
 | 
					      'x-component-props': {
 | 
				
			||||||
 | 
					        useAction: '{{ Table.useTableDestroyAction }}',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return actions[type];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function AddActionButton() {
 | 
				
			||||||
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
 | 
					  const displayed = useDisplayedMapContext();
 | 
				
			||||||
 | 
					  const { appendChild, remove } = useDesignable();
 | 
				
			||||||
 | 
					  const { schema, designable } = useDesignable();
 | 
				
			||||||
 | 
					  if (!designable) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Dropdown
 | 
				
			||||||
 | 
					      trigger={['click']}
 | 
				
			||||||
 | 
					      visible={visible}
 | 
				
			||||||
 | 
					      onVisibleChange={setVisible}
 | 
				
			||||||
 | 
					      overlay={
 | 
				
			||||||
 | 
					        <Menu>
 | 
				
			||||||
 | 
					          <Menu.ItemGroup title={'操作展示'}>
 | 
				
			||||||
 | 
					            {[
 | 
				
			||||||
 | 
					              { title: '编辑', name: 'update' },
 | 
				
			||||||
 | 
					              { title: '删除', name: 'destroy' },
 | 
				
			||||||
 | 
					            ].map((item) => (
 | 
				
			||||||
 | 
					              <SwitchMenuItem
 | 
				
			||||||
 | 
					                key={item.name}
 | 
				
			||||||
 | 
					                checked={displayed.has(item.name)}
 | 
				
			||||||
 | 
					                title={item.title}
 | 
				
			||||||
 | 
					                onChange={async (checked) => {
 | 
				
			||||||
 | 
					                  if (!checked) {
 | 
				
			||||||
 | 
					                    const s = displayed.get(item.name) as Schema;
 | 
				
			||||||
 | 
					                    const path = getSchemaPath(s);
 | 
				
			||||||
 | 
					                    displayed.remove(item.name);
 | 
				
			||||||
 | 
					                    const removed = remove(path);
 | 
				
			||||||
 | 
					                    await removeSchema(removed);
 | 
				
			||||||
 | 
					                  } else {
 | 
				
			||||||
 | 
					                    const s = generateActionSchema(item.name);
 | 
				
			||||||
 | 
					                    const data = appendChild(s);
 | 
				
			||||||
 | 
					                    await createSchema(data);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					          </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>
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <Button style={{ marginLeft: 8 }} type={'dashed'} icon={<PlusOutlined />}>
 | 
				
			||||||
 | 
					        配置操作
 | 
				
			||||||
 | 
					      </Button>
 | 
				
			||||||
 | 
					    </Dropdown>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Actions(props: any) {
 | 
				
			||||||
 | 
					  const { align = 'left' } = props;
 | 
				
			||||||
 | 
					  const { schema, designable } = useDesignable();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Droppable
 | 
				
			||||||
 | 
					      id={`${schema.name}-${align}`}
 | 
				
			||||||
 | 
					      className={`action-bar-align-${align}`}
 | 
				
			||||||
 | 
					      data={{ align, path: getSchemaPath(schema) }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <Space>
 | 
				
			||||||
 | 
					        {schema.mapProperties((s) => {
 | 
				
			||||||
 | 
					          const currentAlign = s['x-align'] || 'left';
 | 
				
			||||||
 | 
					          if (currentAlign !== align) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return (
 | 
				
			||||||
 | 
					            <SortableItem
 | 
				
			||||||
 | 
					              id={s.name}
 | 
				
			||||||
 | 
					              data={{
 | 
				
			||||||
 | 
					                align,
 | 
				
			||||||
 | 
					                draggable: true,
 | 
				
			||||||
 | 
					                title: s.title,
 | 
				
			||||||
 | 
					                path: getSchemaPath(s),
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <RecursionField name={s.name} schema={s} />
 | 
				
			||||||
 | 
					            </SortableItem>
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					      </Space>
 | 
				
			||||||
 | 
					    </Droppable>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -420,3 +420,28 @@ export default () => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Action.Bar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```tsx
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { SchemaRenderer } from '@nocobase/client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const schema = {
 | 
				
			||||||
 | 
					  type: 'void',
 | 
				
			||||||
 | 
					  name: 'actionbar1',
 | 
				
			||||||
 | 
					  'x-component': 'Action.Bar',
 | 
				
			||||||
 | 
					  'x-designable-bar': 'Action.Bar.DesignableBar',
 | 
				
			||||||
 | 
					  'x-component-props': {
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaRenderer 
 | 
				
			||||||
 | 
					      schema={schema} 
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
@ -11,23 +11,41 @@ import {
 | 
				
			|||||||
  useField,
 | 
					  useField,
 | 
				
			||||||
  SchemaExpressionScopeContext,
 | 
					  SchemaExpressionScopeContext,
 | 
				
			||||||
} from '@formily/react';
 | 
					} from '@formily/react';
 | 
				
			||||||
import { Button, Dropdown, Menu, Popover, Space, Drawer, Modal } from 'antd';
 | 
					import {
 | 
				
			||||||
import { Link, useHistory, LinkProps } from 'react-router-dom';
 | 
					  Button,
 | 
				
			||||||
import { useDesignable, useDefaultAction, updateSchema } from '..';
 | 
					  Dropdown,
 | 
				
			||||||
 | 
					  Menu,
 | 
				
			||||||
 | 
					  Popover,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Drawer,
 | 
				
			||||||
 | 
					  Modal,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					} from 'antd';
 | 
				
			||||||
 | 
					import { Link, useHistory, LinkProps, Switch } from 'react-router-dom';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  useDesignable,
 | 
				
			||||||
 | 
					  useDefaultAction,
 | 
				
			||||||
 | 
					  updateSchema,
 | 
				
			||||||
 | 
					  removeSchema,
 | 
				
			||||||
 | 
					} from '..';
 | 
				
			||||||
import './style.less';
 | 
					import './style.less';
 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import cls from 'classnames';
 | 
					import cls from 'classnames';
 | 
				
			||||||
import { MenuOutlined } from '@ant-design/icons';
 | 
					import { MenuOutlined } from '@ant-design/icons';
 | 
				
			||||||
import { FormLayout } from '@formily/antd';
 | 
					import { FormDialog, FormLayout } from '@formily/antd';
 | 
				
			||||||
import IconPicker from '../../components/icon-picker';
 | 
					import IconPicker from '../../components/icon-picker';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  findPropertyByPath,
 | 
					  findPropertyByPath,
 | 
				
			||||||
  getSchemaPath,
 | 
					  getSchemaPath,
 | 
				
			||||||
 | 
					  SchemaField,
 | 
				
			||||||
  useSchemaComponent,
 | 
					  useSchemaComponent,
 | 
				
			||||||
} from '../../components/schema-renderer';
 | 
					} from '../../components/schema-renderer';
 | 
				
			||||||
import { VisibleContext } from '../../context';
 | 
					import { VisibleContext } from '../../context';
 | 
				
			||||||
import { DndContext, DragOverlay } from '@dnd-kit/core';
 | 
					import { DndContext, DragOverlay } from '@dnd-kit/core';
 | 
				
			||||||
import { createPortal } from 'react-dom';
 | 
					import { createPortal } from 'react-dom';
 | 
				
			||||||
 | 
					import { ActionBar } from './ActionBar';
 | 
				
			||||||
 | 
					import { DragHandle } from '../../components/Sortable';
 | 
				
			||||||
 | 
					import { useDisplayedMapContext } from '../../constate';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ButtonComponentContext = createContext(null);
 | 
					export const ButtonComponentContext = createContext(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -90,6 +108,8 @@ Action.Modal = observer((props: any) => {
 | 
				
			|||||||
  const { run: runOk } = useOkAction();
 | 
					  const { run: runOk } = useOkAction();
 | 
				
			||||||
  const { run: runCancel } = useCancelAction();
 | 
					  const { run: runCancel } = useCancelAction();
 | 
				
			||||||
  const isFormDecorator = schema['x-decorator'] === 'Form';
 | 
					  const isFormDecorator = schema['x-decorator'] === 'Form';
 | 
				
			||||||
 | 
					  const field = useField();
 | 
				
			||||||
 | 
					  console.log('Action.Modal.field', field);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Modal
 | 
					    <Modal
 | 
				
			||||||
      title={schema.title}
 | 
					      title={schema.title}
 | 
				
			||||||
@ -304,10 +324,11 @@ Action.Popover = observer((props) => {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Action.DesignableBar = (props: any) => {
 | 
					Action.DesignableBar = (props: any) => {
 | 
				
			||||||
  const field = useField();
 | 
					  const { schema, remove, refresh, insertAfter } = useDesignable();
 | 
				
			||||||
  // const schema = useFieldSchema();
 | 
					 | 
				
			||||||
  const { schema, insertAfter, refresh } = useDesignable(props.path);
 | 
					 | 
				
			||||||
  const [visible, setVisible] = useState(false);
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
 | 
					  const isPopup = Object.keys(schema.properties || {}).length > 0;
 | 
				
			||||||
 | 
					  const displayed = useDisplayedMapContext();
 | 
				
			||||||
 | 
					  const field = useField();
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={cls('designable-bar', { active: visible })}>
 | 
					    <div className={cls('designable-bar', { active: visible })}>
 | 
				
			||||||
      <span
 | 
					      <span
 | 
				
			||||||
@ -316,6 +337,7 @@ Action.DesignableBar = (props: any) => {
 | 
				
			|||||||
        }}
 | 
					        }}
 | 
				
			||||||
        className={cls('designable-bar-actions', { active: visible })}
 | 
					        className={cls('designable-bar-actions', { active: visible })}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
 | 
					        <DragHandle />
 | 
				
			||||||
        <Dropdown
 | 
					        <Dropdown
 | 
				
			||||||
          trigger={['click']}
 | 
					          trigger={['click']}
 | 
				
			||||||
          visible={visible}
 | 
					          visible={visible}
 | 
				
			||||||
@ -325,25 +347,85 @@ Action.DesignableBar = (props: any) => {
 | 
				
			|||||||
          overlay={
 | 
					          overlay={
 | 
				
			||||||
            <Menu>
 | 
					            <Menu>
 | 
				
			||||||
              <Menu.Item
 | 
					              <Menu.Item
 | 
				
			||||||
                onClick={(e) => {
 | 
					                onClick={async (e) => {
 | 
				
			||||||
                  console.log('按钮文案被修改了', { schema });
 | 
					                  const values = await FormDialog('修改名称和图标', () => {
 | 
				
			||||||
                  schema.title = '按钮文案被修改了';
 | 
					                    return (
 | 
				
			||||||
                  // field.setTitle('按钮文案被修改了');
 | 
					                      <FormLayout layout={'vertical'}>
 | 
				
			||||||
                  // setVisible(false);
 | 
					                        <SchemaField
 | 
				
			||||||
 | 
					                          schema={{
 | 
				
			||||||
 | 
					                            type: 'object',
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              title: {
 | 
				
			||||||
 | 
					                                type: 'string',
 | 
				
			||||||
 | 
					                                title: '按钮名称',
 | 
				
			||||||
 | 
					                                required: true,
 | 
				
			||||||
 | 
					                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                'x-component': 'Input',
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                              icon: {
 | 
				
			||||||
 | 
					                                type: 'string',
 | 
				
			||||||
 | 
					                                title: '按钮图标',
 | 
				
			||||||
 | 
					                                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                                'x-component': 'IconPicker',
 | 
				
			||||||
 | 
					                              },
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                          }}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                      </FormLayout>
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                  }).open({
 | 
				
			||||||
 | 
					                    initialValues: {
 | 
				
			||||||
 | 
					                      title: schema['title'],
 | 
				
			||||||
 | 
					                      icon: schema['x-component-props']?.['icon'],
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                  schema['title'] = values.title;
 | 
				
			||||||
 | 
					                  schema['x-component-props']['icon'] = values.icon;
 | 
				
			||||||
 | 
					                  field.componentProps.icon = values.icon;
 | 
				
			||||||
 | 
					                  field.title = values.title;
 | 
				
			||||||
 | 
					                  updateSchema(schema);
 | 
				
			||||||
                  refresh();
 | 
					                  refresh();
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                点击修改按钮文案
 | 
					                修改名称和图标
 | 
				
			||||||
              </Menu.Item>
 | 
					              </Menu.Item>
 | 
				
			||||||
 | 
					              {isPopup && (
 | 
				
			||||||
 | 
					                <Menu.Item>
 | 
				
			||||||
 | 
					                  在{' '}
 | 
				
			||||||
 | 
					                  <Select
 | 
				
			||||||
 | 
					                    bordered={false}
 | 
				
			||||||
 | 
					                    size={'small'}
 | 
				
			||||||
 | 
					                    defaultValue={'Action.Modal'}
 | 
				
			||||||
 | 
					                    onChange={(value) => {
 | 
				
			||||||
 | 
					                      const s = Object.values(schema.properties).shift();
 | 
				
			||||||
 | 
					                      s['x-component'] = value;
 | 
				
			||||||
 | 
					                      refresh();
 | 
				
			||||||
 | 
					                      updateSchema(s);
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Select.Option value={'Action.Modal'}>对话框</Select.Option>
 | 
				
			||||||
 | 
					                    <Select.Option value={'Action.Drawer'}>抽屉</Select.Option>
 | 
				
			||||||
 | 
					                    <Select.Option value={'Action.Window'}>
 | 
				
			||||||
 | 
					                      浏览器窗口
 | 
				
			||||||
 | 
					                    </Select.Option>
 | 
				
			||||||
 | 
					                  </Select>{' '}
 | 
				
			||||||
 | 
					                  内打开
 | 
				
			||||||
 | 
					                </Menu.Item>
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					              <Menu.Divider />
 | 
				
			||||||
              <Menu.Item
 | 
					              <Menu.Item
 | 
				
			||||||
                onClick={() => {
 | 
					                onClick={async () => {
 | 
				
			||||||
                  insertAfter({
 | 
					                  const displayName =
 | 
				
			||||||
                    name: uid(),
 | 
					                    schema?.['x-decorator-props']?.['displayName'];
 | 
				
			||||||
                    'x-component': 'Input',
 | 
					                  const data = remove();
 | 
				
			||||||
                  });
 | 
					                  await removeSchema(data);
 | 
				
			||||||
 | 
					                  if (displayName) {
 | 
				
			||||||
 | 
					                    displayed.remove(displayName);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  setVisible(false);
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                insertAfter
 | 
					                移除
 | 
				
			||||||
              </Menu.Item>
 | 
					              </Menu.Item>
 | 
				
			||||||
            </Menu>
 | 
					            </Menu>
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -354,3 +436,5 @@ Action.DesignableBar = (props: any) => {
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Action.Bar = ActionBar;
 | 
				
			||||||
 | 
				
			|||||||
@ -225,7 +225,6 @@ function generateCardItemSchema(component) {
 | 
				
			|||||||
          properties: {
 | 
					          properties: {
 | 
				
			||||||
            [uid()]: {
 | 
					            [uid()]: {
 | 
				
			||||||
              type: 'void',
 | 
					              type: 'void',
 | 
				
			||||||
              name: 'action1',
 | 
					 | 
				
			||||||
              'x-component': 'Action',
 | 
					              'x-component': 'Action',
 | 
				
			||||||
              'x-component-props': {
 | 
					              'x-component-props': {
 | 
				
			||||||
                icon: 'EllipsisOutlined',
 | 
					                icon: 'EllipsisOutlined',
 | 
				
			||||||
@ -844,6 +843,12 @@ AddNew.PaneItem = observer((props: any) => {
 | 
				
			|||||||
                  },
 | 
					                  },
 | 
				
			||||||
                  'x-designable-bar': 'Form.DesignableBar',
 | 
					                  'x-designable-bar': 'Form.DesignableBar',
 | 
				
			||||||
                  properties: {
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    [uid()]: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      'x-component': 'Action.Bar',
 | 
				
			||||||
 | 
					                      'x-designable-bar': 'Action.Bar.DesignableBar',
 | 
				
			||||||
 | 
					                      'x-component-props': {},
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
                    [uid()]: {
 | 
					                    [uid()]: {
 | 
				
			||||||
                      type: 'void',
 | 
					                      type: 'void',
 | 
				
			||||||
                      'x-component': 'Grid',
 | 
					                      'x-component': 'Grid',
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,18 @@ import {
 | 
				
			|||||||
  useDisplayedMapContext,
 | 
					  useDisplayedMapContext,
 | 
				
			||||||
} from '../../constate';
 | 
					} from '../../constate';
 | 
				
			||||||
import { useResource as useGeneralResource } from '../../hooks/useResource';
 | 
					import { useResource as useGeneralResource } from '../../hooks/useResource';
 | 
				
			||||||
 | 
					import { Resource } from '../../resource';
 | 
				
			||||||
 | 
					import { BaseResult } from '@ahooksjs/use-request/lib/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface FormReadPrettyContextProps {
 | 
				
			||||||
 | 
					  resource?: Resource;
 | 
				
			||||||
 | 
					  service?: BaseResult<any, any>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const FormContext = createContext<FormReadPrettyContextProps>({});
 | 
				
			||||||
 | 
					export const FormReadPrettyContext = createContext<FormReadPrettyContextProps>(
 | 
				
			||||||
 | 
					  {},
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FormMain = (props: any) => {
 | 
					const FormMain = (props: any) => {
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
@ -50,9 +62,11 @@ const FormMain = (props: any) => {
 | 
				
			|||||||
      readPretty: schema['x-read-pretty'],
 | 
					      readPretty: schema['x-read-pretty'],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
  const { resource, run } = useResource({
 | 
					  const { resource, run, service } = useResource({
 | 
				
			||||||
    onSuccess: (initialValues: any) => {
 | 
					    onSuccess: (initialValues: any) => {
 | 
				
			||||||
 | 
					      console.log('onSuccess', { initialValues });
 | 
				
			||||||
      form.setInitialValues(initialValues);
 | 
					      form.setInitialValues(initialValues);
 | 
				
			||||||
 | 
					      form.setValues(initialValues);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const path = useSchemaPath();
 | 
					  const path = useSchemaPath();
 | 
				
			||||||
@ -66,7 +80,7 @@ const FormMain = (props: any) => {
 | 
				
			|||||||
      console.log(displayed.map, 'displayed.map', collection?.name);
 | 
					      console.log(displayed.map, 'displayed.map', collection?.name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [displayed.map]);
 | 
					  }, [displayed.map]);
 | 
				
			||||||
  return (
 | 
					  const content = (
 | 
				
			||||||
    <FormProvider form={form}>
 | 
					    <FormProvider form={form}>
 | 
				
			||||||
      {schema['x-decorator'] === 'Form' ? (
 | 
					      {schema['x-decorator'] === 'Form' ? (
 | 
				
			||||||
        <SchemaField
 | 
					        <SchemaField
 | 
				
			||||||
@ -119,6 +133,14 @@ const FormMain = (props: any) => {
 | 
				
			|||||||
      )}
 | 
					      )}
 | 
				
			||||||
    </FormProvider>
 | 
					    </FormProvider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return schema['x-read-pretty'] ? (
 | 
				
			||||||
 | 
					    <FormReadPrettyContext.Provider value={{ resource, service }}>
 | 
				
			||||||
 | 
					      {content}
 | 
				
			||||||
 | 
					    </FormReadPrettyContext.Provider>
 | 
				
			||||||
 | 
					  ) : (
 | 
				
			||||||
 | 
					    <>{content}</>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Form: any = observer((props: any) => {
 | 
					export const Form: any = observer((props: any) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -70,6 +70,8 @@ import { isValid } from '@formily/shared';
 | 
				
			|||||||
import { FormButtonGroup, FormDialog, FormLayout, Submit } from '@formily/antd';
 | 
					import { FormButtonGroup, FormDialog, FormLayout, Submit } from '@formily/antd';
 | 
				
			||||||
import flatten from 'flat';
 | 
					import flatten from 'flat';
 | 
				
			||||||
import IconPicker from '../../components/icon-picker';
 | 
					import IconPicker from '../../components/icon-picker';
 | 
				
			||||||
 | 
					import { FormReadPrettyContext } from '../form';
 | 
				
			||||||
 | 
					import { VisibleContext } from '../../context';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ITableContext {
 | 
					export interface ITableContext {
 | 
				
			||||||
  props: any;
 | 
					  props: any;
 | 
				
			||||||
@ -153,6 +155,7 @@ const useTableUpdateAction = () => {
 | 
				
			|||||||
  } = useTable();
 | 
					  } = useTable();
 | 
				
			||||||
  const ctx = useContext(TableRowContext);
 | 
					  const ctx = useContext(TableRowContext);
 | 
				
			||||||
  const form = useForm();
 | 
					  const form = useForm();
 | 
				
			||||||
 | 
					  const { service: formService } = useContext(FormReadPrettyContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    async run() {
 | 
					    async run() {
 | 
				
			||||||
@ -160,7 +163,11 @@ const useTableUpdateAction = () => {
 | 
				
			|||||||
        await resource.save(form.values, {
 | 
					        await resource.save(form.values, {
 | 
				
			||||||
          resourceKey: ctx.record[rowKey],
 | 
					          resourceKey: ctx.record[rowKey],
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return service.refresh();
 | 
					        if (formService) {
 | 
				
			||||||
 | 
					          await formService.refresh();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        await service.refresh();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      field.value[ctx.index] = form.values;
 | 
					      field.value[ctx.index] = form.values;
 | 
				
			||||||
      // refresh();
 | 
					      // refresh();
 | 
				
			||||||
@ -179,6 +186,7 @@ const useTableDestroyAction = () => {
 | 
				
			|||||||
    props: { refreshRequestOnChange, rowKey },
 | 
					    props: { refreshRequestOnChange, rowKey },
 | 
				
			||||||
  } = useTable();
 | 
					  } = useTable();
 | 
				
			||||||
  const ctx = useContext(TableRowContext);
 | 
					  const ctx = useContext(TableRowContext);
 | 
				
			||||||
 | 
					  const [, setVisible] = useContext(VisibleContext);
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    async run() {
 | 
					    async run() {
 | 
				
			||||||
      if (refreshRequestOnChange) {
 | 
					      if (refreshRequestOnChange) {
 | 
				
			||||||
@ -190,6 +198,7 @@ const useTableDestroyAction = () => {
 | 
				
			|||||||
          [`${rowKey}.in`]: rowKeys,
 | 
					          [`${rowKey}.in`]: rowKeys,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        setSelectedRowKeys([]);
 | 
					        setSelectedRowKeys([]);
 | 
				
			||||||
 | 
					        setVisible && setVisible(false);
 | 
				
			||||||
        return service.refresh();
 | 
					        return service.refresh();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ctx) {
 | 
					      if (ctx) {
 | 
				
			||||||
@ -873,7 +882,7 @@ function generateMenuActionSchema(type) {
 | 
				
			|||||||
      properties: {
 | 
					      properties: {
 | 
				
			||||||
        [uid()]: {
 | 
					        [uid()]: {
 | 
				
			||||||
          type: 'void',
 | 
					          type: 'void',
 | 
				
			||||||
          title: '查看',
 | 
					          title: '查看数据',
 | 
				
			||||||
          'x-component': 'Action.Modal',
 | 
					          'x-component': 'Action.Modal',
 | 
				
			||||||
          'x-component-props': {
 | 
					          'x-component-props': {
 | 
				
			||||||
            bodyStyle: {
 | 
					            bodyStyle: {
 | 
				
			||||||
@ -2011,7 +2020,7 @@ Table.useResource = ({ onSuccess }) => {
 | 
				
			|||||||
    resourceName: collection.name,
 | 
					    resourceName: collection.name,
 | 
				
			||||||
    resourceKey: ctx.record[props.rowKey],
 | 
					    resourceKey: ctx.record[props.rowKey],
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const { data, loading, run } = useRequest(
 | 
					  const service = useRequest(
 | 
				
			||||||
    (params?: any) => {
 | 
					    (params?: any) => {
 | 
				
			||||||
      console.log('Table.useResource', params);
 | 
					      console.log('Table.useResource', params);
 | 
				
			||||||
      return resource.get(params);
 | 
					      return resource.get(params);
 | 
				
			||||||
@ -2022,7 +2031,7 @@ Table.useResource = ({ onSuccess }) => {
 | 
				
			|||||||
      manual: true,
 | 
					      manual: true,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  return { initialValues: data, loading, run, resource };
 | 
					  return { resource, service, initialValues: service.data, ...service };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Table.useTableFilterAction = useTableFilterAction;
 | 
					Table.useTableFilterAction = useTableFilterAction;
 | 
				
			||||||
 | 
				
			|||||||
@ -69,6 +69,7 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-drawer-body,
 | 
				
			||||||
.ant-card-body,
 | 
					.ant-card-body,
 | 
				
			||||||
.ant-modal-body {
 | 
					.ant-modal-body {
 | 
				
			||||||
  .nb-tabs {
 | 
					  .nb-tabs {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user