npm package: @geom_team/ngx-page-table
Description: 基于ng-zorro-antd table组件开发的分页表格组件，内置排序、筛选、分页、编辑单元格等功能，支持配置式生成表格列，提供page-table-column 等组件，用以支持自定义配置相关功能。简化在ng-zorro-antd table组件在angular项目中的使用
Author: geominfo
Latest version: 0.0.3

# NgxPageTable
基于ng-zorro-antd table组件开发的分页表格组件，内置排序、筛选、分页、编辑单元格等功能，支持配置式生成表格列，提供page-table-column 等组件，用以支持自定义配置相关功能。简化在ng-zorro-antd table组件在angular项目中的使用

## 安装
```bash
#  use npm
npm install @geom_team/ngx-page-table

# use yarn
yarn add @geom_team/ngx-page-table

```

```ts
import { NgxPageTableModule } from '@geom_team/ngx-page-table';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
  declarations: [
    AppComponent  
  ],
  imports: [
    BrowserModule, 
    NgxPageTableModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

```

## 基本用法
```html
<ngx-page-table [tableData]="tableData" [tableColumns]="tableColumns" [paginationConfig]="paginationConfig"
  [tableConfig]="tableConfig"
  [virtualConfig]="virtualConfig"
  (pageSizeChange)="onPageSizeChange($event)"
  (pageIndexChange)="onPageIndexChange($event)"
  (currentPageDataChange)="onPageDataChange($event)"
  (queryParamsChange)="onQueryParamsChange($event)"
  (sortChange)="onSortChange($event)"
  (filterChange)="onFilterChange($event)"
  (selectionChange)="onSelectionChange($event)"
  (editComplete)="onEditComplete($event)"
  (selectAllChange)="onSelectAllChange($event)"

  >
</ngx-page-table>
```
```ts
export class TableDemoComponent {

  tableData: Array<any> = mockTableData;
  tableColumns: Array<ITableColumn<any>> = mockTableColumns;
  
  paginationConfig: IPagination = {
    pageIndex: 1,
    pageSize: 10,
    total: 0,
    show: true,
    showSizeChanger: true
  }; // 分页配置
  
  tableConfig: ITableConfig = {
    loading: false,
    title: '',
    noResult: 'noResultTemplate',
    scroll: {x: 1620 +'px', y: '460px'},
    showSelection: true,
    showOperation: true,
    showRowSelection: false,
    size: 'small',
    border: true,
    outerBorder: true
  }; // 表格配置
  virtualConfig = {
    virtualItemSize: 0,
    virtualMaxBufferPx: 100,
    virtualMinBufferPx: 500,
    virtualForTrackBy: VirtualForTrackBy
  }, // 虚拟滚动配置

  constructor(private cdr: ChangeDetectorRef) {

  }

  onPageSizeChange(size: number) {
    console.log('onPageSizeChange size:', size);
  }
  onPageIndexChange(page: number) {
    console.log('onPageIndexChange page:', page);
  }
  onPageDataChange(data: Array<any>) {
    console.log('onPageDataChange data:', data);
  }
  onQueryParameterChange(params: any) {
    console.log('onQueryParameterChange params:', params);
  }
  onSortChange($event) {
    console.log('onSortChange $event:', $event);
  }
  onFilterChange($event) {
    console.log('onFilterChange $event:', $event);
  }

  onSelectionChange($event) {
    console.log('onSelectionChange $event:', $event);
  }

  onEditComplete($event) {
    console.log('onEditComplete $event:', $event);
  
  }
  onSelectAllChange($event) {
    console.log('onSelectAllChange $event:', $event);
  }

}

```

