import { Injectable, Injector } from '@angular/core'; import { BehaviorSubject, Subject, Observable, of } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { debounceTime, map, switchMap, catchError, tap, delay } from 'rxjs/operators'; import { LoadingService, LoadingComponent } from '@farris/ui-loading'; import { LookupUtils, ServerSideToken } from '@farris/ui-lookup'; import { ComboServerSideToken, ComboHttpService } from './http/ComboHttpService'; import { NormalObject } from './combo.interface'; @Injectable() export class ComboService { selections$ = new Subject(); isOpen$ = new BehaviorSubject(false); data$ = new BehaviorSubject(''); serachValue$ = new Subject(); loadSuccess$ = new Subject(); treeInfo$ = new BehaviorSubject(null); selections: NormalObject[]; idField: string; valueField: string; textField: string; multiSelect: boolean; displayType = 'LIST'; separator = ','; _uri: string; get uri() { return this._uri; } set uri(val: string) { this._uri = val; this.data$.next([]); } selectedValues = ''; pageInfo: any; treeInfo: any; columns: NormalObject[] = []; context: any; remoteSearch = true; panelElement: any = null; treeSearchHandler: any = null; // 树帮助加载设置 private treeloadconfig = null; private _data: NormalObject[] = []; private loading: LoadingComponent; private lookupUtils: LookupUtils; private comboHttp: ComboHttpService; get data(): NormalObject[] { return this._data; } set data(value: NormalObject[]) { this._data = value || []; if (Array.isArray(value)) { this.data$.next(value); } } constructor(public http: HttpClient, public loadingService: LoadingService, private injector: Injector) { this.serachValue$.pipe(debounceTime(300)).subscribe(value => { if (!this.remoteSearch) { this.filterData(value, this.textField); } else { this.filterDataOnServer(value); } }); } injectService() { if (this.injector && !this.comboHttp) { this.lookupUtils = this.injector.get(LookupUtils, null); if (this.displayType.indexOf('LOOKUP') > -1) { this.comboHttp = this.injector.get(ServerSideToken, null); } else { this.comboHttp = this.injector.get(ComboServerSideToken, null); } } } toBoolean(value: any): boolean { return value != null && `${value}` !== 'false'; } selectItem(data: any, index?: number, emitEvent = true) { if (!this.multiSelect) { this.selections = []; } if (Array.isArray(data)) { data.forEach(n => { if (this.selections.findIndex(s => s[this.idField] === n[this.idField]) === -1) { this.selections.push(n); } }); } else { if (this.selections.findIndex(s => s[this.idField] === data[this.idField]) === -1) { this.selections.push(data); } } if (emitEvent) { this.selections$.next({action: 'clicked'}); } } unSelectItem(data: any) { // console.log(data); this.selections = this.selections.filter(item => { // return item[this.idField] !== data[this.idField]; return JSON.stringify(item) !== JSON.stringify(data); }); this.selections$.next({action: 'clicked'}); } selectAll(datas) { (datas || []).forEach(n => { if (!this.selections.find(i => i[this.idField] === n[this.idField])) { this.selections.push(n); } }); // this.selections = datas; this.selections$.next({action: 'clicked'}); } unSelectAll(datas) { // this.selections = []; datas = datas || []; this.selections = (this.selections || []).filter(n => datas.findIndex(i => i[this.idField] === n[this.idField]) === -1 ); this.selections$.next({action: 'clicked'}); } isSelect(id: any) { if (this.selections && this.selections.length) { return this.selections.find(item => item[this.idField] === id) !== undefined; } return false; } loadData(data: any, selectValues = '', callback) { if (data) { if (selectValues === null || selectValues === undefined) { selectValues = ''; } if (typeof selectValues === 'boolean') { selectValues = '' + selectValues; } // this.data$.next(data); if (selectValues) { let vals = [(selectValues + '')]; if (this.multiSelect) { vals = (selectValues + '').split(this.separator); } let selectedItems = vals.map(val => { return callback(data, val); }); selectedItems = selectedItems.filter(el => el); this.selections = selectedItems; } else { this.selections = []; } this.selections$.next({action: 'initData'}); } } filterDataOnServer(params) { this.getData(params).subscribe(r => { this.closeLoading(); this.loadingService.clearAll(); if (r && r.items) { switch (this.displayType) { case 'LOOKUPLIST': { this.loadLookUpDataTable(r, true); break; } case 'LOOKUPTREELIST': { this.loadLookUpDataTree(r); break; } } } else { this.data$.next([]); } }); } // 客户端过滤 filterData(val: string, field: any = 'text') { if (val) { let data = []; if (this.displayType === 'LOOKUPLIST' || this.displayType === 'LIST') { data = this.data.filter(item => { return String(this.getValueByObj(field, item)).indexOf(val) > -1; }); } // const data = this.data // ? this.data.filter(item => { // if (this.getValueByObj(filed, item)) { // return String(this.getValueByObj(filed, item)).indexOf(val) > -1; // } else if (item.data && this.getValueByObj(filed, item.data)) { // return String(this.getValueByObj(filed, item.data)).indexOf(val) > -1; // } // }) // : []; this.data$.next(data); } else { this.data$.next(this.data); } } getSelections() { return this.selections; } clearSelections() { this.selections = []; } getValue(prop: string, selections?: any): string { selections = selections ? selections : this.selections; if (selections && selections.length) { const tmp = selections.map(item => { return this.getValueByObj(prop, item); }); if (tmp && (tmp.length > 1 || tmp.length === 0)) { return tmp.join(this.separator); } else { return tmp[0]; } } return ''; } getValueByObj(field: string, data: any) { if (!data) { return ''; } let resultVal = ''; if (field.indexOf('.') === -1) { if (data.hasOwnProperty(field)) { resultVal = data[field]; } else { console.log(`%cError: The %c"${field}"%c is not in `, 'color: #bb0000;font-weight: bold;', 'color: red;font-style: italic', 'color: #bb0000;font-weight: bold;', data); resultVal = null; } } else { resultVal = field.split('.').reduce((obj, key) => { if (obj) { return obj[key]; } else { console.log(`%cError: The %c"${key}"%c is not in `, 'color: #bb0000;font-weight: bold', 'color: red;font-style: italic', 'color: #bb0000;font-weight: bold;', obj); return null; } }, data); } return resultVal; } initData(params: any = {}, method = 'get', selectedIds = '') { switch (this.displayType) { case 'TreeList': case 'LIST': { if (params.data) { params = params.data; } this.getData(params, method).subscribe(d => { if (this.displayType === 'TreeList') { this.loadDataTree(d); } else { this.loadDataTable(d); } this.loadSuccess$.next(true); }); break; } case 'LOOKUPLIST': case 'LOOKUPTREELIST': { this.loadLookupData(params, selectedIds, 'get', this.displayType === 'LOOKUPTREELIST'); break; } } return this.loadSuccess$; } private loadLookupData(params: any, selectedIds, method = 'get', isTree = false) { const { data, enableFullTree, loadTreeDataType } = params; if (data) { params = { customData: data }; } if (this.displayType === 'LOOKUPTREELIST') { params.enableFullTree = enableFullTree; params.loadTreeDataType = 'loadall'; // loadTreeDataType; params.searchValue = '{"category":"all"}'; this.treeloadconfig = { enableFullTree, loadTreeDataType }; } this.getData(params, method).pipe( switchMap( (data) => { if (selectedIds) { return this.getSelectedItems(selectedIds).pipe( map(d => { if (d && d.items) { data.selectedItems = isTree ? d.items.map(n => n.data) : d.items; } else { if (Array.isArray(d)) { data.selectedItems = (selectedIds + '').split(this.separator).map(val => { if (isTree) { return this.treeNodeToFlatData(d, val, this.idField); } else { return d.find(n => n[this.idField] + '' == val || n[this.textField] == val); } }); } } return data; }), catchError(() => { return of(data); }) ); } return of(data); }) ).subscribe(data => { this.loadingService.clearAll(); if (data) { if (isTree) { this.loadLookUpDataTree(data); } else { this.loadLookUpDataTable(data); } } this.loadSuccess$.next(true); }); } getSelectedItems(selIds) { const searchParam = { category: 'fav', favoriteIds: ('' + selIds).split(this.separator) }; const p = {searchValue: JSON.stringify(searchParam), enableFullTree: false, loadTreeDataType: 'default'}; return this.getData(p); } getData(params = {}, method = 'get'): Observable { if (this.uri) { // this.data = []; this.showLoading(); if (this.comboHttp) { if (this.context) { this.comboHttp.context = this.context; } return this.comboHttp.getData(this.uri, params, method).pipe( tap(() => { this.closeLoading(); }), ); } else { return this.http.request(method, this.uri, params).pipe( tap(() => { this.closeLoading(); }), ); } } else { if (this.data) { return of(this.data).pipe(delay(10)); } else { return of([]).pipe(delay(10)); } } } loadDataTable(data: any) { if (data instanceof Array) { this.data = [...data]; } else { this.data = data ? data.returnValue : []; } this.loadData(this.data, this.selectedValues, (dataArr, val) => { return dataArr.find(d => d[this.idField] + '' == val || d[this.textField] == val); }); this.closeLoading(); } loadDataTree(data: any) { if (data instanceof Array) { this.data = data; } else { this.data = data ? data.returnValue : []; } this.loadData(this.data, this.selectedValues, (dataArr, val) => { return eachData(dataArr, val, this.idField); function eachData(paramData, paramVal, idField) { let rtnData: any = ''; paramData.find(d => { if (d.data[idField] == paramVal) { rtnData = d.data; return true; } else if (d.children && d.children.length) { rtnData = eachData(d.children, paramVal, idField); } else { return false; } }); return rtnData; } }); this.closeLoading(); } loadLookUpDataTable(resData: any, sortable = false) { this.closeLoading(); if (typeof resData === 'object') { if (resData.returnValue) { resData = resData.returnValue; } if (!sortable && resData.columns) { this.columns = resData.columns; } if (resData.pageInfo) { this.pageInfo = resData.pageInfo; this.pageInfo.total = resData.total ? resData.total : 0; } if ( resData.items) { this.data = resData.items; } if (resData.selectedItems) { this.selections = resData.selectedItems || []; } } if (this.selections) { const ids = this.selections.map(n => n[this.idField]).join(this.separator); if (ids !== this.selectedValues) { this.selectedValues = ids; } } this.loadData(this.data, this.selectedValues, (dataArr, val) => { let isMaped = dataArr.find(d => d[this.idField] + '' == val); if (this.selections) { isMaped = !isMaped ? this.selections.find(d => d[this.idField] + '' == val) : isMaped; } return isMaped; }); } private checkNodeCanBeSelect(nodes, allData = true) { if (nodes && nodes.length) { return nodes.map((node: any) => { if (node.hasOwnProperty('addtional')) { node.selectable = !node['addtional']; } if (node.children && node.children.length) { this.checkNodeCanBeSelect(node.children, allData); } else { if (allData) { node.leaf = true; } } return node; }); } return nodes; } loadLookUpDataTree(resData: any) { this.closeLoading(); if (!resData) { return; } if (resData instanceof Array) { this.data = resData; } else { if (resData.returnValue) { resData = resData.returnValue; } this.columns = resData.columns; this.treeInfo = resData.treeInfo; this.treeInfo$.next(this.treeInfo); if (resData.selectedItems) { this.selections = resData.selectedItems || []; } if (this.treeInfo && !this.treeInfo['treeDataIsInit']) { if (this.treeInfo.layerType.toLowerCase() === 'pathcode') { this.data = this.lookupUtils.makeTree(resData.items, this.treeInfo); } else { this.data = this.lookupUtils.makeTreeWithParentID( resData.items, '', `${this.treeInfo.dataField}.${this.treeInfo.parentField}`, this.idField ); } } else if (resData.items) { // this.data = resData.items; const isLoadAllTreeData = () => { if (this.treeloadconfig.loadTreeDataType === 'default') { return this.treeInfo.loadDataType === 'all'; } else { return this.treeloadconfig.loadTreeDataType === 'loadall'; } }; this.data = this.checkNodeCanBeSelect(resData.items); } } this.loadData(this.data, this.selectedValues, (dataArr, val) => { return this.treeNodeToFlatData(dataArr, val, this.idField); }); } treeNodeToFlatData(paramData, paramVal, idField) { let rtnData: any = ''; paramData.find(d => { if ((d.data && d.data[idField] == paramVal) || d[idField] == paramVal) { rtnData = d.data; return true; } else if (d.children && d.children.length) { rtnData = this.treeNodeToFlatData(d.children, paramVal, idField); return rtnData ? true : false; } else { return false; } }); return rtnData; } private showLoading() { this.loading = this.loadingService.show({ container: this.panelElement, delay: 100 }); } closeLoading() { if (this.loading) { this.loading.close(); this.loading = null; } } }