1.25.1 • Published 9 months ago

search-page v1.25.1

Weekly downloads
58
License
MIT
Repository
github
Last release
9 months ago

search-page

搜索类页面的封装实现, 使用 react

NPM

Install

yarn add search-page

Sreenshot

[example/screenshot.png]

Features

  • 自动记住页面状态,刷新或 history.back(),不会丢失页面状态
  • 数据请求自动节流,阈值 500ms
  • 自动显示 loading 状态, 为了避免闪烁默认 delay 500ms
  • 支持高级搜索,展开收起,收起时重置高级搜索部分的条件为默认值(filtersDefault)
  • 根据配置自动生成 form (目前只支持 input),非 input 组件或自定义组件使用 FormWrapper
  • 支持用户自定义筛选条件
  • 支持手动触发搜索
  • 支持响应式布局(default: { lg: 6, md: 8, sm: 12, xs: 24 })
  • 支持同一页面显示多个实例, 请传递不同的 storeKey
  • 如果不想"记住"状态, 请传递 noStore = true
  • 支持用户侧表头自定义宽度(不支持百分比设置,react-resizable 的属性缺陷,可以持续关注)
  • 加入聚焦自动刷新,页面数据能在页签聚焦时自动刷新

Usage

一般性场景(简单使用)

const getDataApi: GetDataApi = async (filters, pagination) => { await new Promise(resolve => setTimeout(resolve, 1000)); const result = await Promise.resolve({ data: { filters, pagination }, total: 100 }); return result; };

const SearchPage = createSearchPage({ filtersDefault: { orgName: 'gmsoft' }, pageSize: 40, noPagination: false, getDataApi, FiltersForm, });

const Demo = () => { const searchPageRef = useRef({ forceUpdate: () => undefined }); const forceUpdate = useCallback(() => { searchPageRef.current.forceUpdate(); }, []); return ( <div style={{ padding: 16 }}> <SearchPage ref={searchPageRef}>{Content}</SearchPage> <Button onClick={forceUpdate}>强制刷新</Button> </div> ); };

export default Demo;

const Wrap = styled.div` padding: 16px; border: 2px solid purple; background-color: #8000802e; color: purple; `;

const Content = ({ data, forceUpdate, loading, filters }: ContentProps) => ( <Wrap> data: {JSON.stringify(data)} <br /> filters: {JSON.stringify(filters)} <a style={{ float: 'right' }} onClick={forceUpdate}> 强制刷新 </a> </Wrap> ); export default Content;

const fields: Fields = { orgName: { type: 'input', label: '单位名称' }, orgCode1: { type: 'input', label: '组织机构代码 1' }, orgCode2: { type: 'input', label: '组织机构代码 2' }, orgCode3: { type: 'input', label: '组织机构代码 3' }, orgCode4: { type: 'input', label: '组织机构代码 4' }, };

