基于ProComponents的pro-table思路,对antd-table进行二次封装(解决项目中不能使用ProComponents的问题)

1,070 阅读2分钟

目录结构

  • UseTable
    • index.jsx
    • SearchFrom.jsx
// UseTable
import React, { useEffect, useState } from 'react';
import { Button, Card, Table } from 'antd';
import SearchForm from './SearchForm';

/**
 * @params {()=>Promise.resolve/Promise.reject} request 异步请求
 * @params {TableTypes} tableProps table属性
 * @params {clickEvent} onClickNewBtn 新增按钮事件
 * @params {boolean} showNewBtn 展示新增按钮
 * @params {boolean} disableNewBtn 禁用新增按钮
 * @params {false | SearchTypes} search 禁用新增按钮
 */
const UseTable = (props) => {
  const {
    request,
    tableProps,
    onClickNewBtn,
    showNewBtn,
    disableNewBtn,
    search,
  } = props;
  const [loading, setLoading] = useState(true);
  const [current, setCurrent] = useState(1);
  const [size, setSize] = useState(10);
  const [total, setTotal] = useState(0);

  const getData = (values) => {
    request(current, size, values)
      .then((res) => {
        setTotal(res?.total);
        setLoading(false);
      })
      .catch(() => {
        setLoading(false);
      });
  };

  // 分页默认逻辑,可修改
  const paginationProps = {
    showQuickJumper: true,
    showSizeChanger: true,
    total,
    onShowSizeChange: (page, pageSize) => {
      setCurrent(page);
      setSize(pageSize);
    },
    showTotal: (totals) => `共${totals}条记录`,
    onChange: (page, pageSize) => {
      setCurrent(page);
      setSize(pageSize);
    },
  };

  useEffect(() => {
    getData();
  }, [current, size]);

  return (
    <Card>
      {search && <SearchForm getData={getData} columns={tableProps?.columns} />}
      {showNewBtn && (
        <Button
          type="primary"
          onClick={showNewBtn && onClickNewBtn}
          disabled={disableNewBtn}
        >
          新增
        </Button>
      )}
      <Table
        rowKey={(record) => record.id}
        loading={loading}
        {/* 通过新申明将默认项覆盖 */}
        pagination={{ ...paginationProps, ...tableProps?.paginationProps }}
        style={{ marginTop: 20 }}
        {/* 放最后方便对上面的props覆盖 */}
        {...tableProps}
      />
    </Card>
  );
};

// 添加默认值
UseTable.defaultProps = {
  showNewBtn: true,
  disableNewBtn: false,
  search: true,
};

export default UseTable;
// SearchForm
import React, { useState } from 'react';
import { Button, Col, Form, Input, Row, Icon } from 'antd';

const FormItem = Form.Item;

