美文网首页
基于 Antd Protable 及 ahooks 的表格组件业

基于 Antd Protable 及 ahooks 的表格组件业

作者: 布可booker | 来源:发表于2020-10-21 12:04 被阅读0次

    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>

    1. 取消 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;
    };
    
    
    1. 覆写了 Column 的一些默认属性。

      • 默认 hideInSearch 为 false,覆写为 true
    const columns = useMemo(() => {
      return (_columns ?? []).map(i => {
        return {
          hideInSearch: true,
          ...i,
        };
      });
    }, [_columns, tableData.data]);
    
    1. 自行实现的翻页调用接口

      • 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,
        },
      );
    
    
    1. 覆写了 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;
    
    

    相关文章

      网友评论

          本文标题:基于 Antd Protable 及 ahooks 的表格组件业

          本文链接:https://www.haomeiwen.com/subject/opismktx.html