import { Component, Input, Output, EventEmitter, ContentChildren, OnInit, QueryList, ContentChild, TemplateRef, OnChanges, SimpleChanges, ViewChild, HostListener, ElementRef, OnDestroy, Renderer } from '@angular/core'; import {TableColumnComponent} from './column.component'; import {Observable} from 'rxjs'; import * as _ from 'lodash'; import {DcEventService} from '../broadcast/broadcast.service'; @Component({ selector: 'dc-table', template: `
暂无数据
{{header.title}}
{{option.name}}
确定
`, styles: [ ` .canSort { cursor: pointer } .table-title { font-size: 14px; } table { border: none; } table thead, table tbody { display: table; } table > div { display: block; overflow-x: hidden; overflow-y: auto; } table th { color: #333; background-color: #fff; border-bottom: 1px solid #cccccc; } table td { border-bottom: 1px solid #e2e2e2; border-top: none; } .sort { background-image: url(/assets/img/sort.png); background-repeat: no-repeat; background-position: center; width: 20px; height: 13px; display: inline-block; } .sort-desc { background-image: url(/assets/img/sort.png); background-repeat: no-repeat; background-position: center; width: 20px; height: 13px; transform: rotate(180deg); } .table-title-th { display: flex; } .table-title-th > div { display: inline-block; margin-right: 5px } .table { font-size: 12px; color: #666 !important; } .table th { font-size: 14px; color: #333 !important; line-height: 13px; } .table-th-sort { position: relative; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAMBAMAAACtsOGuAAAAHlBMVEUAAABmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmbpCqcMAAAACXRSTlMA5sZkORkGnJnb+QAcAAAAMElEQVQI12NgYDZgYGDwnMLAwCo5MYAhaeZMNYbOmTNnMCBA5cyZ08ESYCVgxWBtAGv8DCictG4/AAAAAElFTkSuQmCC') no-repeat left center; width: 8px; height: 12px; top: 1px; cursor: pointer; } .table-th-sort.asc { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFBAMAAACKv7BmAAAAG1BMVEUAAABmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ8aTmeAAAACHRSTlMA5MaZYzkYBjL+0/MAAAAhSURBVAjXY2BgcWBgYIhoZWBgk2hMYCjq6FBnsOjoaAYAMaEFlaDQ04sAAAAASUVORK5CYII=') no-repeat left top; } .table-th-sort.desc { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFBAMAAACKv7BmAAAAG1BMVEUAAABmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ8aTmeAAAACHRSTlMA58acZjkbBtcF5e8AAAAhSURBVAjXY7Do6GhmKOroUGdgk2hMYGCIaGVgYGBxYAAAWCUFlY5P/qEAAAAASUVORK5CYII=') no-repeat left bottom; } .table-th-filter { position: relative; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOBAMAAAAGUYvhAAAAKlBMVEUAAABmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZY/DOeAAAADXRSTlMA7hHexqWBXTwhA65Xbt8TvwAAAEBJREFUCNdjiL0LAgEMyiDqsgIDB4i+wcDAkAukE4D0krt3rywA0pyydyUZQKD2bgGY5r3LgJfmkWWAAG0GBAAA/oQb9Q1/UEkAAAAASUVORK5CYII=') no-repeat left bottom; width: 13px; height: 14px; top: 1px; font-size: 12px; color: #666; font-weight: normal } .hasFilter { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2QjVCMDc1RDQ4RkQxMUU4QkVBOTgyOUExQkY4MDU0MyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2QjVCMDc1RTQ4RkQxMUU4QkVBOTgyOUExQkY4MDU0MyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZCNUIwNzVCNDhGRDExRThCRUE5ODI5QTFCRjgwNTQzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjZCNUIwNzVDNDhGRDExRThCRUE5ODI5QTFCRjgwNTQzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Z/aSswAAAIpJREFUeNpiZGg8s5SBgSGKgXiwjAlIZALxAyI1gNRlgTR9AuJoIP5LQMNfqLqPTFCBY0DcQkBTC1QdAxOSYDMQH8eh4ThUngFd019ogHxC0/AJKv4XmyaYRzPRxLLQA4oRGOTYnPMfRQ0aYGIgAwy8pnAgfkWqplVArAvEq7FJMv7//59k5wEEGACgyx6ML12vzAAAAABJRU5ErkJggg==') no-repeat left bottom; } .noDatas { min-width: 100px; } .filterBtn { width: 100%; height: 100%; display: block; cursor: pointer; } .filter-box { position: absolute; left: 0; top: 20px; display: none; background: #fff; padding: 5px; box-shadow: 0px 0px 2px 1px #ccc; text-indent: 0; border-radius: 2px; white-space: nowrap; z-index: 10; } .filter-box.offset-left { right: 0; left: auto; } .filter-box > input[type=text] { width: 159px; height: 26px; border: solid 1px #ccc; padding: 0; margin: 0; background: #fff; transition: none; text-indent: 5px; font-size: 14px; font-weight: normal; color: #666; border-radius: 2px; font-size: 12px } .filter-box > input:focus { border-color: #0081cc } .filter-box > span { display: inline-block; font-size: 14px; line-height: 25px; text-indent: 7px } .filter-box > input[type=checkbox] { position: relative; display: none; bottom: -2px; cursor: pointer; } .filterSubmit { padding: 0 20px; text-align: center; margin: 5px auto; color: #fff; width: 94px; height: 26px; line-height: 23px; font-size: 14px; background: #0081cc; border-radius: 10px; box-shadow: 0px 0px 1px 1px #ccc; cursor: pointer; } .filterSubmit:hover { background: #0067a3 } .filterSubmit:active { box-shadow: none } .hasSubmit { color: #000000; background: #ccc; box-shadow: 0px 0px 1px 1px #ccc; } th.check-box { width: 33px; } .table th, .table td { text-align: left; border-top: none; padding: 18px 0 13px; text-indent: 20px; height: 14px; line-height: 14px } .check-box, td { position: relative; } input[type=checkbox] { visibility: hidden; } .check-box label, td label { cursor: pointer; position: absolute; width: 18px; height: 18px; top: 18px; left: 15px; background: #fff; border: 1px solid #c8c8c8; -moz-border-radius: 3px; /* Gecko browsers */ -webkit-border-radius: 3px; /* Webkit browsers */ border-radius: 3px; /* W3C syntax */ } .filter-box label { display: inline-block; position: relative; cursor: pointer; width: 16px; height: 16px; top: 10px; left: 5px; background: #fff; border: 1px solid #c8c8c8; -moz-border-radius: 3px; /* Gecko browsers */ -webkit-border-radius: 3px; /* Webkit browsers */ border-radius: 3px; /* W3C syntax */ } .check-box label:hover, .filter-box label:hover, td label:hover { background: #0081CC; } .check-box label:after, td label:after { opacity: 0; content: ''; position: absolute; width: 9px; height: 5px; background: transparent; top: 4px; left: 4px; border: 2px solid #fff; border-top: none; border-right: none; -webkit-transform: rotate(-45deg); -moz-transform: rotate(-45deg); -o-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .filter-box label:after { opacity: 0; content: ''; position: absolute; width: 9px; height: 5px; background: transparent; top: 3px; left: 3px; border: 2px solid #fff; border-top: none; border-right: none; -webkit-transform: rotate(-45deg); -moz-transform: rotate(-45deg); -o-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .check-box label:hover::after, .filter-box label:hover::after, td label:hover::after { opacity: 0.6; } input[type=checkbox]:disabled + label { cursor: not-allowed; background-color: #f5f5f5; opacity: 0.4; } input[type=checkbox]:disabled + label:hover { background: #ffffff; } input[type=checkbox]:checked + label { background: #0081CC; } input[type=checkbox]:checked + label:after { opacity: 1.0; } tbody tr.bgc:nth-child(odd) { background-color: #f8f8f8; } tbody tr.bgc:nth-child(even) { background-color: #ffffff; } tbody tr:hover { background-color: #edf0f5; } tbody tr.bgc:hover { background-color: #edf0f5; } ` ] }) export class TableComponent implements OnInit, OnDestroy { @ContentChild(TemplateRef) template: TemplateRef; // @ContentChildren(TableColumnComponent) // childCmps: QueryList; @ViewChild('filterTemplate') filterTemplate: any; @ViewChild('table') tableContainer: ElementRef; @ViewChild('overflowBox') overflowBox: ElementRef; @Input() headers: Array; @Input() oddEven: any; // 是否奇偶变色 @Input() isSmall: any; // 表格行高设置 @Input() tableId: any; // 设置table表格唯一Id @Input() radio: boolean; // 是否单选 @Input() userPersentWidth: boolean = false; hasFilter: Array = []; // 表格列是否过滤数组 _datas: any; @Input() set datas(v) { this.allSelect = false; this._datas = v; this.setDivWidth(); this.initCheck(); } get datas() { return this._datas; } @Input() checkBox: boolean = false; @Output() sortEvent: EventEmitter = new EventEmitter(); @Output() checkEvent: EventEmitter = new EventEmitter(); nowSort: any = {}; allSelect: boolean = false; checks: Array = []; checks_data: any = []; currentField: any; @Input() scrollHeight: string; _parentHidden: boolean; curSearchValue: any; @Input() set parentHidden(v: boolean) { this._parentHidden = v; setTimeout(() => this.setDivWidth()); } get parentHidden(): boolean { return this._parentHidden; } initWidth: any; resizeEvent: any; scrollBarWidth: any = 0; showFilter: any = []; broadCastPromise: any; constructor(private renderer: Renderer, private broadcast: DcEventService) { } ngOnInit(): void { this.broadCastPromise = this.broadcast.on('leftmenu_close').subscribe(event => { setTimeout(() => { this.setDivWidth(); }, 100); }); this.setDivWidth(); this.resizeEvent = Observable.fromEvent(window, 'resize').subscribe(event => { this.setDivWidth(); }); // this.initCheck(); } ngOnDestroy() { this.resizeEvent && this.resizeEvent.unsubscribe(); this.broadCastPromise && this.broadCastPromise.unsubscribe(); } setWidth(width: any, index?: number) { if (this.userPersentWidth) { if (width.indexOf('%') <= 0) { width = width + '%'; return width; } } else { if (width && width.indexOf('%') > 0) { // if (this.checkBox && index === 0) { // return (parseInt(width) / 100 * this.initWidth) - 30 + 'px'; // } else { let _w; if (this.checkBox) { _w = this.initWidth - 35; } else { _w = this.initWidth; } if (_w < 0) { _w = 0; } return parseInt(width) / 100 * _w + 'px'; // } } else { return width; } } } setDivWidth() { const parent = this.tableContainer.nativeElement.parentNode.parentNode; this.initWidth = parent.offsetWidth || this.initWidth; if (this.scrollHeight && this.overflowBox) { this.renderer.setElementStyle(this.overflowBox.nativeElement, 'width', this.initWidth + 'px'); } } private initCheck() { this.checks = []; for (let d of this.datas) { this.checks.push(false); } } allSelectCheck() { this.checks = []; if (this.radio) { return; } for (let d of this.datas) { if (d.readOnly) { this.checks.push(false); } else { this.checks.push(this.allSelect); } } this.sendCheckEvent(); } checkSelect(index: number) { if (this.radio) { for (let i = 0; i < this.checks.length; i++) { if (!this.datas[i].readOnly && i !== index) { this.checks[i] = false; } } } let allTrue = true; for (let i = 0; i < this.checks.length; i++) { if (!this.checks[i] && !this.datas[i].readOnly) { allTrue = false; } } if (allTrue) { this.allSelect = true; } else { this.allSelect = false; } this.sendCheckEvent(); } checkOption(event: any, k: any, header: any) { header.filter.optionList[k].check = event; } private sendCheckOption(header: any, index: any) { let result: any = header.filter.optionList.filter((item: any) => item.check); if (result.length === 0) { this.hasFilter[index] = false; } else { this.hasFilter[index] = true; } header.filter.fn(result); } private sendCheckEvent(): any { this.checks_data = []; for (let i = 0; i < this.datas.length; i++) { if (this.checks[i]) { this.checks_data.push(this.datas[i]); } } this.checkEvent.emit(this.checks_data); } sort(header: any) { if (!header.canSort) { return; } if (this.nowSort.field == header.field) { if (this.nowSort.sort == 'desc') { this.nowSort.sort = 'asc'; } else if (this.nowSort.sort == 'asc') { this.nowSort.sort = ''; } else { this.nowSort.sort = 'desc'; } } else { this.nowSort.field = header.field; this.nowSort.sort = 'desc'; } if (this.sortEvent.observers.length) { this.sortEvent.emit(this.nowSort); } else { this.datas.sort((a: any, b: any) => { let result = this.nowSort.sort === 'asc' ? a[this.nowSort.field] > b[this.nowSort.field] : b[this.nowSort.field] > a[this.nowSort.field]; return result ? 1 : 0; }); } } showFilterBox(event: any, header: any) { this.hideFilter(); event.stopPropagation(); event.preventDefault(); let filterBoxDom = event.target.nextElementSibling; filterBoxDom.style.display = 'block'; let flag = false; for (let i = 0; i < this.showFilter.length; i++) { if (this.showFilter[i] == filterBoxDom) { flag = true; break; } } if (!flag) { this.showFilter.push(filterBoxDom); } this.currentField = header.field; } hideFilter() { for (let i = 0; i < this.showFilter.length; i++) { this.showFilter[i].style.display = 'none'; } this.showFilter = []; } clickFilter(event: any, header: any, index?: any) { if (event.target.value === '') { } else { this.hasFilter[index] = true; header.filter.fn(_.trim(event.target.value)); } let filterBoxDom = event.target.parentNode; filterBoxDom.style.display = 'none'; } checkEmpty(event: any, header: any, index?: number) { if (event === '') { this.hasFilter[index] = false; header.filter.fn(event); } } // 设置th内容居中 setThCenter(isCenter: boolean) { let center: any; if (isCenter) { center = { 'display': 'flex', 'justify-content': 'center' }; } return center; } @HostListener('document:click', ['$event']) onDocumentClick($event: any) { let current = $event.target; for (let i = 0; i < this.showFilter.length; i++) { if (current.parentNode !== this.showFilter[i] && current !== this.showFilter[i].prevElementSibling && current !== this.showFilter[i]) this.showFilter[i].style.display = 'none'; } } }