## 自定义组件
### 自定义列
使用 page-table-column 组件自定义列
```html
<ngx-page-table [tableData]="tableData" [tableColumns]="tableColumns" [paginationConfig]="paginationConfig"
  [tableConfig]="tableConfig"
  [virtualConfig]="virtualConfig"
  >
  <page-table-column label="ID" key="key" align="center" [showOverflowTooltip]="true" [width]="65">
    <ng-template let-row>
      <td nzAlign="center">
        <button nz-button class="temporary_storage">
          {{row['key']}}
        </button>
      </td>
    </ng-template>
  </page-table-column>
   <page-table-column label="操作" key="operation" type="operation">
    <ng-template let-listData>
      <td> <a (click)="handleDetails(listData)">详情</a></td>
    </ng-template>
  </page-table-column>
</ngx-page-table>
```
```ts
export class TableDemoComponent {

  tableData: Array<any> = mockTableData;
  tableColumns: Array<ITableColumn<any>> = mockTableColumns;
  
  paginationConfig: IPagination = {
    pageIndex: 1,
    pageSize: 10,
    total: 0,
    show: true,
    showSizeChanger: true
  }; // 分页配置
  
  tableConfig: ITableConfig = {
    loading: false,
    title: '',
    noResult: 'noResultTemplate',
    scroll: {x: 1620 +'px', y: '460px'},
    showSelection: true,
    showOperation: true,
    showRowSelection: false,
    size: 'small',
    border: true,
    outerBorder: true
  }; // 表格配置
  virtualConfig = {
    virtualItemSize: 0,
    virtualMaxBufferPx: 100,
    virtualMinBufferPx: 500,
    virtualForTrackBy: VirtualForTrackBy
  }, // 虚拟滚动配置

  constructor(private cdr: ChangeDetectorRef) {

  }

  handleDetails(data) {
    console.log("handleDetails", data);
  }
}
```
### 自定义title, footer, noResult, total
可通过两种方式定义表格title, footer, noResult, total
### 使用组件
page-table-title 组件自定义title, page-table-footer 组件自定义footer, page-table-no-result 组件自定义noResult, page-table-total 组件自定义total
```html
<ngx-page-table [tableData]="tableData" [tableColumns]="tableColumns" [paginationConfig]="paginationConfig"
  [tableConfig]="tableConfig"
  [virtualConfig]="virtualConfig"
  >
  <!-- 自定义title -->
   <page-table-title>
    <ng-template>
      <div nz-row>
        <div nz-col nzSpan="12">
          <span>tableTitle</span>
        </div>
        <div nz-col nzSpan="12">
          <button nz-button nzType="primary" (click)="console.log('aaa')">表格title</button>
        </div>
      </div>
    </ng-template>
  </page-table-title>
  <!-- 自定义表格列 -->
  <page-table-column label="ID" key="key" align="center" [showOverflowTooltip]="true" [width]="65">
    <ng-template let-listData>
      <td nzAlign="center">
        <button nz-button class="temporary_storage">
          {{listData['key']}}
        </button>
      </td>
    </ng-template>
  </page-table-column>
   <page-table-column label="操作" key="operation" type="operation">
    <ng-template let-listData>
      <td> <a (click)="handleDetails(listData)">详情</a></td>
    </ng-template>
  </page-table-column>

  <!-- 自定义total -->
  <page-table-total>
    <ng-template let-total>
      共{{total}} 条
    </ng-template>
  </page-table-total>
  <!-- 自定义footer -->
  <page-table-footer>
    <ng-template>
    <div nz-row>
      <div nz-col nzSpan="12">
        <button nz-button nzType="danger">页脚</button>
      </div>
    </div>
  </ng-template>
  </page-table-footer>
</ngx-page-table>
```
### 使用配置项
通过tableConfig.title 配置表格title, 优先级低于 page-table-title组件

tableConfig.footer 配置表格footer, 优先级低于 page-table-footer组件

tableConfig.noResult 配置表格无数据时显示的模板, 优先级低于 page-table-no-result组件

