# ListView 分页列表

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/list-view/freepass)
- 平台：PC
- 维护者：王斌
- 设计稿：http://pd.e-cology.com.cn/pd/E10/interface/e10xiaoguotu/PC/zms/zujian-list/
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[ListView]

## 代码演示

### 基础用法

列表数据, 列表总数, 操作菜单权限 同一接口返回下同步操作。 默认直接渲染数据、总数、操作菜单

```jsx
import React, { Component } from 'react'
import { ListView, constants } from '@weapp/ui'
import ListViewDemoStore from './store'
import mock2 from './mock'
import { RequestOptionConfig } from '@weapp/utils'

const prefixCls = `${constants.uiPcClsPrefix}-demo-listView`

const listViewDemoStore = new ListViewDemoStore()
const listViewStore = listViewDemoStore.listView

export default class ListViewDemo extends Component {
  componentDidMount() {
    this.initListView()
  }

  initListView = () => {
    const { setState, getData } = listViewStore

    // 同步：返回ListView 所需全部数据，asyncCounts、asyncOperates 不再需要传入
    const requestConfig: RequestOptionConfig = {
      url: '/getuser',
      method: 'post',
      params: {
        current: 1,
        pageSize: 10,
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }

    // getData(requestConfig)
    // mock模拟数据 实际开发中请使用上面 store.getData 的方式！！
    setTimeout(() => {
      let res = { ...mock2.mockData }
      if (res.status) {
        const { data: _d } = res
        const {
          data,
          columns,
          current,
          pageSize,
          operates,
          displayData,
          operatesPermission = [],
          checkBoxPermission = [],
          total,
          tableType,
        } = _d

        console.log(columns.filter(i => !i.hide))
        setState({
          initColumns: columns,
          data,
          columns,
          operates,
          displayData,
          operatesPermission,
          checkBoxPermission,
          total,
          pageSize,
          current,
          tableType
        })
      }
    }, 50)
  }

  render() {
    return (
      <div className={prefixCls}>
        <ListView
         
          store={listViewStore}
          rememberResizeColumns
          // autoScrollInResize={false}
        />
      </div>
    )
  }
}
```

### 异步列表数据

列表数据, 列表总数, 操作菜单权限 不同接口下返回，数据返回后渲染总数、操作菜单

