UNPKG

ace-component

Version:

ace-components for ewms

819 lines (713 loc) 22.7 kB
import { Component, OnInit, ViewEncapsulation, Input, Output, ElementRef, NgZone, EventEmitter, ChangeDetectorRef,OnChanges,ContentChild,TemplateRef} from '@angular/core'; import { AjaxSetting, AceTableService, CBparams } from './ace-table.service' import * as $ from 'jquery' interface DataInfo { page: number; totalPage?: number; total?: number; startId?: number; endId?: number; } interface ModalState { show: boolean; text?: string; } interface ShowTr { el: any; show: boolean; } @Component({ selector: 'ace-table', templateUrl: './ace-table.component.html', styleUrls: ['./ace-table.component.scss'], encapsulation: ViewEncapsulation.None, providers: [AceTableService], }) export class AceTableComponent implements OnInit { @ContentChild(TemplateRef) template; @Input() DEGUGGER:boolean = false; @Input() tbTitle; //表格标题 _dataSource: Array<object> = [];//遍历的数据 @Input() set dataSource(val: Array<object>) { this._dataSource = val; this.init(); } get dataSource() { return this._dataSource } @Input() theadSource: Array<object> //表头数据 @Input() widths: Array<number> = []; //默认宽度100; @Input() minWidth: number = 100;//最小宽度 _tableHeight:number; @Input() get tableHeight():number{ return this._tableHeight } set tableHeight(val){ this._tableHeight = val; if(this.tableEle){ this.styInit() } } // @Input() rowNumber: number = 10; //一页的函数,默认10 @Input() multipleChoice: boolean = true; //是否可以多选 @Input() loading: boolean = false; //加载动画 @Input() dataInf: DataInfo = { //数据的相关信息 page: 1, totalPage: 1, total: 1, startId: 0, endId: 0 }; @Input() modalState: ModalState = { //modal框的设置 show: false, text: "初次打开页面不加载数据,请组合条件进行搜索数据..." }; @Input() operateState: boolean = false; //控制开关状态 @Input() changeState: boolean = false; //操作状态 @Input() paginNum: number = 5; //翻页器显示的数量 @Output() onSelect = new EventEmitter(); //选中了某一行触发的事件 @Output() onChangeRows = new EventEmitter(); //改变了每页行数的事件 @Output() onChangePage = new EventEmitter(); //翻页 @Output() onReflresh = new EventEmitter(); //刷新单项 @Output() onChangeInfomation = new EventEmitter(); @Output() onDelInfomation = new EventEmitter(); @Output() onAjaxOver = new EventEmitter(); private wrapEle: any; //容器 private tableEle: any; //表格区 private theadEle: any; //头部 public theadSty: any; //头部的样式 public thOffsetLeft: number = 0; //头部偏移量 private contentEle: any; //内容区 private moveBlock: any; //拖动的模型 private lineEle: any; //标志线 public wrapWidth: number; //容器宽度 private tableWidth: number; //表格区宽度 private colsWidth: Array<number> = []; //每一列的实际宽度 private movedCol: number | null; //可以移动的列的下标 private moveStarX: number | null = null; //初始位置 private moveCurrX: number | null = null; //最新的位置 private colSetVals: Array<number> = []; //用户设置的固定宽度,包括拖动,固定宽度 private setColsTotal: number; //设置的值的固定宽度 private tdpadding: number; //td,td padding值 private closeStatus: boolean = false; //收起 private checkRow: object = {}; //选中的行 private selectAll: boolean = false; //选中的行 private windowResize: any; //window.onresize 绑定的函数 private mouseUpFunction: any; //window.mouseup 绑定的函数 private inPutEle: any; //底部页数输入框 public inputValue: any = 1; //底部页数输入框 输入的值 public inputTextSty: object = { //输入框样式 "z-index": 5 }; private operaRefresh: Array<boolean>; //正在刷新的行的集合 private operaShowDetail: Array<ShowTr> = []; //正在展开的行的集合 @Input() rowNumber: number = 30; //一页的函数,默认30 _selectOption:Array<number>=[ 10,20,30,50,100 ]; @Input() set selectOption(arr:Array<number>){ this._selectOption = arr; } get selectOption(){ return this._selectOption } constructor( private el: ElementRef, private zone: NgZone, public service: AceTableService, public cd: ChangeDetectorRef ) { this.cd.detach(); } ngOnChanges() { this.do(); setTimeout(() => { this.tableResize(); }); this.inputValue = this.dataInf.page; } ngOnInit() { if (!this.theadSource) { throw new Error('theadSource is undefined.theadSource is required.') }; this.colsWidth = []; Promise.resolve().then(() => { this.init(); this.getElementWidth(); if ("colsWidth" in this) { this.setUserSettingWidth() ? this.styInit() : ""; } else { this.styInit() } }).then(() => { //绑定事件 let timeout; this.windowResize = function () { clearTimeout(timeout); setTimeout(() => { this.zone.run(() => { this.tableResize(); }); }, 200) }; this.windowResize = this.windowResize.bind(this); window.addEventListener('resize', this.windowResize); }).then(() => { this.mouseUpFunction = this.mouseUp.bind(this); document.body.addEventListener('mouseup', this.mouseUpFunction); }).then(() => { if (this.ajaxUrl) { if (typeof this.setParamsFn != 'function') { throw 'settingParams must be function , it is used to setting http params'; } this.modalState.show = true; } }); } ngOnDestroy() { document.body.removeEventListener('mouseup', this.mouseUpFunction); window.removeEventListener('resize', this.windowResize); } do() { this.cd.detectChanges(); } //获取关键节点 init() { this.wrapEle = (<any>$(this.el.nativeElement)).find('.ace-wrap'); this.tableEle = $(this.wrapEle).find('.ace-table-content'); this.theadEle = (<any>$(this.el.nativeElement)).find('.ace-table-thead'); this.contentEle = (<any>$(this.el.nativeElement)).find('.ace-table-list'); this.moveBlock = (<any>$(this.el.nativeElement)).find('.ace-move-block'); this.lineEle = (<any>$(this.el.nativeElement)).find('.ace-move-line'); this.inPutEle = (<any>$(this.el.nativeElement)).find('.text-area-view').find('input'); if (this.operateState) { this.operaRefresh = []; for (let i = 0; i < this.dataSource.length; i++) { this.operaRefresh.push(false); } }; } //计算没设置固定宽度td的宽度 styInit() { if ('tableHeight' in this) { //设置默认高度: $(this.tableEle).css({ height: this.tableHeight + 'px', overflow: "hidden" }); } this.setColsTotal = this.colsWidth.reduce((total, next) => { return total + next; }, 0); //默认值minWidth不足以填满table var val; if (this.tableWidth > (this.setColsTotal + this.minWidth * (this.theadSource.length - this.colsWidth.length))) { //平均分配 val = Math.floor((this.tableWidth - this.setColsTotal) / (this.theadSource.length - this.colsWidth.length)); } else { //统一设置为this.minWidth val = this.minWidth } for (let i = this.colsWidth.length; i < this.theadSource.length; i++) { this.colsWidth[i] = val; } } //获取宽度,wrap 跟table,如果table大于wrap,需要添加滚动属性给wrap getElementWidth() { this.wrapWidth = $(this.wrapEle).width(); this.tableWidth = $(this.tableEle).width() - 17; this.theadSty = { width: this.wrapWidth + "px" }; } //设置用户自定义的宽度 setUserSettingWidth() { //widths不够 if (this.widths.length < this.theadSource.length) { this.widths.forEach((val, idx) => { this.colSetVals[idx] = val; this.colsWidth.push(val); }) return true } else { //widths过多,不需要计算默认值 this.widths.forEach((val, idx) => { if (idx > this.colsWidth.length) return val > this.minWidth ? this.colsWidth[idx] = val : this.colsWidth[idx] = this.minWidth; }); return false } } //resize table tableResize() { if (!this.wrapEle) return this.getElementWidth(); //没设置宽度的td计算 var nosetArr = []; this.theadSource.forEach((val, idx) => { if (!this.colSetVals[idx]) { nosetArr.push(idx) } }); let x = Math.floor((this.tableWidth - this.setColsTotal - (this.multipleChoice ? 50 : 0) - (this.operateState ? 200 : 0) - (this.changeState ? 200 : 0)) / nosetArr.length); x = x > this.minWidth ? x : this.minWidth; nosetArr.forEach((val) => { this.colsWidth[val] = x; }); this.checkScroll(); } //判断是否需要 横向滚动条 或者纵向滚动条 checkScroll() { //纵向 var scrollY = 'hidden', scrollX = 'hidden'; if ('tableHeight' in this) { var h = $(this.contentEle).height(); var contentH = $(this.theadEle).height() + h; if (contentH > this.tableHeight || h < 10) { scrollY = 'scroll' this.theadSty = { width: this.wrapWidth - 17 + "px" } $(this.contentEle).css('padding-right', 0); } else { $(this.contentEle).css('padding-right',0); this.theadSty = { width: this.wrapWidth + "px" } } } var total = this.colsWidth.reduce((pre, next) => { return pre + next; }, ((this.multipleChoice ? 50 : 0) + (this.operateState ? 200 : 0) + (this.changeState ? 200 : 0))); if (total > this.tableWidth) { scrollX = 'scroll'; } $(this.tableEle).css({ overflowX: scrollX, overflowY: scrollY }); this.do(); } //计算th宽度 getThSty(idx) { return "colsWidth" in this ? { width: this.colsWidth[idx] + "px" } : ''; } // 收起表单 close() { this.closeStatus = !this.closeStatus; if (this.closeStatus) { (<any>$(this.wrapEle)).slideUp(); } else { (<any>$(this.wrapEle)).slideDown(); } this.do(); } //关闭表单时候的按钮动画 closeIconSty() { // return this.closeStatus?{display:'none'}:{display:'block'}; if (this.closeStatus) { return { transform: "rotate(180deg)" }; } else { return { transform: "rotate(0)" }; } } //获取key值 getKeys(data: any) { var arr = []; this.theadSource.forEach((val: any, idx: number)=>{ var tdData: any = {}; if (typeof data[val.name] == 'object'&&data[val.name]!==null) { data[val.name].rowspan ? tdData.rowspan = data[val.name].rowspan : 1; data[val.name].slot ? tdData.slot = data[val.name].slot :false; if('value' in data[val.name]){ tdData.text = data[val.name].value; } if('position' in data[val.name]){ tdData.position = data[val.name].position; } arr.push(tdData); } else if (val.name in data) { tdData.text = data[val.name]; arr.push(tdData); }else{ if(this.DEGUGGER){ arr.push(""); } } }); return arr; } //拖动横向滚动条 tableScroll(e: any) { if (e.target.scrollLeft != -this.thOffsetLeft) { this.thOffsetLeft = -e.target.scrollLeft; this.do(); } } //th拖动事件 //1.只能在右边拖动 //2.20px是触发的条件 //3.鼠标变形 //4.点击之后,隐藏标签出现,获取offsetX //5.隐藏标签有mouseon事件,竖条跟着走。 //6.松开鼠标结束 //7.判断能否移动到该位置(过小的问题) thMoving(e: any, idx) { if (this.colsWidth[idx] - e.offsetX < 20) { if($(e.target).css('cursor')!='e-resize'){ $(e.target).css({ cursor: 'e-resize' }); } } else { if($(e.target).css('cursor')!='default'){ $(e.target).css({ cursor: 'default' }); } } } //记录下移动的th的下标 tdisClilked(e: any, idx) { if (this.colsWidth[idx] - e.offsetX < 20) { this.movedCol = idx; $(this.moveBlock).css('z-index', 10); } } mySetTimeout = null; //坐标线位置, 移动中 moveBlockEvent(e: any) { var css:any = { transform:'translateX(' + e.offsetX + 'px)' } if($(this.lineEle).css('opacity') as any==0){ css.opacity = 1; this.moveStarX = e.clientX; } this.moveCurrX = e.clientX; $(this.lineEle).css(css); } mouseUpSet=null; //松开鼠标 mouseUp(e) { if(this.mouseUpSet) clearTimeout(this.mouseUpSet); this.mouseUpSet = setTimeout(()=>{ if (this.lineEle[0].style.opacity == 1) { if (this.movedCol == null) return $(this.lineEle).css('opacity', 0); $(this.moveBlock).css('z-index', -1); //计算移动的距离 let moveSize = this.moveCurrX - this.moveStarX; if (this.colsWidth[this.movedCol] + moveSize < this.minWidth) { this.colsWidth[this.movedCol] = this.minWidth; } else { this.colsWidth[this.movedCol] = this.colsWidth[this.movedCol] + moveSize; } this.colSetVals[this.movedCol] = this.colsWidth[this.movedCol]; this.setColsTotal = this.colSetVals.reduce((pre, next) => { if (next) { return pre + next; } else { return pre; } }) this.tableResize(); this.moveCurrX = null; this.moveStarX = null; this.movedCol = null; this.do(); } },30) } //选中一行 onCheckRow(idx: number) { setTimeout(() => { var num = 0; for (var i in this.checkRow) { if (this.checkRow[i] == false) break; num++ }; this.emitSelect() this.selectAll = num == this.dataSource.length; this.do(); }) } //全选 onSelectedAll() { setTimeout(() => { this.dataSource.forEach((val, idx) => { this.checkRow[idx] = this.selectAll }) this.emitSelect(); this.do(); }, 30) } //选中删除指定行 delRow(): void { for (var key in this.checkRow) { this.dataSource.splice((<any>key), 1) }; this.checkRow = {}; this.do(); } //重置选中 initCheckRow() { var arr = [] for (var i in this.checkRow) { arr.push(i); } arr.forEach((val) => { delete this.checkRow[val] }) this.selectAll = false; this.do(); } //output 返回选中的数据 emitSelect() { var arr = []; for (var i in this.checkRow) { if (this.checkRow[i]) { arr.push(this.dataSource[i]) } } this.onSelect.emit(arr); } //改变每页行数 onPageNumerChanged(e: any) { this.rowNumber = e.target.value; if (this.ajaxUrl) { this.sendAjax(1); } this.onChangeRows.emit(e.target.value); this.do(); } //翻页 onToPage(page: any) { if (page == 1) { if (this.dataInf.page != 1) { if (this.ajaxUrl) { this.sendAjax(page); } this.onChangePage.emit(page); } } else if (page == this.dataInf.totalPage) { if (this.dataInf.page != this.dataInf.totalPage) { if (this.ajaxUrl) { this.sendAjax(page); } this.onChangePage.emit(page); } } else if (page > 1 && page < this.dataInf.totalPage) { if (this.ajaxUrl) { this.sendAjax(page); } this.onChangePage.emit(page) } this.do(); } //计算显示的页数 computPagination() { var paginNum = this.paginNum; var cPage = this.dataInf.page; var total = this.dataInf.totalPage; var result = []; if (total <= paginNum) { for (var i = 1; i <= total; i++) { result.push(i) } } else if (cPage <= (paginNum - 1) / 2) { for (var i = 1; i <= paginNum; i++) { result.push(i) }; } else if (cPage + ((paginNum - 1) / 2) >= total) { for (var i = total; i > total - paginNum; i--) { result.unshift(i) } } else { for (var i = cPage - (paginNum - 1) / 2; i <= cPage + (paginNum - 1) / 2; i++) { result.push(i) } } return result; } //键盘输入 页数 onInputPageNum() { this.inputTextSty["z-index"] = -1; Promise.resolve().then(() => { this.inPutEle.focus(); }) } //检查输入的值 onCheckInputValue(e: any) { if (this.modalState.show) { e.preventDefault(); return } var value = e.target.value; var pro = new Promise(function (resolve, reject) { resolve(); }); pro.then(() => { if (/^[0-9]+$/.test(value) == false) { throw new Error('输入的值无效') } }).then(() => { if (value >= 1 && value <= this.dataInf.totalPage) { this.inPutEle.blur(); this.onToPage(value); this.inputTextSty["z-index"] = 5; } else { throw new Error('超出了页数范围') } }).catch(err => { this.modalState.show = true; this.modalState.text = err; setTimeout(() => { this.inputValue = this.dataInf.page; this.modalState.show = false }, 1500) }) } //输入框失去焦点 onInputBlur() { this.inputTextSty["z-index"] = 5; } //鼠标变形 onCheckChangePageAU(order: string | any) { //首页 switch (order) { case "first": if (this.dataInf.page == 1) { return { disable: true } } break; case "pre": if (this.dataInf.page - 1 <= 0) { return { disable: true } }; break; case "last": if (this.dataInf.page >= this.dataInf.totalPage) { return { disable: true } }; break; case "next": if (this.dataInf.page - 0 + 1 > this.dataInf.totalPage) { return { disable: true } }; break; } } //设置刷新动画 getReflreshSty(idx: number): string { if (!this.operaRefresh) return "" return this.operaRefresh[idx] ? "fa-spin" : "" } //改变刷新动画的状态 onChangeReflreshState(idx: number): void { this.operaRefresh[idx] = !this.operaRefresh[idx]; this.onReflresh.emit({ state: this.operaRefresh[idx], data: this.dataSource[idx] }); this.do(); }; //修改属性 onChangeInfo(idx: number): void { this.onChangeInfomation.emit(this.dataSource[idx]); this.do(); }; //删除选中行 onDelInfo(idx: number): void { this.onDelInfomation.emit(this.dataSource[idx]); this.do(); }; //展示detail onShowDetail(e: any, idx: number): void { if (this.operaShowDetail[idx] && this.operaShowDetail[idx].show) { //删除 $(this.operaShowDetail[idx].el).remove(); this.operaShowDetail[idx].show = false; } else { var curTr = $(e.target).closest('tr'); var ele = $(` <tr> <td class='ace-tb-detail' colspan="${this.computeNotDataColspan()}"> ${(<any>this.dataSource[idx]).detail} </td> </tr> `); this.operaShowDetail[idx] = { el: ele[0], show: true }; ele.insertAfter(curTr); } this.do(); }; // 全新功能 @Input() ajaxUrl: string; //请求的地址 @Input() setParamsFn; // 设置请求参数的函数 @Input() cbParams: CBparams; //设置响应时候的各个字段的名称 //启动第一次请求 firstAjax() { this.sendAjax(1); }; sendAjaxPage: number; //请求的page //发送ajax sendAjax(page: number) { if (!this.cbParams) { throw new Error('ace-table cbParams undefined') } this.modalState.show = false; this.loading = true; this.sendAjaxPage = page; this.do(); this.service.toAjax({ url: this.ajaxUrl, setParams: this.setParamsFn, cb: this.ajaxCB, page, limit: this.rowNumber, cbParams: this.cbParams }); } //请求成功 ajaxCB = ({ code, items, page, total, msg, data }) => { //根据code判断 setTimeout(() => { this.checkScroll(); setTimeout(() => { this.tableResize(); }) this.loading = false; this.do(); }, 30) $(this.el.nativeElement).find('.ace-tb-detail').closest('tr').remove(); this.initCheckRow(); if (code == 200) { this.modalState.show = false; this.dataSource = items; this.dataInf.page = page; this.dataInf.total = total; this.dataInf.startId = ((page - 1) * this.rowNumber + 1)>0?((page - 1) * this.rowNumber + 1):0; this.dataInf.endId =( (page-1) * this.rowNumber)+this.dataSource.length; this.dataInf.totalPage = Math.ceil(total / this.rowNumber); } else { this.modalState.show = true; if (typeof msg == 'string') { this.modalState.text = msg; } else { this.modalState.text = '请求失败 错误码:' + code; } } this.onAjaxOver.emit(data); } //无数据时候的展示 computeNotDataColspan() { var result = this.theadSource.length; if (this.multipleChoice) result++; if (this.changeState) result++; if (this.operateState) result++; return result; }; //判断是否展示 computeNotDataRow() { return this.dataSource.length == 0 && this.modalState.show == false && this.loading == false; } computedRowData(item) { if (typeof item == 'string' && item.indexOf("</") > -1) { return true } else { return false } } }