From 3223d95d01efc9dea281df5942d5d2568a8b08ab Mon Sep 17 00:00:00 2001 From: chenos Date: Fri, 23 Jul 2021 18:08:44 +0800 Subject: [PATCH] updates --- .../src/components/admin-layout/datatable.tsx | 3 +- .../src/components/router-config/index.tsx | 4 +- packages/client/src/resource.ts | 19 +- packages/client/src/schemas/action/index.tsx | 8 +- packages/client/src/schemas/add-new/index.tsx | 292 ++++++++++++------ .../client/src/schemas/add-new/style.less | 10 + .../src/schemas/database-field/index.tsx | 10 +- .../src/schemas/database-field/style.less | 7 + packages/client/src/schemas/form/index.tsx | 22 +- packages/client/src/schemas/index.tsx | 15 + packages/client/src/schemas/input/index.tsx | 1 - packages/client/src/schemas/menu/index.tsx | 7 +- packages/client/src/schemas/table/index.tsx | 264 +++++++++++----- .../plugin-collections/src/actions/index.ts | 5 +- .../src/models/collection.ts | 75 ++++- .../plugin-collections/src/models/field.ts | 2 +- 16 files changed, 548 insertions(+), 196 deletions(-) create mode 100644 packages/client/src/schemas/add-new/style.less diff --git a/packages/client/src/components/admin-layout/datatable.tsx b/packages/client/src/components/admin-layout/datatable.tsx index e04eddf51..2ead62ee2 100644 --- a/packages/client/src/components/admin-layout/datatable.tsx +++ b/packages/client/src/components/admin-layout/datatable.tsx @@ -1,5 +1,6 @@ import { SchemaRenderer } from '../../'; import React from 'react'; +import { FormItem } from '@formily/antd'; export default () => { const schema = { @@ -32,5 +33,5 @@ export default () => { }, }, }; - return ; + return ; }; diff --git a/packages/client/src/components/router-config/index.tsx b/packages/client/src/components/router-config/index.tsx index 98830b760..9bb0488b8 100644 --- a/packages/client/src/components/router-config/index.tsx +++ b/packages/client/src/components/router-config/index.tsx @@ -69,10 +69,11 @@ export function createRouteSwitch(options: RouteSwitchOptions) { value={{ ...options.components, ...props.components }} > - {routes.map((route) => { + {routes.map((route, index) => { if (route.type == 'redirect') { return ( { const { useAction = useDefaultAction, icon, ...others } = props; const { run } = useAction(); + const field = useField(); const { schema, DesignableBar } = useDesignable(); - const [visible, setVisible] = useState(false); + const { visible, setVisible } = useVisible(field.address.entire); const child = Object.values(schema.properties || {}).shift(); const isDropdownOrPopover = child && @@ -74,6 +75,7 @@ Action.Modal = observer((props: any) => { } = props; const { schema } = useDesignable(); const [visible, setVisible] = useContext(VisibleContext); + console.log('VisibleContext', visible); const form = useForm(); const { run: runOk } = useOkAction(); const { run: runCancel } = useCancelAction(); @@ -81,7 +83,7 @@ Action.Modal = observer((props: any) => { return ( { const name = schema.name || uid(); return { @@ -117,17 +119,17 @@ function generateCardItemSchema(component) { '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() }, + // { 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() }, ], 'x-component-props': { - rowKey: 'key', + rowKey: 'id', dragSort: true, showIndex: true, }, @@ -232,45 +234,34 @@ function generateCardItemSchema(component) { 'x-component': 'Menu.Action', 'x-designable-bar': 'Table.Action.DesignableBar', properties: { - drawer1: { + [uid()]: { type: 'void', title: '查看', 'x-component': 'Action.Modal', - 'x-component-props': {}, + 'x-component-props': { + bodyStyle: { + background: '#f0f2f5', + paddingTop: 0, + }, + }, properties: { [uid()]: { type: 'void', 'x-component': 'Tabs', properties: { - tab1: { + [uid()]: { type: 'void', 'x-component': 'Tabs.TabPane', 'x-component-props': { tab: 'Tab1', }, properties: { - aaa: { - type: 'string', - title: 'AAA', - 'x-decorator': 'FormItem', - required: true, - 'x-component': 'Input', - }, - }, - }, - tab2: { - type: 'void', - 'x-component': 'Tabs.TabPane', - 'x-component-props': { - tab: 'Tab2', - }, - properties: { - bbb: { - type: 'string', - title: 'BBB', - 'x-decorator': 'FormItem', - required: true, - 'x-component': 'Input', + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.PaneItem', + }, }, }, }, @@ -282,14 +273,13 @@ function generateCardItemSchema(component) { }, [uid()]: { type: 'void', - name: 'action1', - title: '修改', + title: '编辑', 'x-component': 'Menu.Action', 'x-designable-bar': 'Table.Action.DesignableBar', properties: { - drawer1: { + [uid()]: { type: 'void', - title: '编辑表单', + title: '编辑数据', 'x-decorator': 'Form', 'x-decorator-props': { useValues: '{{ Table.useTableRow }}', @@ -299,17 +289,12 @@ function generateCardItemSchema(component) { useOkAction: '{{ Table.useTableUpdateAction }}', }, properties: { - field1: { - type: 'string', - title: '字段1', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - field2: { - type: 'string', - title: '字段2', - 'x-decorator': 'FormItem', - 'x-component': 'Input', + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.FormItem', + }, }, }, }, @@ -327,48 +312,6 @@ function generateCardItemSchema(component) { }, }, }, - [uid()]: { - type: 'void', - title: '字段1', - 'x-component': 'Table.Column', - 'x-component-props': { - // title: 'z1', - }, - 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - field1: { - type: 'string', - required: true, - 'x-read-pretty': true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - [uid()]: { - type: 'void', - title: '字段2', - 'x-component': 'Table.Column', - 'x-component-props': { - // title: 'z1', - }, - 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - field2: { - type: 'string', - required: true, - 'x-read-pretty': true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, }, }, Form: { @@ -679,7 +622,7 @@ AddNew.FormItem = observer((props: any) => { placement={'bottomCenter'} overlay={ - + {resource?.fields?.map((field) => ( { ))} - + {options.map( (option) => option.children.length > 0 && ( @@ -827,4 +774,163 @@ AddNew.FormItem = observer((props: any) => { ); }); +AddNew.PaneItem = observer((props: any) => { + const { ghost, defaultAction } = props; + const { schema, insertBefore, insertAfter, appendChild } = useDesignable(); + const path = useSchemaPath(); + const { resource = {}, refresh } = useResourceContext(); + const [visible, setVisible] = useState(false); + const { displayFields = [] } = useDisplayFieldsContext(); + console.log({ displayFields }); + return ( + + + { + let data: ISchema = { + type: 'void', + name: uid(), + 'x-decorator': 'CardItem', + 'x-component': 'Form', + 'x-read-pretty': true, + 'x-component-props': {}, + 'x-designable-bar': 'Form.DesignableBar', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.FormItem', + }, + }, + }, + }; + 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); + } + setVisible(false); + }} + style={{ minWidth: 150 }} + > + 阅读模式 + + { + let data: ISchema = { + type: 'void', + name: uid(), + 'x-decorator': 'CardItem', + 'x-component': 'Form', + 'x-component-props': { + showDefaultButtons: true, + }, + 'x-designable-bar': 'Form.DesignableBar', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid', + 'x-component-props': { + addNewComponent: 'AddNew.FormItem', + }, + }, + }, + }; + 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); + } + setVisible(false); + }} + > + 编辑模式 + + + + 日志 + 评论 + + { + let data: ISchema = { + key: uid(), + type: 'void', + default: '这是一段演示文字,**支持使用 Markdown 语法**', + 'x-designable-bar': 'Markdown.Void.DesignableBar', + 'x-decorator': 'CardItem', + 'x-read-pretty': true, + 'x-component': 'Markdown.Void', + }; + 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); + } + setVisible(false); + }} + > + 添加说明文字 + + + } + > + {ghost ? ( + + ) : ( + + )} + + ); +}); + export default AddNew; diff --git a/packages/client/src/schemas/add-new/style.less b/packages/client/src/schemas/add-new/style.less new file mode 100644 index 000000000..b43b94140 --- /dev/null +++ b/packages/client/src/schemas/add-new/style.less @@ -0,0 +1,10 @@ +.ant-dropdown-menu-item-group.display-fields { + .ant-dropdown-menu-item-group-list { + overflow: auto; + max-height: 300px; + } +} +.add-new-fields-popup .ant-dropdown-menu { + overflow: auto; + max-height: 300px; +} diff --git a/packages/client/src/schemas/database-field/index.tsx b/packages/client/src/schemas/database-field/index.tsx index 67aa9524c..08395d3a0 100644 --- a/packages/client/src/schemas/database-field/index.tsx +++ b/packages/client/src/schemas/database-field/index.tsx @@ -145,6 +145,7 @@ export const DatabaseCollection = observer((props) => { {field.value?.map((item, index) => { return ( { type: 'error', address: `*(${path},${path}.*)`, }); + console.log('item.key', item.key); return ( { } extra={[ - , + , { e.stopPropagation(); field.remove(index); @@ -305,6 +308,7 @@ export const DatabaseField: any = observer((props) => { { }} > {options.map( - (option) => + (option, groupIndex) => option.children.length > 0 && ( - + {option.children.map((item) => ( {item.title} ))} diff --git a/packages/client/src/schemas/database-field/style.less b/packages/client/src/schemas/database-field/style.less index 2c0db49e0..b8accb89d 100644 --- a/packages/client/src/schemas/database-field/style.less +++ b/packages/client/src/schemas/database-field/style.less @@ -14,3 +14,10 @@ background: #1890ff; } } + +.ant-dropdown.all-fields { + .ant-dropdown-menu { + max-height: 300px; + overflow: auto; + } +} diff --git a/packages/client/src/schemas/form/index.tsx b/packages/client/src/schemas/form/index.tsx index 5ac584c45..f32040734 100644 --- a/packages/client/src/schemas/form/index.tsx +++ b/packages/client/src/schemas/form/index.tsx @@ -22,7 +22,7 @@ import { ResourceContextProvider, } from '../'; import get from 'lodash/get'; -import { Button, Dropdown, Menu, Space } from 'antd'; +import { Button, Dropdown, Menu, message, Space } from 'antd'; import { MenuOutlined, DragOutlined } from '@ant-design/icons'; import cls from 'classnames'; import { FormLayout } from '@formily/antd'; @@ -38,6 +38,7 @@ import { DesignableBar } from './DesignableBar'; import { FieldDesignableBar } from './Field.DesignableBar'; import { createContext } from 'react'; import { BlockItem } from '../block-item'; +import { Resource } from '../../resource'; const [DisplayFieldsContextProvider, useDisplayFieldsContext] = constate(() => { const [displayFields, setDisplayFields] = useState([]); @@ -46,12 +47,12 @@ const [DisplayFieldsContextProvider, useDisplayFieldsContext] = constate(() => { displayFields, setDisplayFields, addDisplayField(fieldName) { - setDisplayFields(fields => fields.concat(fieldName)); + setDisplayFields((fields) => fields.concat(fieldName)); }, - } + }; }); -export { DisplayFieldsContextProvider, useDisplayFieldsContext } +export { DisplayFieldsContextProvider, useDisplayFieldsContext }; export const Form: any = observer((props: any) => { const { @@ -60,12 +61,12 @@ export const Form: any = observer((props: any) => { resourceName, ...others } = props; + const { schema } = useDesignable(); const initialValues = useValues(); const form = useMemo(() => { console.log('Form.useMemo', initialValues); - return createForm({ initialValues }); + return createForm({ initialValues, readPretty: schema['x-read-pretty'] }); }, []); - const { schema } = useDesignable(); const path = useSchemaPath(); const scope = useContext(SchemaExpressionScopeContext); const content = ( @@ -102,6 +103,9 @@ export const Form: any = observer((props: any) => { onClick={async () => { const values = await form.submit(); console.log({ values }); + await Resource.make(resourceName).save(values); + message.success('保存成功'); + await form.reset(); }} type={'primary'} > @@ -121,9 +125,7 @@ export const Form: any = observer((props: any) => { return resourceName ? ( // @ts-ignore - - {content} - + {content} ) : ( content @@ -141,7 +143,7 @@ Form.Field = observer((props: any) => { const { resource = {} } = useResourceContext(); useEffect(() => { if (fieldName) { - addDisplayField(fieldName); + addDisplayField && addDisplayField(fieldName); } }, [fieldName]); if (!fieldName) { diff --git a/packages/client/src/schemas/index.tsx b/packages/client/src/schemas/index.tsx index 53e73a2c5..a26b25aa2 100644 --- a/packages/client/src/schemas/index.tsx +++ b/packages/client/src/schemas/index.tsx @@ -32,6 +32,21 @@ export function mapReadPretty(component: any, readPrettyProps?: any) { } export const VisibleContext = createContext(null); + +export function useVisible(name, defaultValue = false) { + const [visible, setVisible] = useState(defaultValue); + return { visible, setVisible }; + // const [visible, setVisible] = useCookieState(`${name}-visible`, { + // defaultValue: defaultValue ? 'true' : null, + // }); + // return { + // visible: visible === 'true' ? true : false, + // setVisible: (value) => { + // setVisible(value ? 'true' : null); + // }, + // } +} + export const DesignableBarContext = createContext(null); const [PageTitleContextProvider, usePageTitleContext] = constate(() => { diff --git a/packages/client/src/schemas/input/index.tsx b/packages/client/src/schemas/input/index.tsx index 35290da38..3eb9ced77 100644 --- a/packages/client/src/schemas/input/index.tsx +++ b/packages/client/src/schemas/input/index.tsx @@ -24,7 +24,6 @@ type ComposedInput = React.FC & { export const Input: ComposedInput = connect( AntdInput, mapProps((props, field) => { - console.log('fieldfieldfieldfieldfield', field.address.entire); return { ...props, suffix: ( diff --git a/packages/client/src/schemas/menu/index.tsx b/packages/client/src/schemas/menu/index.tsx index 656b0bde3..a40964715 100644 --- a/packages/client/src/schemas/menu/index.tsx +++ b/packages/client/src/schemas/menu/index.tsx @@ -55,6 +55,7 @@ import { removeSchema, updateSchema, useDefaultAction, + useVisible, VisibleContext, } from '..'; import { useMount } from 'ahooks'; @@ -205,7 +206,8 @@ Menu.Link = observer((props: any) => { eventKey={schema.name} key={schema.name} > - {schema.title} + {schema.title} + {/* {schema.title} */} ); @@ -232,7 +234,8 @@ Menu.URL = observer((props: any) => { Menu.Action = observer((props: any) => { const { icon, useAction = useDefaultAction, ...others } = props; const { schema, DesignableBar } = useDesignable(); - const [visible, setVisible] = useState(false); + const field = useField(); + const { visible, setVisible } = useVisible(field.address.entire); const { run } = useAction(); return ( diff --git a/packages/client/src/schemas/table/index.tsx b/packages/client/src/schemas/table/index.tsx index 585c2ab2f..33fadc274 100644 --- a/packages/client/src/schemas/table/index.tsx +++ b/packages/client/src/schemas/table/index.tsx @@ -1,4 +1,10 @@ -import React, { createContext, useContext, useRef, useState } from 'react'; +import React, { + createContext, + useContext, + useEffect, + useRef, + useState, +} from 'react'; import { useFieldSchema, Schema, @@ -22,7 +28,7 @@ import { Select, Switch, } from 'antd'; -import { findIndex, get, set } from 'lodash'; +import { cloneDeep, findIndex, get, set } from 'lodash'; import constate from 'constate'; import useRequest from '@ahooksjs/use-request'; import { uid, clone } from '@formily/shared'; @@ -39,9 +45,11 @@ import { } from 'react-sortable-hoc'; import cls from 'classnames'; import { + createSchema, getSchemaPath, removeSchema, ResourceContextProvider, + updateSchema, useCollectionContext, useDesignable, useResourceContext, @@ -53,6 +61,8 @@ import { DraggableBlockContext } from '../../components/drag-and-drop'; import AddNew from '../add-new'; import { isGridRowOrCol } from '../grid'; import { options } from '../database-field/interfaces'; +import { Resource } from '../../resource'; +import { useDisplayFieldsContext } from '../form'; interface TableRowProps { index: number; @@ -131,10 +141,13 @@ function useTableActionBars() { return findActionBars(schema); } +const ResourceFieldContext = createContext(null); + function useTableColumns(props?: any) { const { schema, designable } = useDesignable(); // const schema = useFieldSchema(); - const { dataSource } = props || {}; + const { dataSource, rowKey = 'id' } = props || {}; + const { resource = {} } = useResourceContext(); function findColumns(schema: Schema): Schema[] { return schema.reduceProperties((columns, current) => { @@ -148,21 +161,35 @@ function useTableColumns(props?: any) { const columns = findColumns(schema).map((item) => { const columnProps = item['x-component-props'] || {}; console.log(item); + const resourceField = columnProps.fieldName + ? resource?.fields?.find((item) => item.name === columnProps.fieldName) + : null; + return { - title: , + title: ( + + + + ), dataIndex: item.name, ...columnProps, render(value, record, recordIndex) { - const index = dataSource.indexOf(record); + const index = findIndex( + dataSource, + (item) => item[rowKey] === record[rowKey], + ); + console.log({ dataSource, record, index }); return ( - - - + + + + + ); }, }; @@ -198,6 +225,7 @@ function useTableColumns(props?: any) { function AddColumn() { const [visible, setVisible] = useState(false); + const { appendChild } = useDesignable(); const { resource = {}, refresh } = useResourceContext(); return ( - + {resource?.fields?.map((field) => (
{ + const data = appendChild({ + type: 'void', + 'x-component': 'Table.Column', + 'x-component-props': { + fieldName: field.name, + }, + 'x-designable-bar': 'Table.Column.DesignableBar', + }); + await createSchema(data); + }} > {field.uiSchema.title} - +
))}
- + {options.map((option) => ( {option.children.map((item) => ( @@ -266,26 +308,31 @@ export function useTableIndex() { export function useTableDestroyAction() { const ctx = useContext(TableRowContext); - const { field, selectedRowKeys, setSelectedRowKeys, refresh } = + const { resource, field, selectedRowKeys, setSelectedRowKeys, refresh } = useTableContext(); const rowKey = field.componentProps.rowKey || 'id'; return { async run() { if (ctx && typeof ctx.index !== 'undefined') { - field.remove(ctx.index); - refresh(); + // field.remove(ctx.index); + await resource.destroy({ + [rowKey]: ctx.data[rowKey], + }); + await refresh(); return; } - if (!selectedRowKeys.length) { return; } - while (selectedRowKeys.length) { - const key = selectedRowKeys.shift(); - const index = findIndex(field.value, (item) => item[rowKey] === key); - field.remove(index); - } + await resource.destroy({ + [`${rowKey}.in`]: selectedRowKeys, + }); + // while (selectedRowKeys.length) { + // const key = selectedRowKeys.shift(); + // const index = findIndex(field.value, (item) => item[rowKey] === key); + // field.remove(index); + // } refresh(); setSelectedRowKeys([]); }, @@ -305,16 +352,18 @@ export function useTableFilterAction() { } export function useTableCreateAction() { - const { field, run: exec, params } = useTableContext(); + const { resource, field, run: exec, params, refresh } = useTableContext(); const [, setVisible] = useContext(VisibleContext); const form = useForm(); return { async run() { setVisible && setVisible(false); - field.push({ - key: uid(), - ...clone(form.values), - }); + await resource.save(form.values); + // await refresh(); + // field.push({ + // key: uid(), + // ...clone(form.values), + // }); form.reset(); exec({ ...params, page: 1 }); }, @@ -322,14 +371,16 @@ export function useTableCreateAction() { } export function useTableUpdateAction() { - const { field, refresh, params } = useTableContext(); + const { resource, field, refresh, params } = useTableContext(); const [, setVisible] = useContext(VisibleContext); const ctx = useContext(TableRowContext); const form = useForm(); return { async run() { - field.value[ctx.index] = form.values; setVisible && setVisible(false); + await resource.save(form.values, { + resourceKey: form.values[field.componentProps.rowKey || 'id'], + }); refresh(); }, }; @@ -342,6 +393,7 @@ const [TableContextProvider, useTableContext] = constate(() => { const [selectedRowKeys, setSelectedRowKeys] = useState( defaultSelectedRowKeys || [], ); + const resource = Resource.make(field.componentProps.resourceName); console.log({ defaultSelectedRowKeys }); const pagination = usePaginationProps(); const response = useRequest<{ @@ -349,6 +401,21 @@ const [TableContextProvider, useTableContext] = constate(() => { total: number; }>((params = {}) => { return new Promise((resolve) => { + resource.list({}).then((res) => { + field.setValue(res?.data || []); + resolve({ + list: res?.data || [], + total: res?.meta?.count || res?.data?.length, + }); + console.log( + 'field.componentProps.resourceName', + field.componentProps.resourceName, + res, + ); + }); + + return; + const dataSource = Array.isArray(field.value) ? field.value.slice() : []; if (pagination) { const { @@ -375,6 +442,7 @@ const [TableContextProvider, useTableContext] = constate(() => { ...(response.params[0] || {}), }; return { + resource, ...response, params, field, @@ -440,7 +508,10 @@ const TableContainer = observer((props) => { type: 'checkbox', selectedRowKeys, renderCell: (checked, record, _, originNode) => { - const index = dataSource.indexOf(record); + const index = findIndex( + dataSource, + (item) => item[rowKey] === record[rowKey], + ); return ( { - const schema = useFieldSchema(); - const field = useField(); - const { DesignableBar } = useDesignableBar(); +Table.Cell = observer((props: any) => { + const ctx = useContext(TableRowContext); + const schema = props.schema; + const resourceField = useContext(ResourceFieldContext); + return ( + + ); + // const { fieldName } = props; + // const { schema } = useDesignable(); + // const path = getSchemaPath(schema); + // const { addDisplayField } = useDisplayFieldsContext(); + // const { resource = {} } = useResourceContext(); + // useEffect(() => { + // if (fieldName) { + // addDisplayField && addDisplayField(fieldName); + // } + // }, [fieldName]); + // if (!fieldName) { + // return null; + // } + // const field = resource?.fields?.find((item) => item.name === fieldName); + // if (!field) { + // return null; + // } + // const name = useContext(FormFieldUIDContext); + // const title = schema['title'] || field.uiSchema['title']; + // return ( + // + // ); +}); + +Table.Column = observer((props: any) => { + const resourceField = useContext(ResourceFieldContext) || {}; + const { schema, DesignableBar } = useDesignable(); return (
- {field.title} + {schema.title || resourceField?.uiSchema?.title}
); @@ -605,52 +742,28 @@ Table.Column.DesignableBar = () => { overlay={ { + onClick={async (e) => { const title = uid(); field.title = title; schema.title = title; + refresh(); + await updateSchema({ + key: schema['key'], + title: title, + }); setVisible(false); }} > - 点击修改按钮文案 + 编辑列 { - remove(); - console.log('Table.Column.DesignableBar', { schema }); + onClick={async () => { + const s = remove(); + await removeSchema(s); }} > 删除列 - { - const name = uid(); - insertAfter({ - name: `column_${name}`, - type: 'void', - title: `字段 ${name}`, - 'x-component': 'Table.Column', - 'x-component-props': { - // title: 'z1', - }, - 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - [name]: { - type: 'string', - required: true, - // 'x-read-pretty': true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }); - }} - > - 插入列 - } > @@ -927,9 +1040,12 @@ Table.Action.DesignableBar = () => { {inActionBar ? ( 放置在右侧 ) : ( - 点击表格行时触发    + + 点击表格行时触发    + + )} - + 删除 diff --git a/packages/plugin-collections/src/actions/index.ts b/packages/plugin-collections/src/actions/index.ts index ccf7a1ae9..9212d9128 100644 --- a/packages/plugin-collections/src/actions/index.ts +++ b/packages/plugin-collections/src/actions/index.ts @@ -30,9 +30,10 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) = await collection.update(values); } await collection.updateAssociations(values); + await collection.migrate(); } catch (error) { console.log('error.errors', error.errors) + throw error; } - ctx.body = collection; -} \ No newline at end of file +} diff --git a/packages/plugin-collections/src/models/collection.ts b/packages/plugin-collections/src/models/collection.ts index e9a82a102..3f3fbf968 100644 --- a/packages/plugin-collections/src/models/collection.ts +++ b/packages/plugin-collections/src/models/collection.ts @@ -1,5 +1,16 @@ import _ from 'lodash'; -import { Model } from '@nocobase/database'; +import { Model, TableOptions } from '@nocobase/database'; + +export interface LoadOptions { + reset?: boolean; + where?: any; + skipExisting?: boolean; + [key: string]: any; +} + +export interface MigrateOptions { + [key: string]: any; +} export class Collection extends Model { static async create(value?: any, options?: any): Promise { @@ -37,4 +48,66 @@ export class Collection extends Model { } return items; } + + /** + * DOTO: + * - database.table 初始化可能存在一些缺陷 + * - 是否需要考虑关系数据的重载? + * + * @param opts + */ + async loadTableOptions(opts: any = {}) { + const options = await this.toProps(); + console.log(JSON.stringify(options, null, 2)); + const table = this.database.table(options); + return table; + } + + /** + * 迁移 + */ + async migrate(options: MigrateOptions = {}) { + const { isNewRecord } = options; + const table = await this.loadTableOptions(options); + // 如果不是新增数据,force 必须为 false + if (!isNewRecord) { + return await table.sync({ + force: false, + alter: { + drop: false, + } + }); + } + // TODO: 暂时加了个 collectionSync 解决 collection.create 的数据不清空问题 + // @ts-ignore + const sync = this.sequelize.options.collectionSync; + return await table.sync(sync || { + force: false, + alter: { + drop: false, + } + }); + } + + /** + * TODO:需要考虑是初次加载还是重载 + * + * @param options + */ + static async load(options: LoadOptions = {}) { + const { skipExisting = false, reset = false, where = {}, transaction } = options; + const collections = await this.findAll({ + transaction, + where, + }); + for (const collection of collections) { + if (skipExisting && this.database.isDefined(collection.get('name'))) { + continue; + } + await collection.loadTableOptions({ + transaction, + reset, + }); + } + } } diff --git a/packages/plugin-collections/src/models/field.ts b/packages/plugin-collections/src/models/field.ts index 78ee0f344..f335849f3 100644 --- a/packages/plugin-collections/src/models/field.ts +++ b/packages/plugin-collections/src/models/field.ts @@ -26,7 +26,7 @@ export class Field extends Model { const data: any = _.omit(json, ['options', 'created_at', 'updated_at']); const options = json['options'] || {}; const fields = await this.getNestedFields(); - const props = { ...data, ...options }; + const props = { type: json['dataType'], ...data, ...options }; if (fields.length) { props['children'] = fields; }