export default buildFiltersForm(fields, { // 可选,是否需要重置操作 needReset: true, // 精简模式配置 simpleMode: { enable: true, count: 2, // count 优先级高于 rows // row: 1 }, });


FiltersForm.tsx (使用 FormWrapper)

import React from 'react';
import { Form, Input, Select, Col } from 'antd';
import { FormWrapper, FiltersFormType } from 'search-page';
import { withRouter, RouteComponentProps } from 'react-router-dom';

const { Option } = Select;
// 包装容器,自定义栅格的时候使用
const { FormItem } = FormWrapper;

const FiltersForm: FiltersFormType<RouteComponentProps<any>> = props => {
  const {
    form: { getFieldDecorator },
  } = props;

  return (
    <FormWrapper
      {...props}
      simpleMode={{ rows: 1 }}
      resetRetainFiltersDefaultKeys={[]}
    >
      {/* 需要自定义栅格时请使用包装容器 */}
      <FormItem span={8} label="orgName">
        {getFieldDecorator('orgName')(<Input placeholder="Please input your name" />)}
      </FormItem>
      {/* 可设置为响应式布局 */}
      <FormItem colProps={{ lg: 6, md: 8, sm: 12, xs: 24 }} label="name1">
        {getFieldDecorator('name1')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </FormItem>
      {/* 与Antd原有FormItem可以混用,原Form.Item占据默认栅格大小:8 */}
      <Form.Item label="name2">
        {getFieldDecorator('name2')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </Form.Item>
      <Form.Item label="name3">
        {getFieldDecorator('name3')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </Form.Item>
    </FormWrapper>
  );
};

export default withRouter(FiltersForm);

HandwrittenFormDemo.tsx (完全自己手写)

import React, { useCallback } from 'react';
import Form, { FormComponentProps } from 'antd/lib/form';
import { Row, Col, Input } from 'antd';

const FiltersForm = ({ form }: FormComponentProps) => {
  const { resetFields, getFieldDecorator } = form;

  const reset = useCallback(() => {
    resetFields();
  }, [resetFields]);

  return (
    <Form layout="vertical">
      <Row gutter={24}>
        <Col span={8}>
          <Form.Item label="单位名称">{getFieldDecorator('orgName')(<Input />)}</Form.Item>
        </Col>
        <Col span={16} style={{ textAlign: 'right' }}>
          <Form.Item label="&nbsp;">
            <a className="action" onClick={reset} role="button">
              重置筛选条件
            </a>
          </Form.Item>
        </Col>
      </Row>
    </Form>
  );
};

export default FiltersForm;

配置用户侧自定义表头列宽度(Content.tsx)

注意事项:

  1. Table 列配置只能使用 Confs 数组配置模式,不能使用 Jsx 模式
  2. 列宽只能指定具体像素,不能使用百分比,插件实现问题
  3. 列宽数据存储行为与 Filter 条件一致
  4. dispatch、tableWidthConfs、storeKey 均为 SearchPage 内部属性,使用时可以直接透传 props 进行简写
  5. 最右侧配置列的 width 请留空,不要写
import React, { useEffect, useRef, useMemo, useCallback, useState } from 'react';
import styled from 'styled-components';
import { ContentProps, ResizeableTitle, getColumnConfs } from 'search-page';
import { Table, Button } from 'antd';

const Wrap = styled.div`
  padding: 16px;
  border: 2px solid purple;
`;

const components = { header: { cell: ResizeableTitle } };

export default ({ data, forceUpdate, dispatch, tableWidthConfs, storeKey }: ContentProps) => {
  const tableRef = useRef<any>();
  const [columnConfs, setColumnConfs] = useState([
    {
      title: 'id',
      key: 'id',
      dataIndex: 'id',
      width: 100,
    },
    {
      // 所有配置列中,请保持有一个配置列的width不配置,否则会导致拖动自适应出现问题
      title: 'operate',
      key: 'operate',
      dataIndex: 'operate',
    },
  ]);

  const renderColumnsConf = useMemo(
    () =>
      getColumnConfs({
        columnConfs,
        setConfs: setColumnConfs,
        dispatch,
        tableWidthConfs,
        storeKey,
      }),
    [columnConfs, dispatch, storeKey, tableWidthConfs]
  );

  return (
    <Wrap>
      <Table
        ref={tableRef}
        rowKey="id"
        dataSource={data.data}
        columns={renderColumnsConf}
        pagination={false}
        components={components}
        size="small"
      />
      {JSON.stringify(data)}
      <Button style={{ float: 'right' }} type="link" onClick={forceUpdate}>
        强制刷新
      </Button>
    </Wrap>
  );
};

关于聚焦刷新

请在 createSearchPage 中指定 autoRefresh 即可,配置如下:

export interface RefreshOpt {
  /** 只要没有显示传递false,都默认true */
  enable?: boolean;
  /** 切换刷新的间隔时间,间隔时间内切换页签不会进行刷新 */
  interval?: number;
}

典型场景

// 页签聚焦自动刷新列表数据(此功能默认启用,默认自动请求间隔时间3000,间隔时间内重复聚焦不会再次触发刷新)
autoRefresh: { interval: 5000 },
// 关闭聚焦自动刷新(如果需要关闭则显示配置为false即可)
autoRefresh: { enable: false },

支持手动触发模式

请在 createSearchPage 中指定 [searchMode]

如果同一个页面有多个 SearchPage 实例

请在 createSearchPage 中指定 [storeKey]

支持指定存储数据使用的 history 对象

请在 createSearchPage 中指定 [storeHistory]

forceUpdate 支持传递参数 forceUpdateArgs

export interface PaginationI {
  current: number;
  pageSize: number;
}

export interface Filters {
  [key: string]: any;
}

interface ForceUpdateArgs {
  filters?: Filters;
  pagination?: Partial<PaginationI>;
}

如果需要定制化筛选条件, 请设置 FromWraper props -> defaultCustomFiltersConf

 /**
   * 定制化筛选条件
   */
  defaultCustomFiltersConf?: {
    /**
     * 定制配置存储在 localStorage 中 key
     */
    storageKey: string;
    /**
     * 禁止定制的项
     */
    notAllowCustomKeys?: string[];
    /**
     * 筛选配置面板label定制
     */
    labels?: { [key: string]: string };
    /**
     * Popover.props.getPopupContainer
     */
    getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
    /**
     * Popover.props.overlayStyle
     * @default { maxWidth: 450 }
     */
    popoverOverlayStyle?: CSSProperties;
  };

支持响应式布局, 请设置 FromWraper props -> theme, 或使用 FromWraper.FormItem props -> colProps

export interface ThemeI {
  rowProps?: RowProps;
  colProps?: ColProps;
}

详见 https://github.com/gmsoft-happyCoding/search-page/tree/master/example

如果你使用了 FromWraper.FormItem, 自定义了每个元素的栅格所占宽度, 请不要使用 simpleMode.rows(直接使用 simpleMode.count) 设置默认显示的元素数量, 因为这可能会导致默认显示的元素数量的计算错误


License

MIT © angular-moon

1.25.0

10 months ago

1.25.1

9 months ago

1.24.0

2 years ago

1.23.0

2 years ago

1.22.2

2 years ago

1.22.1

2 years ago

1.22.0

3 years ago

1.21.0

3 years ago

1.20.0

3 years ago

1.19.0

3 years ago

1.18.0

3 years ago

1.17.3

3 years ago

1.17.2

3 years ago

1.17.1

3 years ago

1.17.0

3 years ago

1.16.3

4 years ago

1.16.2

4 years ago

1.16.1

4 years ago

1.16.0

4 years ago

1.15.0

4 years ago

1.14.0

4 years ago

1.13.0

4 years ago

1.12.0

4 years ago

1.11.2

4 years ago

1.11.1

4 years ago

1.11.0

4 years ago

1.10.0

4 years ago

1.9.0

4 years ago

1.8.0

4 years ago

1.7.3

4 years ago

1.7.2

4 years ago

1.7.1

4 years ago

1.7.0

4 years ago

1.6.1

5 years ago

1.6.0

5 years ago

1.5.2

5 years ago

1.5.1

5 years ago

1.5.0

5 years ago

1.4.1

5 years ago

1.4.0

5 years ago

1.3.0

5 years ago

1.2.1

5 years ago

1.2.0

5 years ago

1.1.1

5 years ago

1.1.0

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago

0.4.5

5 years ago

0.4.4

5 years ago

0.4.3

5 years ago

0.4.2

5 years ago

0.4.1

5 years ago

0.4.0

5 years ago

0.3.3

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.0

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago