Protable 业务封装
基于 Antd Protable 及 ahooks 的表格组件业务封装
<a href="https://procomponents.ant.design/components/table">Protable:https://procomponents.ant.design/components/table</a>
<a href="https://ahooks.js.org/zh-CN/hooks/async">ahooks:https://ahooks.js.org/zh-CN/hooks/async</a>
-
取消 request 属性,增加 url、moreLoading 字段。
url: 为接口 url
moreLoading:更多的 loading ,与接口 loading&&符号连接,可以传入删除等操作的 loading
formators:传入接口的格式化函数,response 为结果的格式化,params 为传参的格式化
-
actionRef:用 useRef 生成 ref 传入,获得调用子组件方法的能力
- actionRef.reload 刷新
- actionRef.afterDel 删除后调用,传入删除的项,自动重置页码至有数据的页
- actionRef.response 表格接口数据
- ...可以扩展一切需要父组件调用,或者获取的值、函数
type TableProps<T, U extends ParamsType = {}> = Omit<ProTableProps<T, U>, 'request'> & {
url: string;
moreLoading?: boolean;
formators?: {
response?: (res: any) => { total: number; list: any[] }; //格式化接口结果
params?: (res: any) => any; //格式化接口参数
};
actionRef?:
| React.MutableRefObject<{ reload: () => void } | undefined>
| ((actionRef: { reload: () => void }) => void)
| undefined;
};
-
覆写了 Column 的一些默认属性。
- 默认 hideInSearch 为 false,覆写为 true
const columns = useMemo(() => {
return (_columns ?? []).map(i => {
return {
hideInSearch: true,
...i,
};
});
}, [_columns, tableData.data]);
-
自行实现的翻页调用接口
- useRequest 请参考 ahooks <a href="https://ahooks.js.org/zh-CN/hooks/async">ahooks</a>
- sorter 会被覆写为后台要的 sort:'asc'|'desc',sort_field:【field】
- current 和 pageSize 被覆写为 page 和 limit
- 所有 search 参数会被直接传入接口参数
// 表格数据
const tableData = useRequest(
({ current, pageSize, sorter, filters }) => {
let params: any = {
page: current,
limit: pageSize,
...searchParams,
filters,
};
if (sorter?.order) {
params = {
...params,
sort_field: sorter?.field,
sort: sorter?.order === 'ascend' ? 'asc' : 'desc',
};
}
if (formators?.params) {
params = formators.params(params);
}
return fetch({
url,
params,
});
},
{
formatResult: formators?.response
? formators?.response
: res => {
return { total: res?.data?.total ?? 0, list: res?.data?.data };
},
refreshDeps: [searchParams],
paginated: true,
onError(errr) {
console.log({ errr });
},
throwOnError: true,
},
);
- 覆写了 defaultPageSize 为 10
全部代码
import React, { useMemo, useState, useImperativeHandle, useRef } from 'react';
import { fetchPlus as fetch } from '@/utils/request';
import { ParamsType } from '@ant-design/pro-provider';
import { useRequest } from 'ahooks';
import ProTable, {
ProTableProps,
ProColumns,
ActionType as _ActionType,
} from '@ant-design/pro-table';
export type ActionType = _ActionType & {
afterDel: (count?: number) => void; // 删除项后执行翻页,count为删除的数量,缺省为1
response: any; // 接口结果
};
type TableProps<T, U extends ParamsType = {}> = Omit<ProTableProps<T, U>, 'request'>;
type Column<T> = ProColumns<T>;
function Table<
T,
U extends {
[key: string]: any;
} = {}
>(
props: Omit<TableProps<T, U>, 'columns' | 'actionRef'> & {
url: string;
moreLoading?: boolean;
columns: Column<T>[];
formators?: {
response?: (res: any) => { total: number; list: any[] }; //格式化接口结果
params?: (res: any) => any; //格式化接口参数
};
actionRef?:
| React.MutableRefObject<{ reload: () => void } | undefined>
| ((actionRef: { reload: () => void }) => void)
| undefined;
},
) {
const {
columns: _columns,
actionRef,
formators,
url,
loading,
search,
moreLoading,
pagination = {},
...restProps
} = props;
// 查询
const [searchParams, setSearchParams] = useState({});
// 表格数据
const tableData = useRequest(
({ current, pageSize, sorter, filters }) => {
let params: any = {
page: current,
limit: pageSize,
...searchParams,
filters,
};
if (sorter?.order) {
params = {
...params,
sort_field: sorter?.field,
sort: sorter?.order === 'ascend' ? 'asc' : 'desc',
};
}
if (formators?.params) {
params = formators.params(params);
}
return fetch({
url,
params,
});
},
{
formatResult: formators?.response
? formators?.response
: res => {
return { total: res?.data?.total ?? 0, list: res?.data?.data };
},
refreshDeps: [searchParams],
paginated: true,
onError(errr) {
console.log({ errr });
},
throwOnError: true,
},
);
const columns = useMemo(() => {
return (_columns ?? []).map(i => {
return {
hideInSearch: true,
...i,
};
});
}, [_columns, tableData.data]);
const noSearch = useMemo(() => {
return columns.findIndex((i: any) => !i.hideInSearch) === -1;
}, [columns]);
const tableRef = useRef<ActionType>();
const handleAfterDel = (count?: number) => {
// 第一页时,直接获取新数据
if (
tableData.tableProps.dataSource?.length > (count ?? 1) ||
tableData.tableProps.pagination.current === 1
) {
tableData.refresh();
} else {
// 被删除的页数,用于计算需要返回的页数
const deletedPage = Number(
(
Math.floor(
Number(
(
((count ?? 1) - (tableData.tableProps.dataSource?.length ?? 0)) /
(tableData.tableProps.pagination?.pageSize ?? 0)
).toFixed(0),
),
) + 1
).toFixed(0),
);
tableData.run({
current:
Number((tableData.pagination.current - deletedPage).toFixed(0)) > 1
? Number((tableData.pagination.current - deletedPage).toFixed(0))
: 1,
pageSize: tableData.pagination.pageSize,
sorter: tableData.sorter,
filters: tableData.filters,
});
}
};
// 转发方法,及数据到父组件
useImperativeHandle(actionRef, () => ({
reload: tableData.refresh,
reset: () => {
tableRef.current?.reset?.();
setSearchParams({});
},
clearSelected: tableRef.current?.clearSelected,
afterDel: handleAfterDel,
response: tableData.data,
}));
// 表格loading
const tableLoading = useMemo(() => {
let _loading = false;
// 全部拼上moreLoading
if (loading === undefined) {
// 接口loading控制
_loading = tableData.loading || !!moreLoading;
} else {
// props.loading控制
_loading = !!loading || !!moreLoading;
}
return _loading;
}, [loading, moreLoading, tableData.loading]);
return (
<ProTable<T, U>
actionRef={tableRef}
search={search ?? (noSearch ? false : undefined)}
columns={columns}
options={{ reload: tableData.refresh }}
dataSource={tableData.tableProps.dataSource}
loading={tableLoading}
pagination={
pagination === false
? false
: {
...tableData.tableProps.pagination,
showQuickJumper: true,
defaultPageSize: 10,
...(pagination ?? {}),
}
}
onReset={() => {
tableRef.current?.reset?.();
setSearchParams({});
}}
onSubmit={params => {
setSearchParams(params);
}}
onChange={(params, sorter, filters) => {
tableData.tableProps.onChange(params, sorter, filters);
}}
rowKey="id"
dateFormatter="string"
{...restProps}
request={undefined} // 取缔原request,基于useRequest自行处理接口调用
/>
);
}
export default Table;