```jsx
import React, { Component } from 'react'
import { ListView, constants, Button, ITableCellPos, OperatesType, ITableColumn } from '@weapp/ui'
import { RequestOptionConfig } from '@weapp/utils'
import ListViewDemoStore from './store'
import mock2 from './mock'

const prefixCls = `${constants.uiPcClsPrefix}-demo-listView`

const listViewDemoStore = new ListViewDemoStore()
const listViewStore = listViewDemoStore.listView

export default class ListViewDemo extends Component {
  private listViewRef: any

  state = {
    style: { marginLeft: '20px' },
  }
  componentDidMount() {
    this.initListView()
  }

  initListView = () => {
    const { setState, getData } = listViewStore

    // 列表数据主接口
    // 同步：返回ListView 所需全部数据，asyncCounts、asyncOperates 不再需要传入
    // 异步：返回 data, columns, current, pageSize, displayData
    const requestConfig: RequestOptionConfig = {
      url: '/getuser',
      method: 'post',
      params: {
        current: 1,
        pageSize: 10,
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }
    //
    // 列表 count接口
    // 异步：返回total
    const asyncCounts: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getMinePageCount',
      method: 'get',
      params: {
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }
    // 列表 operates接口  操作菜单、check权限
    // 异步：返回operates, operatesPermission, checkBoxPermission
    const asyncOperates: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getTodoPageChecks',
      method: 'post',
    }
    // 同步下只需传第一个参数 异步下需要传三个参数
    // getData(requestConfig, asyncCounts, asyncOperates)

    // mock模拟数据 实际开发中请使用上面 store.getData 的方式！！
    setTimeout(() => {
      let res = { ...mock2.mockData }
      if (res.status) {
        const { data: _d } = res
        const {
          data,
          columns,
          current,
          pageSize,
          operates,
          displayData,
          operatesPermission = [],
          checkBoxPermission = [],
          total,
        } = _d
        setState({
          initColumns: columns,
          data,
          pageSize,
          current,
          columns,
          displayData,
        })
      }
    }, 50)
  }

  asyncCount = () => {
    const { setState } = listViewStore
    let res = { ...mock2.mockData }
    const { data: _d } = res
    const { total } = _d
    setState({
      total,
    })
  }

  asyncOperates = () => {
    const { setState } = listViewStore
    let res = { ...mock2.mockData }
    const { data: _d } = res
    const { operates, operatesPermission = [], checkBoxPermission = [] } = _d
    setState({
      operates,
      operatesPermission,
      checkBoxPermission,
    })
  }

  onClick = () => {
    console.log('onClick', listViewStore)
  }

  onOperateClick = (item: OperatesType, data: object, pos: ITableCellPos) => {
    console.log(item, data, pos)
  }

  onSelect = (selectedRowKeys: string[], selectedRows: any[], currentRow: any | any[]) => {
    console.log(selectedRowKeys, selectedRows, currentRow)
  }

  getRef = (instance: any) => {
    this.listViewRef = instance
  }

  onClickRef = () => {
    this.listViewRef?.showColumnSet()
  }

  onSortClickRef = () => {
    this.listViewRef?.showSortSet()
  }

  onSort = (columns: ITableColumn[], sortColumn: ITableColumn) => {
    const { setState, displayData } = listViewStore
    console.log('onSort', columns, sortColumn)

    // 排序逻辑处理 mock
    const _d = JSON.parse(JSON.stringify(displayData))

    _d.sort((a: any, b: any) => {
      if (sortColumn.orderType === 'asc') {
        return Number(b.id) - Number(a.id)
      } else {
        return Number(a.id) - Number(b.id)
      }
    })

    setState({ columns, displayData: _d })
  }

  render() {
    const { style } = this.state
    return (
      <div className={prefixCls}>
        <h4>操作总数接口异步返回</h4>
        <div style={{ marginBottom: '20px' }}>
          <Button onClick={this.asyncCount} style={style}>
            模拟异步获取数据总数(显示总数)
          </Button>
          <Button onClick={this.asyncOperates} style={style}>
            模拟异步获取菜单权限(显示操作列)
          </Button>
        </div>
        <ListView
         
          ref={this.getRef}
          store={listViewStore}
          onOperateClick={this.onOperateClick}
          onSelect={this.onSelect}
          onSort={this.onSort}
          rememberResizeColumns={true}
        />
      </div>
    )
  }
}
```

### 自定义列

使用组件实例showColumnSet方法,设置页面自定义显示列操作

