Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(table): support children column add funtion #3273

Merged
merged 6 commits into from Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/descriptions/src/descriptions.en-US.md
Expand Up @@ -83,7 +83,7 @@ Format the date according to format

ProDescriptions supports the same dataSource as Table

<code src="./demos/data-source.tsx" title="dataSource configuration data"/>
<code src="./demos/use-data-source.tsx" title="dataSource configuration data"/>

### Editable definition list

Expand Down
2 changes: 1 addition & 1 deletion packages/descriptions/src/descriptions.md
Expand Up @@ -83,7 +83,7 @@ interface RequestData {

ProDescriptions 支持了和 Table 相同的 dataSource

<code src="./demos/data-source.tsx" title="dataSource 配置数据"/>
<code src="./demos/use-data-source.tsx" title="dataSource 配置数据"/>

### 可编辑的定义列表

Expand Down
186 changes: 186 additions & 0 deletions packages/table/src/components/EditableTable/demos/children.tsx
@@ -0,0 +1,186 @@
import React, { useState } from 'react';
import type { ProColumns } from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
import ProField from '@ant-design/pro-field';
import ProCard from '@ant-design/pro-card';

const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};

type DataSourceType = {
id?: React.Key;
title?: string;
decs?: string;
state?: string;
created_at?: string;
update_at?: string;
children?: DataSourceType[];
};

const defaultData: DataSourceType[] = [
{
id: 624748504,
title: '活动名称一',
decs: '这个活动真好玩',
state: 'open',
created_at: '2020-05-26T09:42:56Z',
update_at: '2020-05-26T09:42:56Z',
children: [
{
id: 6246912293,
title: '活动名称二',
decs: '这个活动真好玩',
state: 'closed',
created_at: '2020-05-26T08:19:22Z',
update_at: '2020-05-26T08:19:22Z',
},
],
},
{
id: 624691229,
title: '活动名称二',
decs: '这个活动真好玩',
state: 'closed',
created_at: '2020-05-26T08:19:22Z',
update_at: '2020-05-26T08:19:22Z',
},
];

const loopDataSourceFilter = (
data: DataSourceType[],
id: React.Key | undefined,
): DataSourceType[] => {
return data
.map((item) => {
if (item.id !== id) {
if (item.children) {
const newChildren = loopDataSourceFilter(item.children, id);
return {
...item,
children: newChildren.length > 0 ? newChildren : undefined,
};
}
return item;
}
return null;
})
.filter(Boolean) as DataSourceType[];
};
export default () => {
const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
const [dataSource, setDataSource] = useState<DataSourceType[]>(() => defaultData);
const columns: ProColumns<DataSourceType>[] = [
{
title: '活动名称',
dataIndex: 'title',
formItemProps: (form, { rowIndex }) => {
return {
rules: rowIndex > 2 ? [{ required: true, message: '此项为必填项' }] : [],
};
},
width: '30%',
},
{
title: '状态',
key: 'state',
dataIndex: 'state',
valueType: 'select',
valueEnum: {
all: { text: '全部', status: 'Default' },
open: {
text: '未解决',
status: 'Error',
},
closed: {
text: '已解决',
status: 'Success',
},
},
},
{
title: '描述',
dataIndex: 'decs',
fieldProps: (from, { rowKey, rowIndex }) => {
if (from.getFieldValue([rowKey || '', 'title']) === '不好玩') {
return {
disabled: true,
};
}
if (rowIndex > 9) {
return {
disabled: true,
};
}
return {};
},
},
{
title: '活动时间',
dataIndex: 'created_at',
valueType: 'date',
},
{
title: '操作',
valueType: 'option',
width: 200,
render: (text, record) => [
<a
key="delete"
onClick={() => {
setDataSource(loopDataSourceFilter(dataSource, record.id));
}}
>
删除
</a>,
],
},
];

return (
<>
<EditableProTable<DataSourceType>
expandable={{
defaultExpandAllRows: true,
}}
rowKey="id"
headerTitle="可编辑表格"
maxLength={5}
recordCreatorProps={{
position: 'bottom',
newRecordType: 'dataSource',
parentKey: () => 624748504,
record: () => ({ id: (Math.random() * 1000000).toFixed(0) }),
}}
columns={columns}
value={dataSource}
onChange={setDataSource}
editable={{
type: 'multiple',
editableKeys,
onSave: async (rowKey, data, row) => {
console.log(rowKey, data, row);
await waitTime(2000);
},
onChange: setEditableRowKeys,
}}
/>
<ProCard title="表格数据" headerBordered collapsible defaultCollapsed>
<ProField
fieldProps={{
style: {
width: '100%',
},
}}
mode="read"
valueType="jsonCode"
text={JSON.stringify(dataSource)}
/>
</ProCard>
</>
);
};
6 changes: 6 additions & 0 deletions packages/table/src/components/EditableTable/index.md
Expand Up @@ -17,6 +17,10 @@ nav:

<code src="./demos/basic.tsx" background="#f5f5f5" height="420px" title="可编辑表格" />

### 有子列的表格增加

<code src="./demos/children.tsx" background="#f5f5f5" height="420px" title="可展开表格" />

### 自定义可编辑表格

<code src="./demos/custom.tsx" background="#f5f5f5" height="420px" title="自定义可编辑表格" />
Expand Down Expand Up @@ -62,6 +66,8 @@ nav:

```typescript
recordCreatorProps = {
// 要增加到哪个节点下,一般用于多重嵌套表格
parentKey: React.key,
// 顶部添加还是末尾添加
position: 'end',
// 新增一行的方式,默认是缓存,取消后就会消失
Expand Down
55 changes: 34 additions & 21 deletions packages/table/src/components/EditableTable/index.tsx
Expand Up @@ -19,6 +19,8 @@ export type RecordCreatorProps<DataSourceType> = {
* @augments cache 将会把数据放到缓存中,取消后消失
*/
newRecordType?: 'dataSource' | 'cache';
/** 要增加到哪个节点下,一般用于多重嵌套表格 */
parentKey?: React.Key | ((index: number, dataSource: DataSourceType[]) => React.Key);
};

export type EditableProTableProps<T, U extends ParamsType> = Omit<
Expand Down Expand Up @@ -50,13 +52,19 @@ const EditableTableActionContext = React.createContext<
>(undefined);

/** 可编辑表格的按钮 */
function RecordCreator<T = {}>(props: RecordCreatorProps<T> & { children: JSX.Element }) {
const { children, record, position, newRecordType } = props;
function RecordCreator<T = Record<string, any>>(
props: RecordCreatorProps<T> & { children: JSX.Element },
) {
const { children, record, position, newRecordType, parentKey } = props;
const actionRef = useContext(EditableTableActionContext);
return React.cloneElement(children, {
...children.props,
onClick: (e: any) => {
actionRef?.current?.addEditRecord(record, { position, newRecordType });
actionRef?.current?.addEditRecord(record, {
position,
newRecordType,
parentKey: parentKey as React.Key,
});
children.props.onClick?.(e);
},
});
Expand Down Expand Up @@ -99,7 +107,7 @@ function EditableTable<
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value, props.controlled]);

const { record, position, creatorButtonText, newRecordType, ...restButtonProps } =
const { record, position, creatorButtonText, newRecordType, parentKey, ...restButtonProps } =
recordCreatorProps || {};
const isTop = position === 'top';
const creatorButtonDom = useMemo(() => {
Expand All @@ -111,6 +119,7 @@ function EditableTable<
<RecordCreator
record={runFunction(record, value.length, value) || {}}
position={position}
parentKey={runFunction(parentKey, value.length, value)}
newRecordType={newRecordType}
>
<Button
Expand Down Expand Up @@ -179,6 +188,26 @@ function EditableTable<
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isTop, creatorButtonDom]);

const editableProps = {
form,
...props.editable,
};

if (
props?.onValuesChange ||
props.editable?.onValuesChange ||
// 受控模式需要触发 onchange
(props.controlled && props?.onChange)
) {
editableProps.onValuesChange = (r: DataType, dataSource: DataType[]) => {
props.editable?.onValuesChange?.(r, dataSource);
props.onValuesChange?.(dataSource, r);
if (props.controlled) {
props?.onChange?.(dataSource);
}
};
}

return (
<EditableTableActionContext.Provider value={actionRef}>
<ProTable<DataType, Params>
Expand All @@ -192,23 +221,7 @@ function EditableTable<
actionRef={actionRef}
onChange={onTableChange}
dataSource={value}
editable={{
form,
...props.editable,
onValuesChange:
props?.onValuesChange ||
props.editable?.onValuesChange ||
// 受控模式需要触发 onchange
(props.controlled && props?.onChange)
? (r: DataType, dataSource: DataType[]) => {
props.editable?.onValuesChange?.(r, dataSource);
props.onValuesChange?.(dataSource, r);
if (props.controlled) {
props?.onChange?.(dataSource);
}
}
: undefined,
}}
editable={editableProps}
onDataSourceChange={setValue}
/>
</EditableTableActionContext.Provider>
Expand Down
23 changes: 19 additions & 4 deletions packages/utils/src/useEditableArray/index.tsx
Expand Up @@ -27,6 +27,8 @@ export type AddLineOptions = {
position?: 'top' | 'bottom';
recordKey?: RecordKey;
newRecordType?: 'dataSource' | 'cache';
/** 要增加到哪个节点下,一般用于多重嵌套表格 */
parentKey?: RecordKey;
};

export type NewLineConfig<T> = {
Expand Down Expand Up @@ -172,6 +174,7 @@ function editableRowByKey<RecordType>(
if (action === 'delete') {
kvMap.delete(key);
}

const fill = (map: Map<string, RecordType & { map_row_parentKey?: string }>) => {
const kvArrayMap = new Map<string, RecordType[]>();
const kvSource: RecordType[] = [];
Expand All @@ -182,14 +185,13 @@ function editableRowByKey<RecordType>(
if (kvArrayMap.has(map_row_key)) {
reset[childrenColumnName] = kvArrayMap.get(map_row_key);
}

kvArrayMap.set(map_row_parentKey, [
...(kvArrayMap.get(map_row_parentKey) || []),
reset as RecordType,
]);
return;
}

});
map.forEach((value) => {
if (!value.map_row_parentKey) {
// @ts-ignore
const { map_row_key, ...rest } = value;
Expand All @@ -207,6 +209,7 @@ function editableRowByKey<RecordType>(
return kvSource;
};
const source = fill(kvMap);

return source;
}

Expand Down Expand Up @@ -517,7 +520,19 @@ function useEditableArray<RecordType>(
editableKeysSet.add(recordKey);
setEditableRowKeys(Array.from(editableKeysSet));
if (options?.newRecordType === 'dataSource') {
props.setDataSource?.([...props.dataSource, row]);
const actionProps = {
data: props.dataSource,
getRowKey: props.getRowKey,
row: {
...row,
map_row_parentKey: options?.parentKey
? recordKeyToString(options?.parentKey)?.toString()
: undefined,
},
key: recordKey,
childrenColumnName: props.childrenColumnName || 'children',
};
props.setDataSource(editableRowByKey(actionProps, 'update'));
} else {
setNewLineRecord({
defaultValue: row,
Expand Down