mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
Merge branch 'feat/tree-collection' into feat/gantt-block
This commit is contained in:
commit
a0120d4163
@ -7,6 +7,7 @@ import { useCollection } from '../collection-manager';
|
|||||||
import { RecordProvider, useRecord } from '../record-provider';
|
import { RecordProvider, useRecord } from '../record-provider';
|
||||||
import { useDesignable } from '../schema-component';
|
import { useDesignable } from '../schema-component';
|
||||||
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
|
||||||
|
import { useActionContext } from '../schema-component';
|
||||||
|
|
||||||
export const FormBlockContext = createContext<any>({});
|
export const FormBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -78,6 +79,18 @@ export const useFormBlockContext = () => {
|
|||||||
|
|
||||||
export const useFormBlockProps = () => {
|
export const useFormBlockProps = () => {
|
||||||
const ctx = useFormBlockContext();
|
const ctx = useFormBlockContext();
|
||||||
|
const record = useRecord();
|
||||||
|
const { fieldSchema } = useActionContext();
|
||||||
|
const { addChild } = fieldSchema['x-component-props'];
|
||||||
|
useEffect(() => {
|
||||||
|
if (addChild) {
|
||||||
|
ctx.form.query('parent').take((field) => {
|
||||||
|
field.disabled = true;
|
||||||
|
field.value = new Proxy({ ...record }, {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ctx.form.setInitialValues(ctx.service?.data?.data);
|
ctx.form.setInitialValues(ctx.service?.data?.data);
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { ArrayField, createForm } from '@formily/core';
|
import { ArrayField, createForm } from '@formily/core';
|
||||||
import { FormContext, Schema, useField, useFieldSchema } from '@formily/react';
|
import { FormContext, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
import React, { createContext, useMemo, useState, useContext,useEffect } from 'react';
|
||||||
import { useCollectionManager, useCollection } from '../collection-manager';
|
import { useCollectionManager } from '../collection-manager';
|
||||||
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
|
||||||
import { useFixedSchema } from '../schema-component';
|
import { useFixedSchema } from '../schema-component';
|
||||||
|
import { SchemaComponentOptions } from '../..';
|
||||||
|
|
||||||
export const TableBlockContext = createContext<any>({});
|
export const TableBlockContext = createContext<any>({});
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ export const TableBlockProvider = (props) => {
|
|||||||
const form = useMemo(() => createForm(), []);
|
const form = useMemo(() => createForm(), []);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { getCollection } = useCollectionManager();
|
const { getCollection } = useCollectionManager();
|
||||||
const collection=getCollection(props.collection)
|
const collection = getCollection(props.collection);
|
||||||
const { treeTable } = fieldSchema['x-decorator-props'];
|
const { treeTable } = fieldSchema['x-decorator-props'];
|
||||||
if (props.dragSort) {
|
if (props.dragSort) {
|
||||||
params['sort'] = ['sort'];
|
params['sort'] = ['sort'];
|
||||||
@ -101,11 +102,13 @@ export const TableBlockProvider = (props) => {
|
|||||||
params['appends'] = appends;
|
params['appends'] = appends;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<FormContext.Provider value={form}>
|
<SchemaComponentOptions scope={{ treeTable }}>
|
||||||
<BlockProvider {...props} params={params}>
|
<FormContext.Provider value={form}>
|
||||||
<InternalTableBlockProvider {...props} params={params} />
|
<BlockProvider {...props} params={params}>
|
||||||
</BlockProvider>
|
<InternalTableBlockProvider {...props} params={params} />
|
||||||
</FormContext.Provider>
|
</BlockProvider>
|
||||||
|
</FormContext.Provider>
|
||||||
|
</SchemaComponentOptions>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ export const ActionDesigner = (props) => {
|
|||||||
const actionType = fieldSchema['x-action'] ?? '';
|
const actionType = fieldSchema['x-action'] ?? '';
|
||||||
const isLinkageAction = Object.keys(useFormBlockContext()).length > 0 && Object.keys(useRecord()).length > 0;
|
const isLinkageAction = Object.keys(useFormBlockContext()).length > 0 && Object.keys(useRecord()).length > 0;
|
||||||
const isChildCollectionAction = getChildrenCollections(name).length > 0 && fieldSchema['x-action'] === 'create';
|
const isChildCollectionAction = getChildrenCollections(name).length > 0 && fieldSchema['x-action'] === 'create';
|
||||||
|
const isSupportEditButton = fieldSchema['x-action'] !== 'expandAll';
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const schemaUid = uid();
|
const schemaUid = uid();
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
@ -85,6 +86,7 @@ export const ActionDesigner = (props) => {
|
|||||||
title: t('Button title'),
|
title: t('Button title'),
|
||||||
default: fieldSchema.title,
|
default: fieldSchema.title,
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
|
'x-visible': isSupportEditButton,
|
||||||
// description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
// description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
@ -93,6 +95,7 @@ export const ActionDesigner = (props) => {
|
|||||||
title: t('Button icon'),
|
title: t('Button icon'),
|
||||||
default: fieldSchema?.['x-component-props']?.icon,
|
default: fieldSchema?.['x-component-props']?.icon,
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
|
'x-visible': isSupportEditButton,
|
||||||
// description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
// description: `原字段标题:${collectionField?.uiSchema?.title}`,
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
@ -114,27 +117,25 @@ export const ActionDesigner = (props) => {
|
|||||||
} as ISchema
|
} as ISchema
|
||||||
}
|
}
|
||||||
onSubmit={({ title, icon, type }) => {
|
onSubmit={({ title, icon, type }) => {
|
||||||
if (title) {
|
fieldSchema.title = title;
|
||||||
fieldSchema.title = title;
|
field.title = title;
|
||||||
field.title = title;
|
field.componentProps.icon = icon;
|
||||||
field.componentProps.icon = icon;
|
field.componentProps.danger = type === 'danger';
|
||||||
field.componentProps.danger = type === 'danger';
|
field.componentProps.type = type;
|
||||||
field.componentProps.type = type;
|
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
fieldSchema['x-component-props'].icon = icon;
|
||||||
fieldSchema['x-component-props'].icon = icon;
|
fieldSchema['x-component-props'].danger = type === 'danger';
|
||||||
fieldSchema['x-component-props'].danger = type === 'danger';
|
fieldSchema['x-component-props'].type = type;
|
||||||
fieldSchema['x-component-props'].type = type;
|
dn.emit('patch', {
|
||||||
dn.emit('patch', {
|
schema: {
|
||||||
schema: {
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
title,
|
||||||
title,
|
'x-component-props': {
|
||||||
'x-component-props': {
|
...fieldSchema['x-component-props'],
|
||||||
...fieldSchema['x-component-props'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
dn.refresh();
|
});
|
||||||
}
|
dn.refresh();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isLinkageAction && <SchemaSettings.LinkageRules collectionName={name} />}
|
{isLinkageAction && <SchemaSettings.LinkageRules collectionName={name} />}
|
||||||
|
@ -10,13 +10,7 @@ import { default as classNames, default as cls } from 'classnames';
|
|||||||
import React, { RefCallback, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { RefCallback, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { DndContext, useDesignable } from '../..';
|
import { DndContext, useDesignable } from '../..';
|
||||||
import {
|
import { RecordIndexProvider, RecordProvider, useSchemaInitializer, useTableBlockContext } from '../../../';
|
||||||
RecordIndexProvider,
|
|
||||||
RecordProvider,
|
|
||||||
useSchemaInitializer,
|
|
||||||
useTableBlockContext,
|
|
||||||
SchemaComponentOptions,
|
|
||||||
} from '../../../';
|
|
||||||
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
import { useACLFieldWhitelist } from '../../../acl/ACLProvider';
|
||||||
import { isCollectionFieldComponent, isColumnComponent, extractIndex, getIdsWithChildren } from './utils';
|
import { isCollectionFieldComponent, isColumnComponent, extractIndex, getIdsWithChildren } from './utils';
|
||||||
|
|
||||||
@ -418,57 +412,55 @@ export const Table: any = observer((props: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaComponentOptions scope={{ treeTable }}>
|
<div
|
||||||
<div
|
ref={mountedRef}
|
||||||
ref={mountedRef}
|
className={css`
|
||||||
className={css`
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
.ant-table-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
}
|
||||||
.ant-table-wrapper {
|
.ant-table {
|
||||||
height: 100%;
|
overflow-x: auto;
|
||||||
}
|
overflow-y: hidden;
|
||||||
.ant-table {
|
}
|
||||||
overflow-x: auto;
|
`}
|
||||||
overflow-y: hidden;
|
>
|
||||||
}
|
<SortableWrapper>
|
||||||
`}
|
<AntdTable
|
||||||
>
|
ref={(ref) => {
|
||||||
<SortableWrapper>
|
const headerHeight = ref?.querySelector('.ant-table-header')?.getBoundingClientRect().height || 0;
|
||||||
<AntdTable
|
const paginationHeight = ref?.querySelector('.ant-table-pagination')?.getBoundingClientRect().height || 0;
|
||||||
ref={(ref) => {
|
setHeaderAndPaginationHeight(Math.ceil(headerHeight + paginationHeight + 16));
|
||||||
const headerHeight = ref?.querySelector('.ant-table-header')?.getBoundingClientRect().height || 0;
|
}}
|
||||||
const paginationHeight = ref?.querySelector('.ant-table-pagination')?.getBoundingClientRect().height || 0;
|
rowKey={rowKey ?? defaultRowKey}
|
||||||
setHeaderAndPaginationHeight(Math.ceil(headerHeight + paginationHeight + 16));
|
{...others}
|
||||||
}}
|
{...restProps}
|
||||||
rowKey={rowKey ?? defaultRowKey}
|
pagination={paginationProps}
|
||||||
{...others}
|
components={components}
|
||||||
{...restProps}
|
onChange={(pagination, filters, sorter, extra) => {
|
||||||
pagination={paginationProps}
|
onTableChange?.(pagination, filters, sorter, extra);
|
||||||
components={components}
|
}}
|
||||||
onChange={(pagination, filters, sorter, extra) => {
|
tableLayout={'auto'}
|
||||||
onTableChange?.(pagination, filters, sorter, extra);
|
scroll={scroll}
|
||||||
}}
|
columns={columns}
|
||||||
tableLayout={'auto'}
|
expandable={{
|
||||||
scroll={scroll}
|
onExpand: (flag, record) => {
|
||||||
columns={columns}
|
const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i);
|
||||||
expandable={{
|
setExpandesKeys(newKeys);
|
||||||
onExpand: (flag, record) => {
|
},
|
||||||
const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i);
|
expandedRowKeys: expandedKeys,
|
||||||
setExpandesKeys(newKeys);
|
}}
|
||||||
},
|
dataSource={field?.value?.slice?.()}
|
||||||
expandedRowKeys: expandedKeys,
|
/>
|
||||||
}}
|
</SortableWrapper>
|
||||||
dataSource={field?.value?.slice?.()}
|
{field.errors.length > 0 && (
|
||||||
/>
|
<div className="ant-formily-item-error-help ant-formily-item-help ant-formily-item-help-enter ant-formily-item-help-enter-active">
|
||||||
</SortableWrapper>
|
{field.errors.map((error) => {
|
||||||
{field.errors.length > 0 && (
|
return error.messages.map((message) => <div>{message}</div>);
|
||||||
<div className="ant-formily-item-error-help ant-formily-item-help ant-formily-item-help-enter ant-formily-item-help-enter-active">
|
})}
|
||||||
{field.errors.map((error) => {
|
</div>
|
||||||
return error.messages.map((message) => <div>{message}</div>);
|
)}
|
||||||
})}
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</SchemaComponentOptions>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useFieldSchema } from '@formily/react';
|
|
||||||
import { SchemaComponentOptions } from '../../schema-component';
|
|
||||||
import { ActionInitializer } from './ActionInitializer';
|
import { ActionInitializer } from './ActionInitializer';
|
||||||
|
|
||||||
export const CreateChildInitializer = (props) => {
|
export const CreateChildInitializer = (props) => {
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("Add Child") }}',
|
title: '{{ t("Add Child") }}',
|
||||||
@ -55,10 +53,3 @@ export const CreateChildInitializer = (props) => {
|
|||||||
};
|
};
|
||||||
return <ActionInitializer {...props} schema={schema} />;
|
return <ActionInitializer {...props} schema={schema} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateChildProvider = (props) => {
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
const { treeTable } = schema?.parent?.['x-decorator-props'];
|
|
||||||
console.log(props, schema);
|
|
||||||
return <SchemaComponentOptions>{props.children}</SchemaComponentOptions>;
|
|
||||||
};
|
|
||||||
|
@ -16,18 +16,3 @@ export const CreateSubmitActionInitializer = (props) => {
|
|||||||
};
|
};
|
||||||
return <ActionInitializer {...props} schema={schema} />;
|
return <ActionInitializer {...props} schema={schema} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateChildSubmitActionInitializer = (props) => {
|
|
||||||
const schema = {
|
|
||||||
title: '{{ t("Submit") }}',
|
|
||||||
'x-action': 'submit',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-designer': 'Action.Designer',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'primary',
|
|
||||||
htmlType: 'submit',
|
|
||||||
useProps: '{{ useCreateChildActionProps }}',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return <ActionInitializer {...props} schema={schema} />;
|
|
||||||
};
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { ActionInitializer } from './ActionInitializer';
|
import { css } from '@emotion/css';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ActionInitializer } from './ActionInitializer';
|
||||||
import { useTableBlockContext } from '../../';
|
import { useTableBlockContext } from '../../';
|
||||||
import { NodeCollapseOutlined, NodeExpandOutlined } from '@ant-design/icons';
|
import { NodeCollapseOutlined, NodeExpandOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export const ExpandActionInitializer = (props) => {
|
export const ExpandActionInitializer = (props) => {
|
||||||
const schema = {
|
const schema = {
|
||||||
'x-action': 'expandAll',
|
'x-action': 'expandAll',
|
||||||
@ -23,17 +25,62 @@ export const ExpandActionInitializer = (props) => {
|
|||||||
return <ActionInitializer {...props} schema={schema} />;
|
return <ActionInitializer {...props} schema={schema} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ExpandActionComponent = () => {
|
export const actionDesignerCss = css`
|
||||||
|
position: relative;
|
||||||
|
&:hover {
|
||||||
|
.general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: rgba(241, 139, 98, 0.06);
|
||||||
|
border: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: #f18b62;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ExpandActionComponent = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ctx = useTableBlockContext();
|
const ctx = useTableBlockContext();
|
||||||
return (
|
return (
|
||||||
<Button
|
<div className={actionDesignerCss}>
|
||||||
onClick={() => {
|
{ctx.params['tree'] && (
|
||||||
ctx?.setExpandFlag();
|
<Button
|
||||||
}}
|
onClick={() => {
|
||||||
icon={ctx?.expandFlag ? <NodeCollapseOutlined /> : <NodeExpandOutlined />}
|
ctx?.setExpandFlag();
|
||||||
>
|
}}
|
||||||
{ctx?.expandFlag ? t('Collapse all') : t('Expand all')}
|
icon={ctx?.expandFlag ? <NodeCollapseOutlined /> : <NodeExpandOutlined />}
|
||||||
</Button>
|
type={props.type}
|
||||||
|
>
|
||||||
|
{props.children[1]}
|
||||||
|
<span style={{ marginLeft: 10 }}>{ctx?.expandFlag ? t('Collapse all') : t('Expand all')}</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user