import { EventEmitter } from '@angular/core'; import { Component, OnInit, ElementRef, ChangeDetectorRef, Inject, Renderer2, Injector, Input, ViewChild, forwardRef, ViewEncapsulation, AfterViewChecked, Output } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { skip, take, filter, takeUntil, map, debounceTime } from 'rxjs/operators'; import { BaseComboComponent, ComboService } from '@farris/ui-combo-list'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { LookupUtils, TreeInfo } from '@farris/ui-lookup'; import { TreeNode, TreeTableComponent } from '@farris/ui-treetable'; import { DataTableComponent } from '@farris/ui-datatable'; import { Subject, forkJoin, interval, zip } from 'rxjs'; const INPUT_COMBO_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, // tslint:disable-next-line: no-use-before-declare useExisting: forwardRef(() => ComboLookupComponent), multi: true }; @Component({ // tslint:disable-next-line: component-selector selector: 'farris-combo-lookup', templateUrl: './combo-lookup.component.html', encapsulation: ViewEncapsulation.None, // styleUrls: ['./combo-lookup.component.scss'], providers: [INPUT_COMBO_VALUE_ACCESSOR, ComboService, LookupUtils] }) export class ComboLookupComponent extends BaseComboComponent implements OnInit { panelHeight = 300; comPosition = { 'height.px': this.panelHeight }; @Input() showHeader = true; @Input() useTreeView = false; // 树列表默认展开层级。 -1: 不展开; 0: 全部展开; >0: 展开到指定级数; @Input() set columns(value: any[]) { this._columns = value; } get columns(): any[] { let cols = this._columns !== undefined && this._columns.length > 0 ? this._columns : this.comboService.columns; if (this.useTreeView && cols.length > 1) { cols = cols.filter(n => n.field === this.textField); } return cols; } @Input() set pagination(value: boolean) { this._pagination = value; } get pagination() { if (this._pagination !== undefined) { return this._pagination; } else { return this.comboService.pageInfo && this.pageInfo.enablePager ? this.pageInfo.enablePager : false; } } @Input() set displayType(val: string) { this.comboService.displayType = val + ''; } get displayType() { return this.comboService.displayType; } /** -1: 不展开; 0: 全部展开;>0: 展开到指定级数 */ @Input() expandLevel = -1; @ViewChild('tt') set treeCmpRef(cmf: TreeTableComponent) { if (cmf) { cmf.cascadeCheck = this.cascade.enable; cmf.cascadeDown = this.cascade.down; cmf.cascadeUp = this.cascade.up; this.tt$.next(cmf); } this._treeCmpRef = cmf; } get treeCmpRef(): TreeTableComponent { return this._treeCmpRef; } @ViewChild('dt') set tableCmpRef(cmf: DataTableComponent) { if (cmf && this.pagination && this._tableCmpRef) { this.loaded$.pipe(take(1)).subscribe(e => { cmf.loadData({ pageSize: this.pageInfo.pageSize, total: this.pageInfo.total, data: this.data, pageIndex: this.pageInfo.pageIndex }); }); } if (!this._tableCmpRef && this.loadFinish && cmf) { cmf.loadData({ pageSize: this.pageInfo.pageSize, total: this.pageInfo.total, data: this.data, pageIndex: this.pageInfo.pageIndex }); this._tableCmpRef = cmf; } } @Input() cascade = { enable: false, up: false, down: false }; @Input() treeInfo: TreeInfo; /** 树形帮助数据加载方式: default: 内置取数; loadall: 加载所有 layerload:分层加载 */ @Input() loadTreeDataType: 'default' | 'loadall' | 'layerload' = 'default'; /** 启用构造完整树过滤 */ @Input() enableFullTree = true; @Output() pageChanged = new EventEmitter(); @Output() pageSizeChanged = new EventEmitter(); ownSelections: any; loadFinish = false; pageInfo: any = { pageSize: 20, pageIndex: 1, total: 0 }; private tt$ = new Subject(); private loaded$ = new Subject(); private _columns: any[]; private _pagination: boolean; private _tableCmpRef: any; private _treeCmpRef: any; private _searchKeyWords = ''; loadDataType = 'all'; constructor( public el: ElementRef, public cdr: ChangeDetectorRef, @Inject(DOCUMENT) public document: any, public render: Renderer2, public comboService: ComboService, public injector: Injector ) { super(el, cdr, document, render, comboService, injector); } ngOnInit() { super.ngOnInit(); this.treeClientSearch.pipe(debounceTime(300)).subscribe((value: string) => { if (!this.remoteSearch && this.treeCmpRef) { this.treeCmpRef.searchHandle.search(this.textField, value); } }); this.comboService.treeInfo$.subscribe( (t: any) => { if (t) { if (this.loadTreeDataType === 'default') { this.loadDataType = t.loadDataType; } } }); } protected onSelectionsChange(selections: any[]) { if (this.displayType === 'LOOKUPLIST') { if (!this.multiSelect) { this.ownSelections = selections[0] ? selections[0] : {}; } else { this.ownSelections = {}; this.comboService.selections.forEach(item => { this.ownSelections[item[this.idField]] = item; }); } this.pageInfo = { ...this.pageInfo, ...this.comboService.pageInfo }; this.loadFinish = true; this.cdr.detectChanges(); this.loaded$.next(this.pageInfo); } else { if (this.treeCmpRef) { this.initTreeData(); } else { this.tt$.pipe(take(1)).subscribe((cmf: TreeTableComponent) => { this.treeCmpRef = cmf; this.initTreeData(); // cmf.checkedNodes(ids, true, false); // cmf.updateSerializedValue(); }); } } } private initTreeData() { const __selections = this.comboService.selections.filter(n => n !== null && n !== undefined); const ids = []; this.ownSelections = __selections.map(item => { ids.push(item[this.idField]); return { data: item, id: item[this.idField] }; }); this.treeCmpRef.selections = this.ownSelections; this.treeCmpRef.checkeds = this.ownSelections; if (this.comboService.data && this.comboService.data.length) { if (this.treeCmpRef.checkValues && this.treeCmpRef.checkValues.length) { if (this.multiSelect) { this.treeCmpRef.checkedNodes(this.treeCmpRef.checkValues); this.treeCmpRef.selectNodes(this.treeCmpRef.checkValues); } else { this.treeCmpRef.selectNodes(this.treeCmpRef.checkValues); } } } } protected initDatasChangeAction() { } private isTree() { return this.displayType === 'LOOKUPTREELIST'; } updateMappingFieldValue(clearMapFields = false) { if ( this.ngControl && this.ngControl.formDirective && this.ngControl.formDirective.form && this.ngControl.formDirective.form.bindingData ) { const bindingData = this.ngControl.formDirective.form.bindingData; const bindingPath = this.ngControl.formDirective.form.bindingPath; let pathArr = []; if (bindingPath) { pathArr = bindingPath.split('/').filter(n => n !== ''); } this.mappingField = this.mappingField ? this.mappingField : {}; if (this.mapFields) { const helpFields = Object.keys(this.mapFields); helpFields.forEach((f: any) => { const fieldNames = this.mapFields[f] ? this.mapFields[f] : ''; let value = ''; if (!clearMapFields) { const text = this.comboService.selections && this.comboService.selections.map(item => { return this.comboService.getValueByObj(f, item); }).filter(n => n !== null).join(this.separator); // value = text ? text : this.displayText ? this.displayText : ''; value = text || ''; } if (fieldNames) { fieldNames.split(',').forEach((fieldName: any) => { let _val = value; if (this.nosearch && fieldName === this.ngControl.name) { _val = this.displayText; } if (bindingData.setValue) { bindingData.setValue( pathArr.concat(fieldName.split('.')), _val, true, true); } else { this.commonUtils.setValue(bindingData, fieldName, value); } }); } }); } } } updateSelectedValues() { if ( this.ngControl && this.ngControl.formDirective && this.ngControl.formDirective.form && this.ngControl.formDirective.form.bindingData ) { const bindingData = this.ngControl.formDirective.form.bindingData; const bindingPath = this.ngControl.formDirective.form.bindingPath; let pathArr = []; if (bindingPath) { pathArr = bindingPath.split('/').filter(n => n !== ''); } let targetField = this.mappingField ? this.mapFields[this.idField] : ''; if (targetField && targetField.indexOf(',') > -1) { targetField = targetField.split(',')[0]; } // this.mappingField = this.mappingField ? this.mappingField : ''; if (targetField && bindingData.getValue) { this.selectedValues = bindingData.getValue(pathArr.concat(targetField.split('.'))) || ''; } else if (targetField) { this.selectedValues = this.commonUtils.getValue(targetField, bindingData) || ''; } } } onSelectRows(row) { if (this.displayType === 'LOOKUPLIST') { const { data, index } = row; this.comboService.selectItem(data, index); this.selectChange.emit({ data, index, instance: this }); } else if (this.displayType === 'LOOKUPTREELIST') { const { node } = row; if (row.nodes) { this.comboService.selectItem(row.nodes.map(n => n.data)); } else { this.comboService.selectItem(node.data); } this.selectChange.emit(node); } this.updateTextAndValues(); if (!this.multiSelect) { this.comboService.isOpen$.next(false); } } onUnSelectRows(row) { if (this.displayType === 'LOOKUPLIST') { const { data } = row; this.comboService.unSelectItem(data); } else if (this.displayType === 'LOOKUPTREELIST') { const { node } = row; this.comboService.unSelectItem(node.data); this.selectChange.emit(node); } this.updateTextAndValues(); } onCheckAll(ev) { let state; let selections = []; if (this.displayType === 'LOOKUPTREELIST') { state = ev.checked; selections = this.treeCmpRef.state.rowNodes .filter(n => n.node.selectable === undefined || n.node.selectable ) .map(r => r.node.data); } else { state = ev; selections = this.data; } if (state) { this.comboService.selectAll(selections); } else { this.comboService.unSelectAll(selections); } this.updateTextAndValues(); } private updateTextAndValues() { this.selectedValues = this.comboService.getValue(this.idField); const _displayText = this.comboService.getValue(this.textField); this.onValueChange({ text: _displayText, value: this.selectedValues, selections: this.selections }); } onKeyup($event) { // console.log('key up', $event); } onKeydown($event: KeyboardEvent) { // console.log('key down', $event); if ($event.code === 'Tab') { this.hide(false); } } onPageChanged(event) { if (this.uri) { this.getData(event).subscribe(data => this.comboService.loadLookUpDataTable(data, !!event.sortName)); } else { this.pageChanged.emit(event); } } onPageSizeChanged(event) { if (this.uri) { this.getData(event).subscribe(data => this.comboService.loadLookUpDataTable(data, !!event.sortName)); } else { this.pageSizeChanged.emit(event); } } onColumnSorted(event: { sortName: string; sortOrder: any }) { const { sortName, sortOrder } = { ...event }; this.getData({ sortName, sortOrder }, 'search').subscribe(data => { this.comboService.loadLookUpDataTable(data, true); }); } onClear() { this.ownSelections = []; if (this.isTree() && this.treeCmpRef) { this.treeCmpRef.clearAll(); } super.onClear(); } getData(event?: any, type = 'all') { event = event || {}; if (this._searchKeyWords) { event.search = { field: '*', value: this._searchKeyWords }; } const params = this.buildQueryParams(event, type); return this.comboService.getData(params); } /** 构选查询参数 */ private buildQueryParams(event?: any, type = 'all') { const params: any = {}; const searchParam = { category: type }; if (event) { if (event.pageInfo) { params['pageIndex'] = event.pageInfo.pageIndex; params['pageSize'] = event.pageInfo.pageSize; } if (event.search) { searchParam['searchField'] = event.search.field; searchParam['searchValue'] = event.search.value; } if (event.sortName) { searchParam['sortName'] = event.sortName; } if (event.sortOrder) { searchParam['sortOrder'] = event.sortOrder; } } params['searchValue'] = JSON.stringify(searchParam); if (this.customData) { params['customData'] = this.customData; } return params; } filterDataOnServer(value, field) { if (!this.isOpen) { return; } let search = { search: { field, value }}; if (value) { this._searchKeyWords = value; } else { this._searchKeyWords = ''; search = null; } const params = this.buildQueryParams(search, 'search' ); this.comboService.serachValue$.next(params); } onExpandNode($event: TreeNode) { } }