```jsx
import React, { Component } from 'react';
import { ListView, constants, Button, ITableCellPos, OperatesType, ITableColumn } from '@weapp/ui';
import { RequestOptionConfig } from '@weapp/utils';
import ListViewDemoStore from './store'
import mock2  from './mock'

const prefixCls = `${constants.uiPcClsPrefix}-demo-listView`;

const listViewDemoStore = new ListViewDemoStore();
const listViewStore = listViewDemoStore.listView

export default class ListViewDemo extends Component {
  private listViewRef: any;
  constructor(props: any) {
    super(props);

  }

  componentDidMount() {
    this.initListView()
  }

  initListView = () => {
    const { setState, getData } = listViewStore

    // 列表数据主接口
    // 同步：返回ListView 所需全部数据，asyncCounts、asyncOperates 不再需要传入
    // 异步：返回 data, columns, current, pageSize, displayData
    const requestConfig: RequestOptionConfig = {
      url: '/getuser',
      method: 'post',
      params: {
        current: 1,
        pageSize: 10,
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z'
      }
    }
    //
    // 列表 count接口
    // 异步：返回total
    const asyncCounts: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getMinePageCount',
      method: 'get',
      params: {
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z'
      }
    }
    // 列表 operates接口  操作菜单、check权限
    // 异步：返回operates, operatesPermission, checkBoxPermission
    const asyncOperates: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getTodoPageChecks',
      method: 'post',
    }
    // 同步下只需传第一个参数 异步下需要传三个参数
    // getData(requestConfig, asyncCounts, asyncOperates)
    // getData(requestConfig)

    // mock模拟数据 实际开发中请使用上面 store.getData 的方式！！
    setTimeout(() => {
      let res = { ...mock2.mockData }

      if (res.status) {
        const { data: _d } = res;
        const { data, columns, current, pageSize, operates, displayData, operatesPermission = [], checkBoxPermission = [], total } = _d;

        setState({
          initColumns: columns,
          data, columns, operates, displayData, operatesPermission, checkBoxPermission, total, pageSize, current
        })
      }
    }, 50)
  }

  onClick = () => {
    console.log('onClick', listViewStore)
  }

  onOperateClick = (item: OperatesType, data: object, pos: ITableCellPos) => {
    console.log(item, data, pos)
  }

  onSelect = (selectedRowKeys: string[], selectedRows: any[], currentRow: any | any[]) => {
    console.log(selectedRowKeys, selectedRows, currentRow)
  }

  getRef = (instance: any) => {
    this.listViewRef = instance
  }

  onClickRef = () => {
    this.listViewRef?.showColumnSet()
  }

  onSortClickRef = () => {
    this.listViewRef?.showSortSet()
  }

  onSort = (columns: ITableColumn[], sortColumn: ITableColumn) => {
    const { setState, displayData } = listViewStore
    console.log('onSort', columns, sortColumn)

    // 排序逻辑处理 mock
    const _d = JSON.parse(JSON.stringify(displayData))

    _d.sort((a: any, b: any) => {
      if (sortColumn.orderType === 'asc') {
        return Number(b.id) - Number(a.id)
      } else {
        return Number(a.id) - Number(b.id)
      }
    })

    setState({ columns, displayData: _d })
  }

  render() {
    console.log(listViewStore)
    return (
      <div className={prefixCls}>
        <div style={{ marginBottom: '20px' }}>
          <Button
            onClick={this.onClickRef}
            style={{ marginLeft: '20px' }}>ref操作 使用显示列定制功能</Button>
        </div>
        <ListView
         
          ref={this.getRef}
          store={listViewStore}
          onOperateClick={this.onOperateClick}
          onSelect={this.onSelect}
          onSort={this.onSort}
          rememberResizeColumns={true}
          disabledPermissionColumns={['requestnamehtml', 'createdatetime', 'currentnode']}
          allowColumnTitleEmpty={true}
        />
      </div>
    );
  }
}
```

### 排序设置

使用组件实例showSortSet方法,设置默认排序设置

