From 0314faeae939f37400dbdaa18306c49d1770e53a Mon Sep 17 00:00:00 2001 From: chenos Date: Sun, 29 Aug 2021 00:25:28 +0800 Subject: [PATCH] feat: improve code --- .../src/components/schema-renderer/index.tsx | 1 + packages/client/src/demos/RequestProvider.tsx | 39 +++ packages/client/src/schemas/add-new/index.tsx | 117 ++++++++- .../client/src/schemas/block-item/index.tsx | 12 +- .../client/src/schemas/card-item/index.tsx | 12 +- packages/client/src/schemas/form/index.tsx | 57 +++-- .../client/src/schemas/select/demos/demo1.tsx | 206 +++++++++++++++ packages/client/src/schemas/select/index.md | 187 +------------- packages/client/src/schemas/select/index.tsx | 235 ++++++++++++------ .../client/src/schemas/table/demos/demo3.tsx | 215 +++++++--------- packages/client/src/schemas/table/index.tsx | 152 ++++++++++- 11 files changed, 791 insertions(+), 442 deletions(-) create mode 100644 packages/client/src/demos/RequestProvider.tsx create mode 100644 packages/client/src/schemas/select/demos/demo1.tsx diff --git a/packages/client/src/components/schema-renderer/index.tsx b/packages/client/src/components/schema-renderer/index.tsx index e9e1a95cb..eafc07a96 100644 --- a/packages/client/src/components/schema-renderer/index.tsx +++ b/packages/client/src/components/schema-renderer/index.tsx @@ -162,6 +162,7 @@ export const SchemaField = createSchemaField({ loadData: loadChinaRegionData, loadDataSource: loadChinaRegionDataSource, }, + Select, }, components: { Card, diff --git a/packages/client/src/demos/RequestProvider.tsx b/packages/client/src/demos/RequestProvider.tsx new file mode 100644 index 000000000..307fb08ee --- /dev/null +++ b/packages/client/src/demos/RequestProvider.tsx @@ -0,0 +1,39 @@ +import { useRequest } from 'ahooks'; +import { Spin } from 'antd'; +import React, { useMemo } from 'react'; +import { MemoryRouter as Router } from 'react-router-dom'; +import { + createRouteSwitch, + RouteRedirectProps, + AdminLayout, + AuthLayout, + RouteSchemaRenderer, +} from '../'; +import { UseRequestProvider } from 'ahooks'; +import { extend } from 'umi-request'; + +const request = extend({ + prefix: process.env.API_URL, + timeout: 30000, +}); + +request.use(async (ctx, next) => { + const { headers } = ctx.req.options as any; + const token = localStorage.getItem('NOCOBASE_TOKEN'); + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } + await next(); +}); + +export const RequestProvider = (props) => { + return ( + request(service), + }} + > + {props.children} + + ); +}; diff --git a/packages/client/src/schemas/add-new/index.tsx b/packages/client/src/schemas/add-new/index.tsx index 418419ee4..2bd875173 100644 --- a/packages/client/src/schemas/add-new/index.tsx +++ b/packages/client/src/schemas/add-new/index.tsx @@ -124,16 +124,7 @@ function generateCardItemSchema(component) { 'x-designable-bar': 'Table.DesignableBar', 'x-decorator': 'CardItem', 'x-component': 'Table', - default: [ - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - // { key: uid(), field1: uid(), field2: uid() }, - ], + default: [], 'x-component-props': { rowKey: 'id', dragSort: true, @@ -178,7 +169,7 @@ function generateCardItemSchema(component) { icon: 'DeleteOutlined', confirm: { title: '删除数据', - content: '删除后无法恢复,确定要删除吗?' + content: '删除后无法恢复,确定要删除吗?', }, useAction: '{{ Table.useTableDestroyAction }}', }, @@ -1407,6 +1398,110 @@ AddNew.FormItem = observer((props: any) => { fieldName: field.name, }, }; + if (field.interface === 'linkTo') { + data.properties = { + options: { + type: 'void', + 'x-decorator': 'Form', + 'x-component': 'Select.Options.Drawer', + 'x-component-props': { + useOkAction: '{{ Select.useOkAction }}', + }, + title: '关联数据', + properties: { + table: { + type: 'array', + 'x-designable-bar': 'Table.DesignableBar', + 'x-decorator': 'BlockItem', + 'x-decorator-props': { + draggable: false, + }, + 'x-component': 'Table', + default: [], + 'x-component-props': { + rowKey: 'id', + defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}', + onSelect: '{{ Select.useSelect() }}', + collectionName: field.target, + // dragSort: true, + showIndex: true, + refreshRequestOnChange: true, + pagination: { + pageSize: 10, + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Table.ActionBar', + 'x-designable-bar': + 'Table.ActionBar.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '筛选', + 'x-decorator': 'AddNew.Displayed', + 'x-decorator-props': { + displayName: 'filter', + }, + 'x-align': 'left', + 'x-component': 'Table.Filter', + 'x-designable-bar': + 'Table.Filter.DesignableBar', + 'x-component-props': { + fieldNames: [], + }, + }, + }, + }, + }, + }, + }, + }, + option: { + type: 'void', + 'x-component': 'Select.OptionTag', + properties: { + [uid()]: { + type: 'void', + title: '查看数据', + 'x-component': 'Action.Drawer', + 'x-component-props': { + bodyStyle: { + background: '#f0f2f5', + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Tabs', + 'x-designable-bar': 'Tabs.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '详情', + 'x-designable-bar': + 'Tabs.TabPane.DesignableBar', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.PaneItem', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }; + } if (isGridBlock(schema)) { path.pop(); path.pop(); diff --git a/packages/client/src/schemas/block-item/index.tsx b/packages/client/src/schemas/block-item/index.tsx index 8bd452a19..7811ba657 100644 --- a/packages/client/src/schemas/block-item/index.tsx +++ b/packages/client/src/schemas/block-item/index.tsx @@ -28,6 +28,7 @@ import cls from 'classnames'; import { Droppable, SortableItem } from '../../components/Sortable'; import { useDndContext } from '@dnd-kit/core'; import { getSchemaPath } from '../../components/schema-renderer'; +import { BlockSchemaContext } from '../../context'; const DraggableBlock = (props) => { const { className, children, ...others } = props; @@ -62,8 +63,13 @@ const Block = (props) => { export const BlockItem: any = observer((props: any) => { const { draggable = true } = props; const ctx = useDndContext(); - return React.createElement( - draggable && ctx.activators?.length > 0 ? DraggableBlock : Block, - props, + const { schema } = useDesignable(); + return ( + + {React.createElement( + draggable && ctx.activators?.length > 0 ? DraggableBlock : Block, + props, + )} + ); }); diff --git a/packages/client/src/schemas/card-item/index.tsx b/packages/client/src/schemas/card-item/index.tsx index f8e51939f..b9ab881e5 100644 --- a/packages/client/src/schemas/card-item/index.tsx +++ b/packages/client/src/schemas/card-item/index.tsx @@ -24,12 +24,10 @@ import { BlockSchemaContext } from '../../context'; export const CardItem: any = connect((props) => { const { schema } = useDesignable(); return ( - - - - {props.children} - - - + + + {props.children} + + ); }); diff --git a/packages/client/src/schemas/form/index.tsx b/packages/client/src/schemas/form/index.tsx index e8ee260b5..8debd27cd 100644 --- a/packages/client/src/schemas/form/index.tsx +++ b/packages/client/src/schemas/form/index.tsx @@ -11,7 +11,13 @@ import { useForm, RecursionField, } from '@formily/react'; -import { useSchemaPath, SchemaField, useDesignable, removeSchema, ISchema } from '../'; +import { + useSchemaPath, + SchemaField, + useDesignable, + removeSchema, + ISchema, +} from '../'; import get from 'lodash/get'; import { Button, Dropdown, Menu, message, Space } from 'antd'; import { MenuOutlined, DragOutlined } from '@ant-design/icons'; @@ -38,6 +44,7 @@ import { import { useResource as useGeneralResource } from '../../hooks/useResource'; import { Resource } from '../../resource'; import { BaseResult } from '@ahooksjs/use-request/lib/types'; +import { CollectionFieldContext } from '../table'; export interface DescriptionsContextProps { resource?: Resource; @@ -87,15 +94,11 @@ const FormMain = (props: any) => { 'x-decorator': 'Form.__Decorator', }, }, - } + }; const content = ( {schema['x-decorator'] === 'Form' ? ( - + ) : ( { const required = schema['required'] || collectionField?.uiSchema?.required; const description = schema['description'] || collectionField?.uiSchema?.description; + console.log('schema.properties', schema.properties) return ( - + + } as ISchema) + } + /> + ); }); diff --git a/packages/client/src/schemas/select/demos/demo1.tsx b/packages/client/src/schemas/select/demos/demo1.tsx new file mode 100644 index 000000000..101a87306 --- /dev/null +++ b/packages/client/src/schemas/select/demos/demo1.tsx @@ -0,0 +1,206 @@ +import React from 'react'; +import { ISchema, SchemaRenderer } from '../../'; +import { useSelect, useOptionTagValues } from '../'; +import { uid } from '@formily/shared'; +import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider'; +import { CollectionsProvider } from '@nocobase/client/src/constate'; + +console.log({ useSelect }); + +const dataSource = [ + { + id: 1, + title: '标题1', + }, + { + id: 2, + title: '标题2', + }, + { + id: 3, + title: '标题3', + }, +] as any[]; + +function useValues() { + return { + table: dataSource, + }; +} + +const schema: ISchema = { + type: 'object', + properties: { + input: { + interface: 'select', + type: 'string', + title: `编辑模式`, + enum: dataSource, + default: [ + { + id: 1, + title: '标题1', + }, + { + id: 2, + title: '标题2', + }, + ], + 'x-decorator': 'FormItem', + 'x-component': 'Select.Drawer', + 'x-component-props': { + placeholder: 'please enter', + mode: 'tags', + fieldNames: { + label: 'title', + value: 'id', + }, + }, + 'x-reactions': { + target: 'read', + fulfill: { + state: { + value: '{{$self.value}}', + }, + }, + }, + properties: { + options: { + type: 'void', + 'x-decorator': 'Form', + 'x-component': 'Select.Options.Drawer', + title: '关联数据', + properties: { + table: { + type: 'array', + 'x-designable-bar': 'Table.DesignableBar', + 'x-decorator': 'BlockItem', + 'x-decorator-props': { + draggable: false, + }, + 'x-component': 'Table', + default: [], + 'x-component-props': { + rowKey: 'id', + collectionName: 'users', + // dragSort: true, + showIndex: true, + refreshRequestOnChange: true, + pagination: { + pageSize: 10, + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Table.ActionBar', + 'x-designable-bar': 'Table.ActionBar.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '筛选', + 'x-decorator': 'AddNew.Displayed', + 'x-decorator-props': { + displayName: 'filter', + }, + 'x-align': 'left', + 'x-component': 'Table.Filter', + 'x-designable-bar': 'Table.Filter.DesignableBar', + 'x-component-props': { + fieldNames: [], + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + read: { + interface: 'select', + type: 'string', + title: `阅读模式`, + enum: dataSource, + default: [ + { + id: 1, + title: '标题1', + }, + { + id: 2, + title: '标题2', + }, + ], + 'x-read-pretty': true, + 'x-decorator': 'FormItem', + 'x-component': 'Select.Drawer', + 'x-component-props': { + placeholder: 'please enter', + mode: 'tags', + fieldNames: { + label: 'title', + value: 'id', + }, + }, + properties: { + option: { + type: 'void', + 'x-component': 'Select.OptionTag', + properties: { + [uid()]: { + type: 'void', + title: '查看数据', + 'x-component': 'Action.Drawer', + 'x-component-props': { + bodyStyle: { + background: '#f0f2f5', + // paddingTop: 0, + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Tabs', + 'x-designable-bar': 'Tabs.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '详情', + 'x-designable-bar': 'Tabs.TabPane.DesignableBar', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.PaneItem', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + + + ); +}; diff --git a/packages/client/src/schemas/select/index.md b/packages/client/src/schemas/select/index.md index 76a709ba2..588653653 100644 --- a/packages/client/src/schemas/select/index.md +++ b/packages/client/src/schemas/select/index.md @@ -383,192 +383,7 @@ export default () => { ## Select.Drawer -```tsx -import React from 'react'; -import { SchemaRenderer } from '../'; -import { useSelect, useOptionTagValues } from './'; - -console.log({ useSelect }) - -const dataSource = [ - { - id: 1, - title: '标题1', - }, - { - id: 2, - title: '标题2', - }, - { - id: 3, - title: '标题3', - }, -]; - -function useValues() { - return { - table: dataSource, - } -} - -const schema = { - type: 'object', - properties: { - input: { - interface: 'select', - type: 'string', - title: `编辑模式`, - enum: dataSource, - default: [ - { - id: 1, - title: '标题1', - }, - { - id: 2, - title: '标题2', - }, - ], - 'x-decorator': 'FormItem', - 'x-component': 'Select.Drawer', - 'x-component-props': { - placeholder: 'please enter', - mode: 'tags', - fieldNames: { - label: 'title', - value: 'id', - }, - }, - 'x-reactions': { - target: 'read', - fulfill: { - state: { - value: '{{$self.value}}', - }, - }, - }, - properties: { - options: { - type: 'void', - 'x-component': 'Select.Options', - properties: { - form: { - type: 'void', - 'x-component': 'Form', - 'x-component-props': { - useValues: '{{ useValues }}', - }, - properties: { - table: { - type: 'array', - 'x-component': 'Table', - properties: { - actionbar: { - type: 'void', - 'x-component': 'Table.ActionBar', - 'x-component-props': { - align: 'bottom', - }, - properties: { - action: { - type: 'void', - 'x-component': 'Action', - 'x-component-props': { - useAction: '{{ useSelect }}', - }, - title: '确定', - }, - }, - }, - column1: { - type: 'void', - title: '标题', - 'x-component': 'Table.Column', - 'x-component-props': { - // title: 'z1', - }, - // 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - title: { - type: 'string', - required: true, - 'x-read-pretty': true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - read: { - interface: 'select', - type: 'string', - title: `阅读模式`, - enum: dataSource, - default: [ - { - id: 1, - title: '标题1', - }, - { - id: 2, - title: '标题2', - }, - ], - 'x-read-pretty': true, - 'x-decorator': 'FormItem', - 'x-component': 'Select.Drawer', - 'x-component-props': { - placeholder: 'please enter', - mode: 'tags', - fieldNames: { - label: 'title', - value: 'id', - }, - }, - properties: { - option: { - type: 'void', - 'x-component': 'Select.OptionTag', - properties: { - form: { - type: 'void', - 'x-component': 'Form', - 'x-component-props': { - useValues: '{{ useOptionTagValues }}', - }, - properties: { - title: { - type: 'string', - title: '标题', - 'x-read-pretty': true, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - } - } -}; - -export default () => { - return ( - - ); -}; -``` + ## Schema API diff --git a/packages/client/src/schemas/select/index.tsx b/packages/client/src/schemas/select/index.tsx index 7c74908e3..e7e510efa 100644 --- a/packages/client/src/schemas/select/index.tsx +++ b/packages/client/src/schemas/select/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { connect, mapReadPretty, @@ -7,6 +7,7 @@ import { observer, RecursionField, useFieldSchema, + Schema, } from '@formily/react'; import { Drawer, Select as AntdSelect, Tag } from 'antd'; import { PreviewText } from '@formily/antd'; @@ -19,6 +20,14 @@ import { createContext } from 'react'; import { useContext } from 'react'; import { isEmpty } from 'lodash'; import { Field, isArrayField, isField } from '@formily/core'; +import { Action } from '../action'; +import { BlockSchemaContext, VisibleContext } from '../../context'; +import { SchemaRenderer } from '../../components/schema-renderer'; +import { uid } from '@formily/shared'; +import { CollectionFieldContext } from '../table'; +import { CollectionProvider, useCollectionContext } from '../../constate'; +import { Resource } from '../../resource'; +import { useRequest } from 'ahooks'; export const Select: any = connect( (props) => { @@ -227,22 +236,48 @@ Select.Object = connect( const OptionTagContext = createContext(null); -const SelectContext = createContext({}); +const SelectedRowKeysContext = createContext([]); + +Select.useOkAction = () => { + const { props } = useContext(SelectContext); + const [selectedRows] = useContext(SelectedRowKeysContext); + return { + async run() { + props.onChange(selectedRows); + console.log('selectedRows', selectedRows); + }, + }; +}; + +Select.useSelect = () => { + const [, setSelectedRows] = useContext(SelectedRowKeysContext); + return (keys, rows) => { + setSelectedRows(rows); + console.log('Select.onSelect', keys, rows); + }; +}; + +Select.useSelectedRowKeys = () => { + const [selectedRows] = useContext(SelectedRowKeysContext); + return selectedRows?.map((row) => row.id) || []; +}; + +const SelectContext = createContext(null); Select.Drawer = connect( (props) => { - const field = useField(); + const field = useField(); const { value, onChange, fieldNames = { - label: 'label', - value: 'value', + label: 'id', + value: 'id', }, ...others } = props; const [visible, setVisible] = useState(false); - const schema = useFieldSchema(); + const { schema } = useDesignable(); const options = field?.['dataSource'] || props.options || []; let optionValue = undefined; @@ -289,60 +324,49 @@ Select.Drawer = connect( ); } }; - - const selectedKeys = toArr(optionValue).map((item) => item.value); - - console.log({ selectedKeys }); - + // const selectedKeys = toArr(optionValue).map((item) => item.value); + const [selectedRows, setSelectedRows] = useState(toArr(field.value)); + console.log({ optionValue, value }); + const collectionField = useContext(CollectionFieldContext); return ( - <> - { - setVisible(true); - }} - onChange={(selectValue: any) => { - if (!selectValue) { - onChange(null); - return; - } - if (isArr(selectValue)) { - const selectValues = selectValue.map((s) => s.value); - onFieldChange(selectValues); - } else { - onFieldChange(selectValue.value); - } - }} - > - setVisible(false)} - destroyOnClose - > - {/* */} - + + { + setVisible(true); }} + onChange={(selectValue: any) => { + if (!selectValue) { + onChange(null); + return; + } + if (isArr(selectValue)) { + const selectValues = selectValue.map((s) => s.value); + onFieldChange(selectValues); + } else { + onFieldChange(selectValue.value); + } + }} + > + - { - return s['x-component'] === 'Select.Options'; - }} - /> - - {/* */} - - + + { + return s['x-component'] === 'Select.Options.Drawer'; + }} + /> + + + + ); }, mapProps( @@ -365,41 +389,98 @@ Select.Drawer = connect( ), mapReadPretty( observer((props: any) => { + const collectionField = useContext(CollectionFieldContext); const field = useField(); - const { fieldNames = { label: 'label' }, ...others } = props; + const { fieldNames = { label: 'id' }, ...others } = props; const value = field.value || field.initialValue; - const schema = useFieldSchema(); + const { schema } = useDesignable(); console.log({ fieldNames, field, value }); if (!value) { return null; } const values = toArr(value); + const s = schema.reduceProperties((buf, current) => { + if (current['x-component'] === 'Select.OptionTag') { + return current; + } + return buf; + }, null); return (
- {values.map((data, index) => { - return ( - - {data[fieldNames.label]} - {/* { - return s['x-component'] === 'Select.OptionTag'; - }} - /> */} - - ); - })} + + + {values.map((data, index) => { + return ( + + {s ? ( + + ) : ( + data[fieldNames.label] + )} + + ); + })} + +
); }), ), ); +Select.Drawer.useResource = ({ onSuccess }) => { + const { collection } = useCollectionContext(); + const ctx = useContext(OptionTagContext); + const resource = Resource.make({ + resourceName: collection?.name, + resourceKey: ctx.data.id, + }); + console.log('OptionTagContext', ctx.data.id) + const { schema } = useDesignable(); + const fieldFields = (schema: Schema) => { + const names = []; + schema.reduceProperties((buf, current) => { + if (current['x-component'] === 'Form.Field') { + const fieldName = current['x-component-props']?.['fieldName']; + if (fieldName) { + buf.push(fieldName); + } + } else { + const fieldNames = fieldFields(current); + buf.push(...fieldNames); + } + return buf; + }, names); + return names; + }; + const [visible] = useContext(VisibleContext); + const service = useRequest( + (params?: any) => { + console.log('Table.useResource', params); + return resource.get({ ...params, appends: fieldFields(schema) }); + }, + { + formatResult: (result) => result?.data, + onSuccess, + manual: true, + }, + ); + useEffect(() => { + if (visible) { + service.run(); + } + }, [visible]); + return { resource, service, initialValues: service.data, ...service }; +} + Select.Options = observer((props) => { return <>{props.children}; }); +Select.Options.Drawer = Action.Drawer; + export function useSelect() { const { onChange } = useContext(SelectContext); return { @@ -418,12 +499,10 @@ Select.OptionTag = observer((props) => { const [visible, setVisible] = useState(false); const { data, fieldNames } = useContext(OptionTagContext); return ( - <> + setVisible(true)}>{data[fieldNames.label]} - setVisible(false)}> - {props.children} - - + {props.children} + ); }); diff --git a/packages/client/src/schemas/table/demos/demo3.tsx b/packages/client/src/schemas/table/demos/demo3.tsx index 45482a681..7ba486237 100644 --- a/packages/client/src/schemas/table/demos/demo3.tsx +++ b/packages/client/src/schemas/table/demos/demo3.tsx @@ -3,39 +3,29 @@ import { range } from 'lodash'; import { ISchema } from '@formily/react'; import { SchemaRenderer } from '../..'; import { uid } from '@formily/shared'; +import { + CollectionsProvider, + DesignableSwitchProvider, +} from '@nocobase/client/src/constate'; +import { RequestProvider } from '@nocobase/client/src/demos/RequestProvider'; -const loadDataSource = (params?: any): Promise => { - const { page, pageSize = 50 } = params || {}; - console.log({ pageSize }); - return new Promise((resolve) => { - setTimeout(() => { - resolve({ - list: range(50 || pageSize).map(() => { - return { id: uid(), title: uid() }; - }), - total: 50, - }); - }, 1000); - }); -}; - -const schema: ISchema = { +const schema = { + name: 'table1', type: 'array', - name: 'arr', + 'x-designable-bar': 'Table.DesignableBar', + 'x-decorator': 'CardItem', 'x-component': 'Table', + default: [], 'x-component-props': { + collectionName: 'users', + rowKey: 'id', dragSort: true, showIndex: true, - refreshRequestOnChange: false, - clientSidePagination: true, - dataRequest: '{{ loadDataSource }}', + refreshRequestOnChange: true, pagination: { - pageSize: 2, + pageSize: 10, }, }, - // default: range(50).map(() => { - // return { id: uid(), title: uid() }; - // }), properties: { [uid()]: { type: 'void', @@ -44,6 +34,12 @@ const schema: ISchema = { properties: { [uid()]: { type: 'void', + title: '筛选', + 'x-decorator': 'AddNew.Displayed', + 'x-decorator-props': { + displayName: 'filter', + }, + 'x-align': 'left', 'x-component': 'Table.Filter', 'x-designable-bar': 'Table.Filter.DesignableBar', 'x-component-props': { @@ -53,15 +49,44 @@ const schema: ISchema = { [uid()]: { type: 'void', name: 'action1', - title: '添加', + 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': { + icon: 'DeleteOutlined', + confirm: { + title: '删除数据', + content: '删除后无法恢复,确定要删除吗?', + }, + useAction: '{{ Table.useTableDestroyAction }}', + }, + }, + [uid()]: { + type: 'void', + name: 'action1', + title: '添加', + 'x-align': 'right', + 'x-decorator': 'AddNew.Displayed', + 'x-decorator-props': { + displayName: 'create', + }, + 'x-component': 'Action', + 'x-component-props': { + icon: 'PlusOutlined', + type: 'primary', + }, + 'x-designable-bar': 'Table.Action.DesignableBar', properties: { modal: { type: 'void', title: '添加数据', 'x-decorator': 'Form', - 'x-component': 'Action.Modal', + 'x-component': 'Action.Drawer', 'x-component-props': { useOkAction: '{{ Table.useTableCreateAction }}', }, @@ -77,76 +102,55 @@ const schema: ISchema = { }, }, }, - [uid()]: { - type: 'void', - name: 'action1', - title: '删除', - 'x-component': 'Action', - 'x-designable-bar': 'Table.Action.DesignableBar', - 'x-component-props': { - useAction: '{{ Table.useTableDestroyAction }}', - }, - }, }, }, - column2: { + [uid()]: { type: 'void', title: '操作', 'x-component': 'Table.Column', - 'x-component-props': { - className: 'nb-table-operation', - }, + 'x-component-props': {}, + 'x-designable-bar': 'Table.Operation.DesignableBar', properties: { - action1: { + [uid()]: { type: 'void', - name: 'dropdown1', - 'x-component': 'Action.Dropdown', - 'x-designable-bar': 'Action.DesignableBar', + 'x-component': 'Action.Group', 'x-component-props': { - buttonProps: { - icon: 'EllipsisOutlined', - }, + type: 'link', }, properties: { - [uid()]: { - type: 'void', - title: '操作 1', - 'x-component': 'Menu.Action', - 'x-component-props': { - style: { - minWidth: 150, - }, - disabled: true, - }, - }, [uid()]: { type: 'void', name: 'action1', title: '查看', - 'x-component': 'Menu.Action', + 'x-component': 'Action', + 'x-component-props': { + type: 'link', + }, 'x-designable-bar': 'Table.Action.DesignableBar', + 'x-action-type': 'view', properties: { [uid()]: { type: 'void', - title: '查看', - 'x-component': 'Action.Modal', + title: '查看数据', + 'x-component': 'Action.Drawer', 'x-component-props': { bodyStyle: { background: '#f0f2f5', - paddingTop: 0, + // paddingTop: 0, }, }, properties: { [uid()]: { type: 'void', 'x-component': 'Tabs', + 'x-designable-bar': 'Tabs.DesignableBar', properties: { [uid()]: { type: 'void', + title: '详情', + 'x-designable-bar': 'Tabs.TabPane.DesignableBar', 'x-component': 'Tabs.TabPane', - 'x-component-props': { - tab: 'Tab1', - }, + 'x-component-props': {}, properties: { [uid()]: { type: 'void', @@ -166,17 +170,22 @@ const schema: ISchema = { [uid()]: { type: 'void', title: '编辑', - 'x-component': 'Menu.Action', + 'x-component': 'Action', + 'x-component-props': { + type: 'link', + }, 'x-designable-bar': 'Table.Action.DesignableBar', + 'x-action-type': 'update', properties: { [uid()]: { type: 'void', title: '编辑数据', 'x-decorator': 'Form', 'x-decorator-props': { + useResource: '{{ Table.useResource }}', useValues: '{{ Table.useTableRowRecord }}', }, - 'x-component': 'Action.Modal', + 'x-component': 'Action.Drawer', 'x-component-props': { useOkAction: '{{ Table.useTableUpdateAction }}', }, @@ -187,75 +196,39 @@ const schema: ISchema = { 'x-component-props': { addNewComponent: 'AddNew.FormItem', }, - properties: { - [uid()]: { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - [uid()]: { - type: 'void', - 'x-component': 'Grid.Col', - properties: { - title: { - title: '标题', - type: 'string', - 'x-component': 'Input', - 'x-decorator': 'FormItem', - }, - }, - }, - }, - }, - }, }, }, }, }, }, - [uid()]: { - type: 'void', - title: '删除', - 'x-component': 'Menu.Action', - 'x-component-props': { - useAction: '{{ Table.useTableDestroyAction }}', - }, - }, + // [uid()]: { + // type: 'void', + // title: '删除', + // 'x-component': 'Action', + // 'x-designable-bar': 'Table.Action.DesignableBar', + // 'x-action-type': 'destroy', + // 'x-component-props': { + // type: 'link', + // useAction: '{{ Table.useTableDestroyAction }}', + // }, + // }, }, }, }, }, - column0: { - type: 'void', - title: 'ID', - 'x-component': 'Table.Column', - 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - id: { - type: 'string', - 'x-component': 'Input', - 'x-read-pretty': true, - }, - }, - }, - column1: { - type: 'void', - title: 'Title', - 'x-component': 'Table.Column', - properties: { - title: { - type: 'string', - 'x-component': 'Input', - 'x-read-pretty': true, - }, - }, - }, }, }; export default () => { return (
- + + + + + + +
); }; diff --git a/packages/client/src/schemas/table/index.tsx b/packages/client/src/schemas/table/index.tsx index 3dd187a29..f20439c23 100644 --- a/packages/client/src/schemas/table/index.tsx +++ b/packages/client/src/schemas/table/index.tsx @@ -40,7 +40,11 @@ import { SchemaField, SchemaRenderer, } from '../../components/schema-renderer'; -import { interfaces, isAssociation, options } from '../database-field/interfaces'; +import { + interfaces, + isAssociation, + options, +} from '../database-field/interfaces'; import { DraggableBlockContext } from '../../components/drag-and-drop'; import AddNew from '../add-new'; import { isGridRowOrCol } from '../grid'; @@ -94,7 +98,7 @@ export interface ITableRowContext { const TableContext = createContext({} as any); export const TableRowContext = createContext(null); -const CollectionFieldContext = createContext(null); +export const CollectionFieldContext = createContext(null); export const useTable = () => { return useContext(TableContext); @@ -417,20 +421,133 @@ function AddColumn() { checked={displayed.has(field.name)} onChange={async (checked) => { if (checked) { - console.log('SwitchMenuItem.field.name', field.dataType, service.params[0]) - const data = appendChild({ + console.log( + 'SwitchMenuItem.field.name', + field.dataType, + service.params[0], + ); + const columnSchema: ISchema = { type: 'void', 'x-component': 'Table.Column', 'x-component-props': { fieldName: field.name, }, 'x-designable-bar': 'Table.Column.DesignableBar', - }); + }; + if (field.interface === 'linkTo') { + columnSchema.properties = { + options: { + type: 'void', + 'x-decorator': 'Form', + 'x-component': 'Select.Options.Drawer', + 'x-component-props': { + useOkAction: '{{ Select.useOkAction }}', + }, + title: '关联数据', + properties: { + table: { + type: 'array', + 'x-designable-bar': 'Table.DesignableBar', + 'x-decorator': 'BlockItem', + 'x-decorator-props': { + draggable: false, + }, + 'x-component': 'Table', + default: [], + 'x-component-props': { + rowKey: 'id', + defaultSelectedRowKeys: '{{ Select.useSelectedRowKeys() }}', + onSelect: '{{ Select.useSelect() }}', + collectionName: field.target, + // dragSort: true, + showIndex: true, + refreshRequestOnChange: true, + pagination: { + pageSize: 10, + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Table.ActionBar', + 'x-designable-bar': + 'Table.ActionBar.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '筛选', + 'x-decorator': 'AddNew.Displayed', + 'x-decorator-props': { + displayName: 'filter', + }, + 'x-align': 'left', + 'x-component': 'Table.Filter', + 'x-designable-bar': + 'Table.Filter.DesignableBar', + 'x-component-props': { + fieldNames: [], + }, + }, + }, + }, + }, + }, + }, + }, + option: { + type: 'void', + 'x-component': 'Select.OptionTag', + properties: { + [uid()]: { + type: 'void', + title: '查看数据', + 'x-component': 'Action.Drawer', + 'x-component-props': { + bodyStyle: { + background: '#f0f2f5', + }, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Tabs', + 'x-designable-bar': 'Tabs.DesignableBar', + properties: { + [uid()]: { + type: 'void', + title: '详情', + 'x-designable-bar': + 'Tabs.TabPane.DesignableBar', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.PaneItem', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }; + } + const data = appendChild(columnSchema); await createSchema(data); if (isAssociation(field)) { - const defaultAppends = service.params[0]?.defaultAppends || []; + const defaultAppends = + service.params[0]?.defaultAppends || []; defaultAppends.push(field.name); - await service.run({...service.params[0], defaultAppends}); + await service.run({ + ...service.params[0], + defaultAppends, + }); } } else { const s: any = displayed.get(field.name); @@ -439,12 +556,16 @@ function AddColumn() { await removeSchema(removed); displayed.remove(field.name); if (isAssociation(field)) { - const defaultAppends = service.params[0]?.defaultAppends || []; + const defaultAppends = + service.params[0]?.defaultAppends || []; const index = defaultAppends.indexOf(field.name); if (index > -1) { defaultAppends.splice(index, 1); } - await service.run({...service.params[0], defaultAppends}); + await service.run({ + ...service.params[0], + defaultAppends, + }); } } // service.refresh(); @@ -535,7 +656,7 @@ const TableMain = () => { setSelectedRowKeys, service, field, - props: { rowKey, dragSort, showIndex }, + props: { rowKey, dragSort, showIndex, onSelect }, refresh, } = useTable(); const columns = useTableColumns(); @@ -624,8 +745,9 @@ const TableMain = () => { rowSelection={{ type: 'checkbox', selectedRowKeys, - onChange: (rowKeys) => { + onChange: (rowKeys, rows) => { setSelectedRowKeys(rowKeys); + onSelect && onSelect(rowKeys, rows); }, renderCell: (checked, record, _, originNode) => { const index = findIndex( @@ -697,12 +819,15 @@ const TableProvider = (props: any) => { rowKey = 'id', dataRequest, useResource = useGeneralResource, + defaultSelectedRowKeys, ...others } = props; const { schema } = useDesignable(); const field = useField(); const [pagination, setPagination] = usePagination(); - const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [selectedRowKeys, setSelectedRowKeys] = useState( + defaultSelectedRowKeys || [], + ); const [, refresh] = useState(uid()); const { resource } = useResource(); const { sortableField } = useCollectionContext(); @@ -1859,6 +1984,9 @@ Table.Cell = observer((props: any) => { feedbackLayout: 'popover', }, 'x-decorator': 'FormilyFormItem', + properties: { + ...schema?.properties, + }, }, }, })