const SearchForm = (props) => {
  const [paramExpand, setParamExpand] = useState();
  const { form, getData, columns } = props;
  const { getFieldDecorator } = form;
  const formItemLayout = {
    labelCol: { span: 7 },
    wrapperCol: { span: 15 },
  };

  const setExpand = (expand) => {
    setParamExpand(expand);
  };

  const handleSearch = (e) => {
    if (e) e.preventDefault();
    form.validateFields({ force: true }, (err, values) => {
      getData(values);
    });
  };

  // 查询重置
  const handleFormReset = () => {
    form.resetFields();
    handleSearch();
  };

  // 渲染search表单项
  const renderFormItem = () => {
    return (
      <>
        {columns?.map((item) => {
          const { hideSearch = true } = item;
          if (item?.renderSearchItem) {
            return (
              <Col md={8} sm={24} key={item?.dataIndex}>
                <FormItem label={item?.searchTitle || item?.title}>
                  {getFieldDecorator(item?.searchIndex || item?.dataIndex)(
                    item?.renderSearchItem(),
                  )}
                </FormItem>
              </Col>
            );
          }
          return (
            hideSearch && (
              <Col md={8} sm={24} key={item?.dataIndex}>
                <FormItem label={item?.searchTitle || item?.title}>
                  {getFieldDecorator(item?.searchIndex || item?.dataIndex)(
                    <Input placeholder="请输入" />,
                  )}
                </FormItem>
              </Col>
            )
          );
        })}
      </>
    );
  };

  return (
    <Form {...formItemLayout} onSubmit={handleSearch}>
      <Row gutter={24}>
        {/* 展开前默认取两项,展开后显示全部。通过children进行dom渲染 */}
        {paramExpand ? (
          renderFormItem()?.props?.children.map((item) => item)
        ) : (
          <>
            {renderFormItem()
              ?.props?.children?.slice(0, 2)
              ?.map((item) => item)}
            <Col
              className={styles.submitButtons}
              md={8}
              sm={24}
              style={{ lineHeight: '40px' }}
            >
              <span>
                <Button type="primary" htmlType="submit">
                  查询
                </Button>
                <Button
                  style={{ marginLeft: 8, marginRight: 8 }}
                  onClick={handleFormReset}
                >
                  重置
                </Button>
                <a
                  style={{ fontSize: 12 }}
                  onClick={() => {
                    setExpand(!paramExpand);
                  }}
                >
                  {paramExpand ? (
                    <Icon type="up" style={{ marginRight: '4px' }} />
                  ) : (
                    <Icon type="down" style={{ marginRight: '4px' }} />
                  )}
                  {paramExpand ? '收起' : '展开'}
                </a>
              </span>
            </Col>
          </>
        )}
      </Row>
      <Row gutter={{ md: 8, lg: 24, xl: 48 }}>
        {paramExpand && (
          <Col
            className={styles.submitButtons}
            style={{ float: 'right' }}
            md={6}
            sm={24}
          >
            <span>
              <Button type="primary" htmlType="submit">
                查询
              </Button>
              <Button
                style={{ marginLeft: 8, marginRight: 8 }}
                onClick={handleFormReset}
              >
                重置
              </Button>
              <a
                style={{ fontSize: 12 }}
                onClick={() => {
                  setExpand(!paramExpand);
                }}
              >
                {paramExpand ? (
                  <Icon type="up" style={{ marginRight: '4px' }} />
                ) : (
                  <Icon type="down" style={{ marginRight: '4px' }} />
                )}
                {paramExpand ? '收起' : '展开'}
              </a>
            </span>
          </Col>
        )}
      </Row>
    </Form>
  );
};

export default Form.create()(SearchForm);

组件的使用

// demo
import React, { useState } from 'react';
import { Select } from 'antd';
import UseTable from '@/components/UseTable';

const { Option } = Select;

const Demo = (props) => {
  const [dataSource, setDataSource] = useState([]);

  const columns = [
    {
      title: 'id',
      dataIndex: 'id',
      // hideSearch: false,
      searchIndex: '自定义字段',
      searchTitle: '自定义头',
      renderSearchItem: () => {
        // 自定义搜索fromItem
        return (
          <Select>
            <Option value="1">s</Option>
            <Option value="2">2</Option>
          </Select>
        );
      },
    },
    {
      title: '用户id',
      dataIndex: 'userId',
    },
    {
      title: '公司名称',
      dataIndex: 'tenantChineseName',
      hideSearch: false,
    },
    {
      title: '用户名',
      dataIndex: 'userName',
    },
  ];

  return (
    <UseTable
      request={async (current, size, values) => {
        const res = await api({
          pageSize: size,
          pageNum: current,
          ...values,
        });
        if (res?.recode === '000000') {
          setDataSource(res?.data?.records);
          return Promise.resolve({ total: res?.data?.total });
        }
        return Promise.reject();
      }}
      tableProps={{
        columns,
        bordered: true,
        dataSource,
        paginationProps: { pageSizeOptions: ['2', '10'] },
      }}
      onClickNewBtn={() => {
        props.history.push({
          pathname: '/test',
        });
      }}
    />
  );
};

export default Demo;

个人博客-记录各种前端问题