```jsx
import React, { Component } from 'react'
import { ListView, constants, Button, ITableCellPos, OperatesType, ITableColumn } from '@weapp/ui'
import { RequestOptionConfig } from '@weapp/utils'
import ListViewDemoStore from './store'
import mock2 from './mock'

const prefixCls = `${constants.uiPcClsPrefix}-demo-listView`

const listViewDemoStore = new ListViewDemoStore()
const listViewStore = listViewDemoStore.listView

export default class ListViewDemo extends Component {
  private listViewRef: any
  componentDidMount() {
    this.initListView()
  }

  initListView = () => {
    const { setState, getData } = listViewStore

    // 列表数据主接口
    // 同步：返回ListView 所需全部数据，asyncCounts、asyncOperates 不再需要传入
    // 异步：返回 data, columns, current, pageSize, displayData
    const requestConfig: RequestOptionConfig = {
      url: '/getuser',
      method: 'post',
      params: {
        current: 1,
        pageSize: 10,
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }
    //
    // 列表 count接口
    // 异步：返回total
    const asyncCounts: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getMinePageCount',
      method: 'get',
      params: {
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }
    // 列表 operates接口  操作菜单、check权限
    // 异步：返回operates, operatesPermission, checkBoxPermission
    const asyncOperates: RequestOptionConfig = {
      url: '/api/fs/workflow/core/list/getTodoPageChecks',
      method: 'post',
    }
    // 同步下只需传第一个参数 异步下需要传三个参数
    // getData(requestConfig, asyncCounts, asyncOperates)
    // getData(requestConfig)

    // mock模拟数据 实际开发中请使用上面 store.getData 的方式！！
    setTimeout(() => {
      let res = { ...mock2.mockData }

      if (res.status) {
        const { data: _d } = res
        const {
          data,
          columns,
          current,
          pageSize,
          operates,
          displayData,
          operatesPermission = [],
          checkBoxPermission = [],
          total,
        } = _d

        setState({
          initColumns: columns,
          data,
          columns,
          operates,
          displayData,
          operatesPermission,
          checkBoxPermission,
          total,
          pageSize,
          current,
        })
      }
    }, 50)
  }

  onClick = () => {
    console.log('onClick', listViewStore)
  }

  onOperateClick = (item: OperatesType, data: object, pos: ITableCellPos) => {
    console.log(item, data, pos)
  }

  onSelect = (selectedRowKeys: string[], selectedRows: any[], currentRow: any | any[]) => {
    console.log(selectedRowKeys, selectedRows, currentRow)
  }

  getRef = (instance: any) => {
    this.listViewRef = instance
  }

  onClickRef = () => {
    this.listViewRef?.showColumnSet()
  }

  onSortClickRef = () => {
    this.listViewRef?.showSortSet()
  }

  onSort = (columns: ITableColumn[], sortColumn: ITableColumn) => {
    const { setState, displayData } = listViewStore
    console.log('onSort', columns, sortColumn)

    // 排序逻辑处理 mock
    const _d = JSON.parse(JSON.stringify(displayData))

    _d.sort((a: any, b: any) => {
      if (sortColumn.orderType === 'asc') {
        return Number(b.id) - Number(a.id)
      } else {
        return Number(a.id) - Number(b.id)
      }
    })

    setState({ columns, displayData: _d })
  }

  render() {
    return (
      <div className={prefixCls}>
        <div style={{ marginBottom: '20px' }}>
          <Button onClick={this.onSortClickRef} style={{ marginLeft: '20px' }}>
            ref操作 使用默认排序设置功能
          </Button>
        </div>
        <ListView
         
          ref={this.getRef}
          store={listViewStore}
          onOperateClick={this.onOperateClick}
          onSelect={this.onSelect}
          onSort={this.onSort}
          rememberResizeColumns={true}
        />
      </div>
    )
  }
}
```

### 其它设置

customRenderIcon

```jsx
import React, { Component } from 'react'
import { ListView, constants, Icon, Button } from '@weapp/ui'
import ListViewDemoStore from './store'
import mock2 from './mock'
import { RequestOptionConfig } from '@weapp/utils'

const prefixCls = `${constants.uiPcClsPrefix}-demo-listView`

const listViewDemoStore = new ListViewDemoStore()
const listViewStore = listViewDemoStore.listView

export default class ListViewDemo extends Component {
  private listViewRef: any
  componentDidMount() {
    this.initListView()
  }

  initListView = () => {
    const { setState, getData } = listViewStore

    // 同步：返回ListView 所需全部数据，asyncCounts、asyncOperates 不再需要传入
    const requestConfig: RequestOptionConfig = {
      url: '/getuser',
      method: 'post',
      params: {
        current: 1,
        pageSize: 10,
        userid: '5111597426042878265',
        tenantkey: 'TSHY6DTU0Z',
      },
    }

    // getData(requestConfig)
    // mock模拟数据 实际开发中请使用上面 store.getData 的方式！！
    setTimeout(() => {
      let res = { ...mock2.mockData }
      if (res.status) {
        const { data: _d } = res
        const {
          data,
          columns,
          current,
          pageSize,
          operates,
          displayData,
          operatesPermission = [],
          checkBoxPermission = [],
          total,
        } = _d

        setState({
          initColumns: columns,
          data,
          columns,
          operates,
          displayData,
          operatesPermission,
          checkBoxPermission,
          total,
          pageSize,
          current,
        })
      }
    }, 50)
  }

  customRenderIcon = () => {
    return <Icon name='Icon-Arithmetic-control' />
  }

  getRef = (instance: any) => {
    this.listViewRef = instance
  }

  onClickRef = () => {
    this.listViewRef?.showColumnSet()
  }
  render() {
    return (
      <div className={prefixCls}>
        <div style={{ marginBottom: '20px' }}>
          <Button onClick={this.onClickRef} style={{ marginLeft: '20px' }}>
            自定义显示列定制图标(customRenderIcon)
          </Button>
        </div>
        <ListView
         
          store={listViewStore}
          ref={this.getRef}
          customRenderIcon={this.customRenderIcon}
        />
      </div>
    )
  }
}
```

