import { ICodeListItem, ICodeListResult, IContext, IHttpResponse, IParam, ITreeModel, ITreeNodeModel, ITreeNodeRsModel, } from '@/core/interface'; import { deepCopy, HttpResponse, isEmpty } from '@/core/utils'; import { ControlVOBase } from '../control-vo'; import { CtrlExServiceBase } from './ctrl-ex-service-base'; /** * 树部件服务 * * @class TreeService */ class TreeService extends CtrlExServiceBase { /** * 节点分隔符 * * @private * @type {string} * @memberof TreeService */ private TREENODE_SEPARATOR = ';'; /** * Creates an instance of TreeService. * @param {IParam[]} controlVOTypes * @param {string} entityCodeName * @param {IParam} [opts] * @memberof TreeService */ constructor(controlVOTypes: IParam[], entityCodeName: string, opts?: IParam) { super(controlVOTypes, entityCodeName, opts); this.model = opts!.model; } /** * 获取节点数据 * * @param {IContext} context * @param {IParam} data * @return {*} * @memberof TreeService */ async getNodes(context: IContext, data: IParam): Promise> { let { srfparentkey, srfnodeid, srfnodefilter, query } = data; srfnodefilter = query ? query : srfnodefilter; const list: any[] = []; const filter: any = {}; const { treeNodes, rootVisible } = this.model; // 根节点 const rootNode = treeNodes.find((node: ITreeNodeModel) => { return node.rootNode; }) as ITreeNodeModel; // 处理是否显示根节点 if (!srfnodeid || Object.is(srfnodeid, '#')) { if (rootVisible) { await this.fillNodeData(rootNode, context, filter, list); return new HttpResponse(list); } else { srfnodeid = rootNode.nodeType; } } const strTreeNodeId: string = srfnodeid; let strRealNodeId = ''; let strNodeType: string; if (Object.is(strTreeNodeId, rootNode.nodeType)) { strNodeType = rootNode.nodeType; if (srfparentkey) { strRealNodeId = srfparentkey; } } else { const nPos = strTreeNodeId.indexOf(this.TREENODE_SEPARATOR); if (nPos === -1) { return Promise.reject({ status: 500, data: { title: '失败', message: `树节点${strTreeNodeId}标识无效` }, }); } strNodeType = strTreeNodeId.substring(0, nPos); strRealNodeId = strTreeNodeId.substring(nPos + 1); } // 处理过滤参数 Object.assign(filter, { srfnodefilter: srfnodefilter, strRealNodeId: strRealNodeId, srfnodeid: srfnodeid, strNodeType: strNodeType, viewParams: deepCopy(data).viewParams, srfparentdata: deepCopy(data).parentData, }); // 分解节点标识 const nodeid: string[] = strRealNodeId.split(this.TREENODE_SEPARATOR); for (let i = 0; i < nodeid.length; i++) { switch (i) { case 0: Object.assign(filter, { nodeid: nodeid[0] }); break; case 1: Object.assign(filter, { nodeid2: nodeid[1] }); break; case 2: Object.assign(filter, { nodeid3: nodeid[2] }); break; case 3: Object.assign(filter, { nodeid4: nodeid[3] }); break; default: break; } } // 根据节点标识填充节点 const node = treeNodes.find((_node: ITreeNodeModel) => { return _node.nodeType == strNodeType; }); if (node) { await this.fillChildNodes(node, context, filter, list); return new HttpResponse(list); } else { return new HttpResponse( { title: '失败', message: `树节点${strTreeNodeId}标识无效` }, null, 500 ); } } /** * 根据节点关系填充所有子节点 * * @private * @param {ITreeNodeModel} node * @param {*} [context={}] * @param {*} filter * @param {any[]} list * @return {*} {Promise} * @memberof TreeService */ private async fillChildNodes( node: ITreeNodeModel, context: any = {}, filter: any, list: any[] ): Promise { // 过滤出父节点是该节点的节点关系集合 const { treeNodes, treeNodeRSs } = this.model; if (treeNodeRSs.length > 0) { const nodeRSs = treeNodeRSs.filter((nodeRS: ITreeNodeRsModel) => { if (nodeRS.parentPSDETreeNodeId !== node.id) { return false; } // 搜索模式 1 有搜索时启用, 2 无搜索时启用, 3 全部启用 switch (nodeRS.searchMode) { case 1: return !isEmpty(filter.srfnodefilter); case 2: return isEmpty(filter.srfnodefilter); case 3: return true; default: return false; } }); // 填充对应节点关系的子节点 if (nodeRSs && nodeRSs.length > 0) { for (let i = 0, len = nodeRSs.length; i < len; i++) { const rsNavContext: any = nodeRSs[i].navigateContext; const rsNavParams: any = nodeRSs[i].navigateParams; const rsParams: any = nodeRSs[i].params; // 根据节点标识填充节点 const treeNode: any = treeNodes.find((_node: ITreeNodeModel) => { return nodeRSs[i].childDeTreeNodeId == _node.id; }); if (treeNode) { await this.fillNodeData( treeNode, context, filter, list, rsNavContext, rsNavParams, rsParams ); } } } } } /** * 填充节点数据 * * @private * @param {ITreeNodeModel} node * @param {IContext} context * @param {*} filter * @param {IParam[]} list * @param {IParam} [rsNavContext] * @param {IParam} [rsNavParams] * @param {IParam} [rsParams] * @return {*} {Promise} * @memberof TreeService */ private fillNodeData( node: ITreeNodeModel, context: IContext, filter: any, list: IParam[], rsNavContext?: IParam, rsNavParams?: IParam, rsParams?: IParam ): Promise { context = this.handleResNavContext(context, filter, rsNavContext); filter = this.handleResNavParams(context, filter, rsNavParams, rsParams); return new Promise((resolve: any, reject: any) => { // 静态节点 if (node.treeNodeType == 'STATIC') { // 快速搜索过滤 if ( node.enableQuickSearch && filter.srfnodefilter && !Object.is(filter.srfnodefilter, '') && node.text ?.toUpperCase() .indexOf(filter.srfnodefilter.toUpperCase()) == -1 ) { resolve(list); return; } const treeNode: any = { allowDrag: node.allowDrag, allowDrop: node.allowDrop, allowEditText: node.allowEditText, allowOrder: node.allowOrder, appendCaption: node.appendCaption, counterId: node.counterId, class: node.cssName, text: App.ts(node.lanResTag as string, node.text), textFormat: node.textFormat, tooltip: App.ts(node.tooltipLanResTag as string, node.tooltip), nodeType: node.nodeType, srfappctx: context, srfmajortext: node.text, enableCheck: node.enableCheck, disabled: node.disableSelect, expanded: node.expanded || filter.isAutoExpand, isLeaf: node.leaf, selected: node.selected, navFilter: node.navFilter, cssClass: node.cssClass, imagePath: node.imagePath, counterMode: node.counterMode, contextMenus: node.contextMenus, }; // 删除无用属性 let strNodeId: string = node.nodeType; if (isEmpty(node.nodeValue)) { Object.assign(treeNode, { srfkey: node.nodeValue }); strNodeId += this.TREENODE_SEPARATOR + node.nodeValue; if (node.appendPNodeId) { strNodeId += this.TREENODE_SEPARATOR + filter.strRealNodeId; } } else { // 没有指定节点值,直接使用父节点值 Object.assign(treeNode, { srfkey: filter.strRealNodeId }); strNodeId += this.TREENODE_SEPARATOR + filter.strRealNodeId; } Object.assign(treeNode, { id: strNodeId }); Object.assign(treeNode, { nodeid: treeNode.srfkey, nodeid2: filter.strRealNodeId, }); list.push(treeNode); resolve(list); } else if (node.treeNodeType == 'CODELIST') { // 代码表节点 if (node.codeListTag) { App.getAppCodeListHelper() .getCodeListItems(node.codeListTag, context) .then((codeListResult: ICodeListResult) => { if (codeListResult.ok) { const treeNodes: any[] = this.transFormCodeListData( codeListResult.data, context, filter, node ); list.push(...treeNodes); resolve(list); } resolve([]); }) .catch(() => { resolve([]); }); } else { resolve([]); } } else if (node.treeNodeType == 'DE' && node.entityCodeName) { // 实体节点 let bFirst = true; const searchFilter: any = {}; const { treeNodeRSs, treeNodes } = this.model; if (treeNodeRSs && treeNodeRSs.length > 0) { treeNodeRSs.forEach((nodeRs: ITreeNodeRsModel) => { if (nodeRs.childDeTreeNodeId == node.id) { const pickupField: string = nodeRs.parentFilter ? nodeRs.parentFilter.toLowerCase() : nodeRs.parentPSDER1N && nodeRs.parentPSAppDEField ? nodeRs.parentPSAppDEField.toLowerCase() : ''; if (pickupField && pickupField !== '') { const tempNode = treeNodes.find((_node: ITreeNodeModel) => { return nodeRs.parentPSDETreeNodeId == _node.id; }); if ( tempNode && Object.is(filter.strNodeType, tempNode.nodeType) ) { Object.assign(searchFilter, { [`n_${pickupField}_eq`]: filter[ `nodeid${ nodeRs.parentValueLevel > 1 ? nodeRs.parentValueLevel : '' }` ], }); } } } }); } Object.assign(searchFilter, { total: false }); if (node.enableQuickSearch) { Object.assign(searchFilter, { query: filter.srfnodefilter }); } try { this.searchNodeData(node, context, searchFilter, filter).then( (records: any) => { if (records && records.length) { records.forEach((entity: any) => { const treeNode: any = { appendCaption: node.appendCaption, appEntityCodeName: node.entityCodeName, allowDrag: node.allowDrag, allowDrop: node.allowDrop, allowEditText: node.allowEditText, allowOrder: node.allowOrder, curData: entity, counterId: node.counterId, class: node.cssName, counterMode: node.counterMode, disabled: node.disableSelect, enableCheck: node.enableCheck, expanded: node.expanded ? node.expandFirstOnly ? bFirst : true : filter.isAutoExpand, textFormat: node.textFormat, selected: node.selected, isLeaf: node.leaf, navFilter: node.navFilter, nodeType: node.nodeType, contextMenus: node.contextMenus, }; const strId: string = entity.id ? entity.id : entity[(node.keyPSAppDEField as string).toLowerCase()]; const strText: string = entity.text ? entity.text : entity[(node.majorPSAppDEField as string).toLowerCase()]; // 用于存储节点自身父值 Object.assign(treeNode, { srfparentdename: filter.strParentEntityname, srfparentkey: filter.strRealNodeId, }); // 用于选中导航 const tempContext = deepCopy(context); Object.assign(tempContext, { srfparentdename: node.entityCodeName?.toLowerCase(), srfparentkey: strId, [(node.entityCodeName as string).toLowerCase()]: strId, }); Object.assign(treeNode, { srfappctx: tempContext, [(node.entityCodeName as string).toLowerCase()]: strId, srfkey: strId, text: strText, srfmajortext: strText, }); let strNodeId: string = node.nodeType; strNodeId += this.TREENODE_SEPARATOR + strId; if (node.appendPNodeId) { strNodeId += this.TREENODE_SEPARATOR + filter.realnodeid; } Object.assign(treeNode, { id: strNodeId }); if (entity.icon) { Object.assign(treeNode, { imagePath: entity.icon }); } else { Object.assign(treeNode, { cssClass: node.cssClass, imagePath: node.imagePath, }); } if (entity.leafflag) { const strLeafFlag: string = entity.leafflag .toString() .toLowerCase(); if ( Object.is(strLeafFlag, '1') || Object.is(strLeafFlag, 'true') ) { Object.assign(treeNode, { isLeaf: true }); } else { Object.assign(treeNode, { isLeaf: false }); } } const nodeDataItems: any[] = node.deTreeNodeDataItems || []; if (nodeDataItems.length > 0) { nodeDataItems.forEach((item: any) => { const name = item.name.toLowerCase(); if (item.fieldCodeName) { Object.assign(treeNode, { [name]: entity[item.fieldCodeName.toLowerCase()], }); } if (Object.is('text', name) && item.customCode) { Object.assign(treeNode, { textCustomCode: true, textScriptCode: item.scriptCode, }); } if (Object.is('icon', name) && item.customCode) { Object.assign(treeNode, { iconCustomCode: true, iconScriptCode: item.scriptCode, }); } }); } if (entity.counterid) { Object.assign(treeNode, { counterId: entity.counterid }); } Object.assign(treeNode, { nodeid: treeNode.srfkey, nodeid2: filter.strRealNodeId, }); list.push(treeNode); resolve(list); bFirst = false; }); } else { resolve(list); } } ); } catch (error: any) { console.error(error); } } else { resolve(list); } }); } /** * 转换代码表数据为树节点数据 * * @private * @param {ICodeListItem[]} codeItems * @param {*} context * @param {*} filter * @param {ITreeNodeModel} node * @return {*} {any[]} * @memberof TreeService */ private transFormCodeListData( codeItems: ICodeListItem[], context: any, filter: any, node: ITreeNodeModel ): any[] { const treeNodes: any[] = []; let bFirst = true; if (codeItems.length) { for (const item of codeItems) { const treeNode: any = { srfappctx: context, srfmajortext: item.text, curData: item, text: item.text, srfkey: item.value, nodeType: node.nodeType, appendCaption: node.appendCaption, allowDrag: node.allowDrag, allowDrog: node.allowDrop, allowEditText: node.allowEditText, allowOrder: node.allowOrder, class: node.cssName, counterId: node.counterId, counterMode: node.counterMode, disabled: node.disableSelect, enableCheck: node.enableCheck, expanded: node.expanded ? node.expandFirstOnly ? bFirst : true : filter.isAutoExpand, cssClass: node.cssClass, imagePath: node.imagePath, selected: node.selected, navFilter: node.navFilter, nodeid: item.value, nodeid2: filter.strRealNodeId, }; // 快速搜索过滤 if (node.enableQuickSearch && filter.srfnodefilter) { const pattern = new RegExp(`${node.text}`, 'i'); if (filter.srfnodefilter.search(pattern) === -1) { continue; } } let strNodeId = `${node.nodeType}${this.TREENODE_SEPARATOR}${item.value}`; if (node.appendPNodeId) { strNodeId += `${this.TREENODE_SEPARATOR}${filter.realnodeid}`; } Object.assign(treeNode, { id: strNodeId }); if ((item as any).items?.length > 0) { const children = this.transFormCodeListData( (item as any).items, context, filter, node ); Object.assign(treeNode, { isLeaf: false, children: children }); } else { Object.assign(treeNode, { isLeaf: true }); } treeNodes.push(treeNode); } } bFirst = false; return treeNodes; } /** * 查询节点数据 * * @private * @param {ITreeNodeModel} node * @param {IContext} context * @param {*} searchFilter * @param {*} filter * @return {*} {Promise} * @memberof TreeService */ private async searchNodeData( node: ITreeNodeModel, context: IContext, searchFilter: any, filter: any ): Promise { if (filter.viewParams) { Object.assign(searchFilter, filter.viewParams); } if (!searchFilter.page) { Object.assign(searchFilter, { page: 0 }); } if (!searchFilter.size) { Object.assign(searchFilter, { size: 1000 }); } if (context && context.srfparentdename) { Object.assign(searchFilter, { srfparentdename: context.srfparentdename }); } if (context && context.srfparentkey) { Object.assign(searchFilter, { srfparentkey: context.srfparentkey }); } if (node.sortPSAppDEField) { Object.assign(searchFilter, { sort: `${node.sortPSAppDEField.toLowerCase()},${ node.sortDir ? node.sortDir : 'asc' }`, }); } const result: any = []; if (node.entityCodeName && node.appDeDataSet) { const appEntityService = await App.getDataService( node.entityCodeName, context ); if ( appEntityService && appEntityService[node.appDeDataSet] instanceof Function ) { try { const response: IHttpResponse = await appEntityService[ node.appDeDataSet ](context, searchFilter, false); if (response.success) { if (response.data instanceof Array) { response.data.forEach((item: any, index: number) => { result.push(this.newControlVO(item, `${node.controlVoName}`)); }); } else { result.push( this.newControlVO(response.data, `${node.controlVoName}`) ); } } return result; } catch (error) { return result; } } } else { return result; } } /** * 处理关系导航上下文 * * @private * @param {*} context * @param {*} filter * @param {*} resNavContext * @return {*} * @memberof TreeService */ private handleResNavContext(context: any, filter: any, resNavContext: any) { if (resNavContext && Object.keys(resNavContext).length > 0) { const tempContextData: any = deepCopy(context); let tempViewParams: any = {}; if (filter && filter.viewparams) { tempViewParams = filter.viewparams; } Object.keys(resNavContext).forEach((item: any) => { const curDataObj: any = resNavContext[item]; this.handleCustomDataLogic( context, tempViewParams, curDataObj, tempContextData, item, filter?.srfparentdata ); }); return tempContextData; } else { return context; } } /** * 处理关系导航参数 * * @private * @param {*} context * @param {*} filter * @param {*} resNavParams * @param {*} resParams * @return {*} * @memberof TreeService */ private handleResNavParams( context: any, filter: any, resNavParams: any, resParams: any ) { if ( (resNavParams && Object.keys(resNavParams).length > 0) || (resParams && Object.keys(resParams).length > 0) ) { let tempViewParamData: any = {}; let tempViewParams: any = {}; if (filter && filter.viewParams) { tempViewParams = filter.viewParams; tempViewParamData = deepCopy(filter.viewParams); } if (resNavParams && Object.keys(resNavParams).length > 0) { Object.keys(resNavParams).forEach((item: any) => { const curDataObj: any = resNavParams[item]; this.handleCustomDataLogic( context, tempViewParams, curDataObj, tempViewParamData, item, filter?.srfparentdata ); }); } if (resParams && Object.keys(resParams).length > 0) { Object.keys(resParams).forEach((item: any) => { const curDataObj: any = resParams[item]; tempViewParamData[item.toLowerCase()] = curDataObj; }); } Object.assign(filter, { viewParams: tempViewParamData }); return filter; } else { return filter; } } /** * 处理自定义节点关系导航数据 * * @private * @param {*} context * @param {*} viewParams * @param {*} curNavData * @param {*} tempData * @param {string} item * @param {*} [parentData] * @memberof TreeService */ private handleCustomDataLogic( context: any, viewParams: any, curNavData: any, tempData: any, item: string, parentData?: any ) { if (curNavData && curNavData.startsWith('%') && curNavData.endsWith('%')) { const param = curNavData.slice(1, curNavData.length - 1)?.toLowerCase(); // 先从导航上下文取数,没有再从导航参数(URL)取数,如果导航上下文和导航参数都没有则为null if (parentData && param && parentData[param] != null) { Object.defineProperty(tempData, item.toLowerCase(), { value: parentData[param], writable: true, enumerable: true, configurable: true, }); } else if (context[param] != null) { Object.defineProperty(tempData, item.toLowerCase(), { value: context[param], writable: true, enumerable: true, configurable: true, }); } else { if (viewParams[param] != null) { Object.defineProperty(tempData, item.toLowerCase(), { value: viewParams[param], writable: true, enumerable: true, configurable: true, }); } else { Object.defineProperty(tempData, item.toLowerCase(), { value: null, writable: true, enumerable: true, configurable: true, }); } } } else { // 直接值 if (isEmpty(curNavData.value)) { Object.defineProperty(tempData, item.toLowerCase(), { value: null, writable: true, enumerable: true, configurable: true, }); } else { Object.defineProperty(tempData, item.toLowerCase(), { value: curNavData.value, writable: true, enumerable: true, configurable: true, }); } } } } export default TreeService;