mirror of
https://github.com/dotnetcore/Util.git
synced 2026-10-21 06:36:23 +08:00
398 lines
11 KiB
TypeScript
398 lines
11 KiB
TypeScript
//============== 表格包装器=======================
|
|
//Copyright 2018 何镇汐
|
|
//Licensed under the MIT license
|
|
//================================================
|
|
import { Component, Input, Output, ViewChild, ContentChild, AfterContentInit, EventEmitter } from '@angular/core';
|
|
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
|
|
import { SelectionModel } from '@angular/cdk/collections';
|
|
import { WebApi as webapi } from '../common/webapi';
|
|
import { Message as message } from '../common/message';
|
|
import { PagerList } from '../core/pager-list';
|
|
import { IKey, QueryParameter } from '../core/model';
|
|
import { MessageConfig as config } from '../config/message-config';
|
|
import { DicService } from '../services/dic.service';
|
|
import { Util as util } from '../util';
|
|
|
|
/**
|
|
* Mat表格包装器
|
|
*/
|
|
@Component({
|
|
selector: 'mat-table-wrapper',
|
|
template: `
|
|
<div class="table-container mat-elevation-z8" [ngStyle]="getStyle()">
|
|
<div class="table-loading-shade" *ngIf="loading">
|
|
<mat-spinner></mat-spinner>
|
|
</div>
|
|
<ng-content></ng-content>
|
|
<mat-paginator [length]="totalCount" [pageSize]="queryParam&&queryParam.pageSize" [pageSizeOptions]="pageSizeOptions"></mat-paginator>
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.table-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: relative;
|
|
}
|
|
.table-loading-shade {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 56px;
|
|
right: 0;
|
|
background: rgba(0, 0, 0, 0.15);
|
|
z-index: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
::ng-deep .mat-table {
|
|
overflow: auto;
|
|
}
|
|
::ng-deep .table-header {
|
|
min-height: 64px;
|
|
padding: 8px 24px 0;
|
|
z-index: 100;
|
|
}
|
|
::ng-deep .mat-form-field {
|
|
width: 100%;
|
|
}
|
|
`]
|
|
})
|
|
export class TableWrapperComponent<T extends IKey> implements AfterContentInit {
|
|
/**
|
|
* 查询延迟
|
|
*/
|
|
timeout;
|
|
/**
|
|
* 查询延迟间隔,单位:毫秒,默认500
|
|
*/
|
|
@Input() delay: number;
|
|
/**
|
|
* 显示进度条
|
|
*/
|
|
loading: boolean;
|
|
/**
|
|
* 总行数
|
|
*/
|
|
totalCount = 0;
|
|
/**
|
|
* 初始排序
|
|
*/
|
|
initOrder: string;
|
|
/**
|
|
* 数据源
|
|
*/
|
|
dataSource: MatTableDataSource<T>;
|
|
/**
|
|
* checkbox选中列表
|
|
*/
|
|
checkedSelection: SelectionModel<T>;
|
|
/**
|
|
* 点击行选中列表
|
|
*/
|
|
selectedSelection: SelectionModel<T>;
|
|
/**
|
|
* 键
|
|
*/
|
|
@Input() key: string;
|
|
/**
|
|
* 初始化时是否自动加载数据,默认为true,设置成false则手工加载
|
|
*/
|
|
@Input() autoLoad: boolean;
|
|
/**
|
|
* 最大高度
|
|
*/
|
|
@Input() maxHeight: number;
|
|
/**
|
|
* 最小高度
|
|
*/
|
|
@Input() minHeight: number;
|
|
/**
|
|
* 宽度
|
|
*/
|
|
@Input() width: number;
|
|
/**
|
|
* 分页长度列表
|
|
*/
|
|
@Input() pageSizeOptions: number[];
|
|
/**
|
|
* 基地址,基于该地址构建加载地址和删除地址,范例:传入test,则加载地址为/api/test,删除地址为/api/test/delete
|
|
*/
|
|
@Input() baseUrl: string;
|
|
/**
|
|
* 数据加载地址,范例:/api/test
|
|
*/
|
|
@Input() url: string;
|
|
/**
|
|
* 删除地址,注意:由于支持批量删除,所以采用Post提交,范例:/api/test/delete
|
|
*/
|
|
@Input() deleteUrl: string;
|
|
/**
|
|
* 查询参数
|
|
*/
|
|
@Input() queryParam: QueryParameter;
|
|
/**
|
|
* 查询参数变更事件
|
|
*/
|
|
@Output() queryParamChange = new EventEmitter<QueryParameter>();
|
|
/**
|
|
* 排序组件
|
|
*/
|
|
@ContentChild(MatSort) sort: MatSort;
|
|
/**
|
|
* 分页组件
|
|
*/
|
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
|
|
|
/**
|
|
* 获取样式
|
|
*/
|
|
getStyle() {
|
|
return {
|
|
'max-height': this.maxHeight ? `${this.maxHeight}px` : null,
|
|
'width': this.width ? `${this.width}px` : null
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 初始化Mat表格包装器
|
|
*/
|
|
constructor(private dic: DicService<QueryParameter>) {
|
|
this.minHeight = 300;
|
|
this.pageSizeOptions = [10, 20, 50, 100];
|
|
this.dataSource = new MatTableDataSource<T>();
|
|
this.checkedSelection = new SelectionModel<T>(true, []);
|
|
this.selectedSelection = new SelectionModel<T>(false, []);
|
|
this.loading = false;
|
|
this.autoLoad = true;
|
|
this.queryParam = new QueryParameter();
|
|
this.delay = 500;
|
|
}
|
|
|
|
/**
|
|
* 内容加载完成时进行初始化
|
|
*/
|
|
ngAfterContentInit() {
|
|
this.initPaginator();
|
|
this.initSort();
|
|
this.restoreQueryParam();
|
|
if (this.autoLoad)
|
|
this.query();
|
|
}
|
|
|
|
/**
|
|
* 初始化分页组件
|
|
*/
|
|
private initPaginator() {
|
|
this.initPage();
|
|
this.paginator.page.subscribe(() => {
|
|
this.queryParam.page = this.paginator.pageIndex + 1;
|
|
this.queryParam.pageSize = this.paginator.pageSize;
|
|
this.query();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 初始化分页参数
|
|
*/
|
|
private initPage() {
|
|
this.queryParam.page = 1;
|
|
if (this.pageSizeOptions && this.pageSizeOptions.length > 0)
|
|
this.queryParam.pageSize = this.pageSizeOptions[0];
|
|
}
|
|
|
|
/**
|
|
* 初始化排序组件
|
|
*/
|
|
private initSort() {
|
|
if (!this.sort)
|
|
return;
|
|
this.setOrder();
|
|
this.sort.sortChange && this.sort.sortChange.subscribe(() => {
|
|
this.setOrder();
|
|
this.query();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 设置排序
|
|
*/
|
|
private setOrder() {
|
|
if (!this.sort.active)
|
|
return;
|
|
let order = `${this.sort.active} ${this.sort.direction}`;
|
|
if (!this.initOrder)
|
|
this.initOrder = order;
|
|
this.queryParam.order = order;
|
|
}
|
|
|
|
/**
|
|
* 还原查询参数
|
|
*/
|
|
private restoreQueryParam() {
|
|
if (!this.key)
|
|
return;
|
|
let query = this.dic.get(this.key);
|
|
if (!query)
|
|
return;
|
|
this.queryParam = query;
|
|
this.queryParamChange.emit(query);
|
|
}
|
|
|
|
/**
|
|
* 发送查询请求
|
|
* @param queryUrl 查询请求地址
|
|
* @param param 查询参数
|
|
*/
|
|
query(queryUrl: string = null, param = null) {
|
|
let url = queryUrl || this.url || (this.baseUrl && `/api/${this.baseUrl}`);
|
|
if (!url) {
|
|
console.log("表格url未设置");
|
|
return;
|
|
}
|
|
param = param || this.queryParam;
|
|
if (this.key)
|
|
this.dic.add(this.key, param);
|
|
webapi.get<PagerList<T>>(url).param(param).handle({
|
|
beforeHandler: () => { this.loading = true; return true; },
|
|
handler: result => {
|
|
result = new PagerList<T>(result);
|
|
result.initLineNumbers();
|
|
this.dataSource.data = result.data;
|
|
this.paginator.pageIndex = result.page - 1;
|
|
this.totalCount = result.totalCount;
|
|
this.checkedSelection.clear();
|
|
},
|
|
completeHandler: () => this.loading = false
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 延迟搜索
|
|
* @param delay 查询延迟间隔,单位:毫秒,默认500
|
|
*/
|
|
search(delay?: number) {
|
|
if (this.timeout)
|
|
clearTimeout(this.timeout);
|
|
this.timeout = setTimeout(() => {
|
|
this.query();
|
|
}, delay || this.delay);
|
|
}
|
|
|
|
/**
|
|
* 刷新
|
|
* @param queryParam 查询参数
|
|
*/
|
|
refresh(queryParam) {
|
|
this.queryParam = queryParam;
|
|
this.initPage();
|
|
this.queryParam.order = this.initOrder;
|
|
this.dic.remove(this.key);
|
|
this.query();
|
|
}
|
|
|
|
/**
|
|
* 清空数据
|
|
*/
|
|
clear() {
|
|
this.dataSource.data = new PagerList<T>().data;
|
|
this.paginator.pageIndex = 1;
|
|
this.totalCount = 0;
|
|
this.checkedSelection.clear();
|
|
}
|
|
|
|
/**
|
|
* 表头主复选框切换选中状态
|
|
*/
|
|
masterToggle() {
|
|
if (this.isMasterChecked()) {
|
|
this.checkedSelection.clear();
|
|
return;
|
|
}
|
|
this.dataSource.data.forEach(data => this.checkedSelection.select(data));
|
|
}
|
|
|
|
/**
|
|
* 表头主复选框的选中状态
|
|
*/
|
|
isMasterChecked() {
|
|
return this.checkedSelection.hasValue() &&
|
|
this.isAllChecked() &&
|
|
this.checkedSelection.selected.length >= this.dataSource.data.length;
|
|
}
|
|
|
|
/**
|
|
* 是否所有行复选框被选中
|
|
*/
|
|
private isAllChecked() {
|
|
return this.dataSource.data.every(data => this.checkedSelection.isSelected(data));
|
|
}
|
|
|
|
/**
|
|
* 表头主复选框的确定状态
|
|
*/
|
|
isMasterIndeterminate() {
|
|
return this.checkedSelection.hasValue() && (!this.isAllChecked() || !this.dataSource.data.length);
|
|
}
|
|
|
|
/**
|
|
* 获取复选框被选中实体列表
|
|
*/
|
|
getChecked(): T[] {
|
|
return this.dataSource.data.filter(data => this.checkedSelection.isSelected(data));
|
|
}
|
|
|
|
/**
|
|
* 获取复选框被选中实体Id列表
|
|
*/
|
|
getCheckedIds(): string {
|
|
return this.getChecked().map((value) => value.id).join(",");
|
|
}
|
|
|
|
/**
|
|
* 批量删除被选中实体
|
|
* @param ids 待删除的Id列表,多个Id用逗号分隔,范例:1,2,3
|
|
* @param handler 删除成功回调函数
|
|
* @param deleteUrl 服务端删除Api地址,如果设置了基地址baseUrl,则可以省略该参数
|
|
*/
|
|
delete(ids?: string, handler?: () => void, deleteUrl?: string) {
|
|
ids = ids || this.getCheckedIds();
|
|
if (!ids) {
|
|
message.warn(config.deleteNotSelected);
|
|
return;
|
|
}
|
|
message.confirm(config.deleteConfirm, () => {
|
|
this.deleteRequest(ids, handler, deleteUrl);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 发送删除请求
|
|
*/
|
|
private deleteRequest(ids?: string, handler?: () => void, deleteUrl?: string) {
|
|
deleteUrl = deleteUrl || this.deleteUrl || (this.baseUrl && `/api/${this.baseUrl}/delete`);
|
|
if (!deleteUrl) {
|
|
console.log("表格deleteUrl未设置");
|
|
return;
|
|
}
|
|
webapi.post(deleteUrl, ids).handle({
|
|
handler: () => {
|
|
if (handler) {
|
|
handler();
|
|
return;
|
|
}
|
|
message.snack(config.deleteSuccessed);
|
|
this.query();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 选中一行
|
|
* @param row 行
|
|
*/
|
|
checkRow(row) {
|
|
this.checkedSelection.clear();
|
|
this.checkedSelection.select(row);
|
|
}
|
|
} |