paginationConfig.total 配置分页器total, 优先级低于 page-table-total组件
```html
<ngx-page-table [tableData]="tableData" [tableColumns]="tableColumns" [paginationConfig]="paginationConfig"
  [tableConfig]="tableConfig"
  [virtualConfig]="virtualConfig"
  >
  <page-table-column label="ID" key="key" align="center" [showOverflowTooltip]="true" [width]="65">
    <ng-template let-listData>
      <td nzAlign="center">
        <button nz-button class="temporary_storage">
          {{listData['key']}}
        </button>
      </td>
    </ng-template>
  </page-table-column>
   <page-table-column label="操作" key="operation" type="operation">
    <ng-template let-listData>
      <td> <a (click)="handleDetails(listData)">详情</a></td>
    </ng-template>
  </page-table-column>
</ngx-page-table>

<ng-template #title>
  <div>title</div>
</ng-template>
<ng-template #noResult>
  <div>无数据</div>
</ng-template>
<ng-template #totalRef let-total>
  <div>{{total}} 条</div>
</ng-template>
```
```ts
export class TableDemoComponent {
  @ViewChild('title') templateTitle: TemplateRef<void> | null  = null;
  @ViewChild('footer') templateFooter: TemplateRef<void> | null  = null;
  @ViewChild('noResult') templateNoResult: TemplateRef<void> | null  = null;
  @ViewChild('totalRef') templateTotal: TemplateRef<{ $implicit: number; range: [number, number]}> | null  = null;

  tableData: Array<any> = mockTableData;
  tableColumns: Array<ITableColumn<any>> = mockTableColumns;
  
  paginationConfig: IPagination = {
    pageIndex: 1,
    pageSize: 10,
    total: 0,
    show: true,
    showSizeChanger: true
  }; // 分页配置
  
  tableConfig: ITableConfig = {
    loading: false,
    title: '',
    noResult: 'noResultTemplate',
    scroll: {x: 1620 +'px', y: '460px'},
    showSelection: true,
    showOperation: true,
    showRowSelection: false,
    size: 'small',
    border: true,
    outerBorder: true
  }; // 表格配置
  virtualConfig = {
    virtualItemSize: 0,
    virtualMaxBufferPx: 100,
    virtualMinBufferPx: 500,
    virtualForTrackBy: VirtualForTrackBy
  }, // 虚拟滚动配置

  constructor(private cdr: ChangeDetectorRef) {

  }

  handleDetails(data) {
    console.log("handleDetails", data);
  }

  ngAfterViewInit() {
    this.tableConfig.title = this.templateTitle ;
    this.tableConfig.footer = this.templateFooter;
    this.tableConfig.noResult = this.templateNoResult;
    this.paginationConfig.totalRef = this.templateTotal;
  }
}
```

## API

### tableData

tableData 为数组，则为前端分页，tableData 为Observable，则为后端分页

### tableConfig

| 参数 | 说明 | 类型 | 默认值 | 备注 |
| --- | --- | --- | --- | --- |
| rowKey | 表格数据索引字段key | string | 'id' | |
| frontPagination | 是否前端分页 | boolean | true | tableData 类型为Array时，默认为true, tableData 类型为Observable时，默认为false |
|initFetchData | 后端分页时，是否初始化就请求数据 | boolean | false | |
| border | 是否带有纵向边框 | boolean | false | |
| outerBorder | 是否带有外边框 | boolean | false | |
| size | 表格大小 | string | 'default' | 可选值：default,middle,small |
| loading | 是否显示加载中效果 | boolean | false | |
| loadingIndicator | 加载中自定义内容 | TemplateRef<void> | |
| loadingDelay | 加载延迟时间 | number | 0 | |
| scroll | 表格滚动区域 | { x:  string, y:  string } | |
| title | 表格标题 | string | TemplateRef<void> \| null |  | |
| footer | 表格页脚 | string | TemplateRef<void> \| null |  | |
| noResult | 无数据时显示内容 | string | TemplateRef<void> \| null |  | |
| dataPath | 后端分页时，从请求结果中获取数据的路径 | string \| null | null |  eg:  res: { data: {data: {list: [], total: 10}}, meta: {}} => 'data.data.list' |
| totalPath | 后端分页时，从请求结果中获取数据的总数 | string \| null | null |  eg:  res: { data: {data: {list: [], total: 10}}, meta: {}} => 'data.data.total' |
| showSelection | 是否显示筛选列 | boolean | false |  |
| showOperation | 是否显示操作列 | boolean | false |  |
| showRowSelection | 是否显示全选按钮 | boolean | false |  |
| selections | 自定义表头筛选项 | Array<ISelection> | [] |  |
| dragSort | 是否开启拖拽排序 | boolean | false |  |
| showSelectAll | 是否显示跨页全选按钮 | boolean | false |  |

### paginationConfig