## 说明

- ListView 是基于 ui Table 组件基础上开发，Table 支持的 API 基本上 ListView 都会支持。目前 columns、selection、pageInfo 是完全由接口控制传入，后续会新增 API 支持外部复写。
- listview 自定义列的“保存”和“恢复默认显示列”有防抖机制，delay 为 500ms。保存时的数据会和打开弹窗时候的初始数据做对比，如果没有变化则不发起请求
- needAllRes 可以通过 props 进行传递，也可以通过 getData 的返回参数进行获取，props 优先级大于返回参数

## 后端接口公共组件 API：点击此处

## API

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| store | 列表实例 | ListViewStore | 是 | - |
| onOperateClick | 操作菜单点击事件 | (item: OperatesType, data: object, pos: ITableCellPos) => void | 否 | - |
| onSelect | check 回调事件 | (selectedRowKeys: string[], selectedRows: any[], currentRow: any \| any[], type?: `normal` \| `batchSelectAll` \| `batchRemoveAll`) => any | 否 | - |
| getColumns | 自定义列各列属性 | (columns: ITableColumn[]) => ITableColumn[] | 否 |  |
| getSelection | 自定义选择列属性 | (selectionProps: ITableSelection) => ITableSelection | 否 | - |
| module | 模块类型(显示列定制功能 使用) | string | 否 | - |
| paginationType | 分页类型('part' / 'more' / 'scroll') | string | 否 | `part` |
| pageInfo | 自定义配置分页信息 | PaginationProps（详情见 组件 Pagination API 说明） | 否 | - |
| disabledByPermissionEmpty | 异步下 权限数据为空数组时 禁用数据 check 权限 | boolean | 否 | false |
| useKeyInRequest | 异步权限 operates 接口是否传入主键参数 非默认 data | boolean | 否 | false |
| operateBodyRenderProps | 自定义配置操作列参数 | (data: Data,pos: ITableCellPos,name: string \| undefined,renderIndex?: number) => object | 否 | - |
| needAllRes | 是否在 getData 内返回 response 所有信息 | boolean | 否 | false |
| pageSizeOptions | 分页选项 | number[] | 否 | 10, 20, 50, 100 |
| rememberResizeColumns | 是否开启列宽拖拽记忆 | boolean | 否 | - |
| customRenderIcon | 自定义显示列定制图标 | () => ReactNode | 否 | - |
| onHandleResizeEnd | 外部复写拖拽 | (columns: ITableColumn[], dragIndex: number, needSetScroll: boolean, widthAccumulate: number, resizeColGroupColumns: ITableColumn[]) => void | 否 | - |
### ListViewStore 参数、方法说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| getData | 请求列表数据 | (options: RequestOptionConfig) => void |  |  |
| setState | 更新设置列表内数据（外部更新 store 内数据请使用此方法，不建议直接赋值操作） | (params?: any) => void |  |  |
| showColumnSet | 外部调用显示列定制弹框（通过 ref 调用） |  |  |  |