| 属性 | 说明 | 类型 | 默认值 | 备注 |
| --- | --- | --- | --- | --- |
| show | 是否显示分页器 | boolean | true |
| position | 分页器位置 | 'top' \| 'bottom' \| 'both' | 'bottom' |
| size | 分页器大小 | 'default' \| 'small' | 'default' |
| pageSizeOptions | 每页显示条目数可选项 | number[] | [10, 20, 30, 40, 50] |
| showSizeChanger | 是否可以改变每页显示多少条 | boolean | false |
| showQuickJumper | 是否可以快速跳转至某页 | boolean | false |
| showTotal | 是否显示total | boolean | false |
| totalRef | 自定义total模板 | TemplateRef<any> | null |
| hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false| null|
| simple | 使用简单模式 | boolean | false | |
| total | 分页总数 | number | 0 |
| pageSize | 每页显示条目数 | number | 10 |
| pageIndex | 当前页数 | number| 1 | 

### virtualConfig
虚拟滚动配置

| 属性 | 说明 | 类型 | 默认值 | 备注 |
| --- | --- | --- | --- | --- |
| virtualItemSize | 虚拟滚动时每一列的高度 | number | 0 |与 cdk itemSize 相同 |
| virtualMaxBufferPx | 缓冲区最大像素高度 | number | 100 | 与 cdk maxBufferPx 相同 |
| virtualMinBufferPx | 缓冲区最小像素高度 | number | 500 | 低于该值时将加载新结构，与 cdk minBufferPx 相同 |
| virtualForTrackBy | 虚拟滚动时，用于跟踪数据的唯一标识 | TrackByFunction<any> | null | 与 cdk virtualForTrackBy 相同 |

### tableColumn 

表格列配置

| 属性 | 说明 | 类型 | 默认值 | 备注 |
| --- | --- | --- | --- | --- |
| key | 列索引 | string | '' |
| type | 列类型 | string | undefined | 可选： 'selection' \| 'operation' |
| label | 列标题 | string | '' |
| width | 列宽度 | number | undefined |
| fixed | 列固定位置 | 'left' \| 'right' \| undefined | undefined | type ="selection" 自动固定在左侧，type="operation" 自动固定在右侧 |
| align | 列对齐方式 | 'left' \| 'center' \| 'right' | 'left' |
| breakWord | 是否换行 | boolean | false |
| ellipsis | 是否省略 | boolean | false |
| showOverflowTooltip | 列内容过长时是否显示tooltip | boolean | false |
| sortOrder | 默认排序顺序 | 'ascend' \| 'descend' \| null | null |
| sortDirections | 可以进行排序的顺序 | 'ascend' \| 'descend' \| null | null |
| showSort | 是否显示排序图标 | boolean | false |
| showFilter | 是否显示筛选图标 | boolean | false |
| sortFn | 排序函数 | Function | null |
| filterFn | 筛选函数 | Function | null |
| filterMultiple | 过滤器是否多选 | boolean | true |
| listOfFilter | 筛选列表 | Array<{ text: string; value: string; disabled?: boolean }> | null |
| formatter | 格式化函数 | Function | null |
| render | 自定义渲染模板 | TemplateRef<any> | null |
| colSpan | 列合并数 | number | 1 |
| rowSpan | 行合并数 | number | 1 |
| lineClamp | 默认显示行数 | number | 1 | 超过指定行数显示省略号 |
| sortPriority | 排序优先级 | number | 0 |
| editable | 单元格是否可编辑 | boolean | false |

### event
| 事件名 | 说明 | 回调参数 | 备注 |
| --- | --- | --- | --- |
| pageSizeChange | 每页显示条数改变 | (size: number) |
| pageIndexChange | 当前页改变 | (index: number) |
| currentPageDataChange | 当前页数据改变 | (data: any[]) |
| queryParamsChange | 查询参数改变 | (params: any) |
| sortChange | 排序改变 | ({order: any, field: ITableColumn<T>}) |
| filterChange | 过滤条件改变 | ({filter: any, field: ITableColumn<T>}) |
| selectionChange | 选中项改变 | (selectedId: Set<number>, selectedData: any[]) |
| editComplete | 单元格编辑完成 | (data: any) | 当前编辑的数据项 |
| selectAllChange | 跨页全选改变 | ({selectAll: boolean, selectedId: Set<number>, selectedData: any[]}) |