import { EntityCache, EntityDBService, HttpResponse, IAbility, IContext, IEntityBase, IHttpResponse, IParam, IUIActionResult, } from '@/core'; import { Http } from '@/http'; import { ascSort, notNilEmpty } from 'qx-util'; import { clone, equals, isEmpty, where } from 'ramda'; /** * 实体服务基类 * @export * @class DataServiceBase */ export class DataServiceBase { /** * 应用上下文 * * @protected * @type {*} * @memberof DataServiceBase */ protected context: any; /** * 应用实体名 * * @protected * @type {string} * @memberof DataServiceBase */ protected appEntityName = ''; /** * 应用实体代码名 * * @protected * @type {string} * @memberof DataServiceBase */ protected appEntityCodeName = ''; /** * 应用实体代码名(复数形式) * * @protected * @type {string} * @memberof DataServiceBase */ protected appEntityCodeNames = ''; /** * 应用实体主键属性代码名 * * @protected * @type {string} * @memberof DataServiceBase */ protected appEntityKeyCodeName = ''; /** * 应用实体主信息属性代码名 * * @protected * @type {string} * @memberof DataServiceBase */ protected appEntityTextCodeName = ''; /** * 系统名称 * * @protected * @memberof DataServiceBase */ protected systemName = ''; /** * 应用名称 * * @protected * @memberof DataServiceBase */ protected appName = ''; /** * HTTP服务类 * * @protected * @memberof DataServiceBase */ protected http = Http.getInstance(); /** * 根据关系,select查询时填充额外条件。 * * @protected * @type {IParam} * @memberof DataServiceBase */ protected selectContextParam: IParam = {}; /** * 存储模式 * * @type {(0 | 1 | 3 | 4)} 无本地存储 | 仅本地存储 | 本地及远程存储 | DTO无存储 */ readonly storageMode: number = 0; /** * 是否本地模式 * * @readonly * @type {boolean} * @memberof DataServiceBase */ get isLocalStore(): boolean { return this.storageMode === 1; } /** * indexDB数据库实例 * * @protected * @type {EntityDBService} * @memberof DataServiceBase */ protected db!: EntityDBService; /** * 数据缓存 * * @protected * @type {EntityCache} * @memberof DataBaseService */ protected cache: EntityCache = new EntityCache(); /** * Creates an instance of DataServiceBase. * @param {IParam} [opts] 应用上下文 * @param {string} [dbName] 本地存储表 * @param {(0 | 1 | 3)} [storageMode] 存储模式 * @memberof DataServiceBase */ constructor(opts: IParam = {}, dbName?: string, storageMode?: 0 | 1 | 3) { this.context = opts; this.initBasicData(); if (this.isLocalStore) { this.db = new EntityDBService( this.appEntityCodeName, (data: IParam): T => { return this.newEntity(data); }, (entity: T): any => { return this.filterEntityData(entity); } ); } } /** * 规范化数据 * * @protected * @param {IParam} data * @param {IContext} [context] * @return {*} {T} * @memberof DataServiceBase */ protected newEntity(data: IParam, context?: IContext): T { throw new Error('Method is not implements'); } /** * 过滤当前实体服务,标准接口数据 * * @return {*} {*} * @memberof DataBaseService */ protected filterEntityData(entity: T): any { throw new Error('Method is not implements'); } /** * 初始化基础数据 * * @protected * @memberof DataServiceBase */ protected initBasicData() {} /** * 执行行为之前 * * @protected * @param {IParam} context 应用上下文 * @param {IParam} data 视图参数 * @param {string} method 方法名 * @memberof DataServiceBase */ protected beforeExecuteAction(context: IParam, data: IParam, method: string) { if (!method) return; switch (method) { // 新建删除接口无效属性 case 'Create': if (!data.srffrontuf || data.srffrontuf != 1) { data[this.appEntityCodeName] = null; } if (data.srffrontuf != null) { delete data.srffrontuf; } break; // 加载草稿删除接口无效属性 case 'GetDraft': delete data[this.appEntityCodeName]; if (this.appEntityKeyCodeName) { delete data[this.appEntityKeyCodeName]; } break; default: break; } } /** * 执行行为之后 * * @protected * @param {IParam} context 应用上下文 * @param {IParam} data 视图参数 * @param {string} method 方法名 * @memberof DataServiceBase */ protected afterExecuteAction(context: IParam, data: IParam, method: string) { if (!method) return; } /** * 添加本地 * * @param {IContext} [context={}] * @param {T} data * @return {*} * @memberof DataServiceBase */ public async addLocal(context: IContext = {}, data: IParam) { try { if (this.isLocalStore) { return this.db.create(context, this.newEntity(data, context)); } else { return this.cache.add(context, this.newEntity(data, context)); } } catch (error) { throw error; } } /** * 新建数据 * * @param {IContext} [context={}] * @param {(IParam)} data * @return {*} {Promise} * @memberof DataServiceBase */ public async Create( context: IContext = {}, data: IParam ): Promise { return this.CreateTemp(context, data); } /** * 删除数据 * * @param {IContext} [context={}] * @param {(IParam)} data * @return {*} {Promise} * @memberof DataServiceBase */ public async Remove( context: IContext = {}, data: IParam ): Promise { return this.RemoveTemp(context, data); } /** * 更新数据 * * @param {IContext} [context={}] * @param {(IParam)} data * @return {*} {Promise} * @memberof DataServiceBase */ public async Update( context: IContext = {}, data: IParam ): Promise { return this.UpdateTemp(context, data); } /** * 获取数据 * * @param {IContext} [context={}] * @param {(IParam)} data * @return {*} {Promise} * @memberof DataServiceBase */ public async Get( context: IContext = {}, data: IParam ): Promise { return this.GetTemp(context, data); } /** * 获取草稿数据 * * @param {IContext} [context={}] * @param {(IParam | IParam[])} data * @return {*} {Promise} * @memberof DataServiceBase */ public async GetDraft( context: IContext = {}, data: IParam ): Promise { return this.GetDraftTemp(context, data); } /** * 新建本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async CreateTemp( context: IContext = {}, data: IParam ): Promise { try { await this.beforeExecuteAction(context, data, 'CreateTemp'); const tempData = await this.createLocal(context, data); await this.afterExecuteAction(context, tempData, 'CreateTemp'); return new HttpResponse(tempData); } catch (err) { return new HttpResponse(err, null, 500); } } /** * 获取本地数据新建默认值 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async GetDraftTemp( context: IContext = {}, data: IParam ): Promise { try { await this.beforeExecuteAction(context, data, 'GetDraftTemp'); const tempData = await this.getDraftLocal(context, data); await this.afterExecuteAction(context, tempData, 'GetDraftTemp'); if (tempData) { return new HttpResponse(tempData); } return new HttpResponse(data, null, 500); } catch (err) { return new HttpResponse(err, null, 500); } } /** * 删除本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async RemoveTemp( context: IContext = {}, data: IParam = {} ): Promise { try { await this.beforeExecuteAction(context, data, 'RemoveTemp'); let key = null; if (data) { key = data[this.appEntityKeyCodeName.toLowerCase()]; } if (!key && context) { key = context[this.appEntityCodeName.toLowerCase()]; } const tempData = await this.removeLocal(context, key); await this.afterExecuteAction(context, tempData, 'RemoveTemp'); if (tempData) { return new HttpResponse(tempData); } return new HttpResponse(data, null, 500); } catch (err) { return new HttpResponse(err, null, 500); } } /** * 更新本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async UpdateTemp( context: IContext = {}, data: IParam ): Promise { try { await this.beforeExecuteAction(context, data, 'UpdateTemp'); const tempData = await this.updateLocal(context, data); await this.afterExecuteAction(context, tempData, 'UpdateTemp'); if (tempData) { return new HttpResponse(tempData); } return new HttpResponse(data, null, 500); } catch (err) { return new HttpResponse(err, null, 500); } } /** * 获取本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async GetTemp( context: IContext = {}, data: IParam = {} ): Promise { try { await this.beforeExecuteAction(context, data, 'UpdateTemp'); let key = null; if (data) { key = data[this.appEntityKeyCodeName.toLowerCase()]; } if (!key && context) { key = context[this.appEntityCodeName.toLowerCase()]; } const tempData = await this.getLocal(context, key); await this.afterExecuteAction(context, tempData, 'UpdateTemp'); if (tempData) { return new HttpResponse(tempData); } return new HttpResponse(data, null, 500); } catch (err) { return new HttpResponse(err, null, 500); } } /** * 新建本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ public async createLocal(context: IContext = {}, data: IParam): Promise { try { data.srfuf = 0; const tempData = await this.addLocal(context, data); return tempData; } catch (error) { throw error; } } /** * 查找本地数据 * * @param {IContext} [context={}] * @param {string} srfKey * @return {*} {Promise} * @memberof DataServiceBase */ public async getLocal(context: IContext = {}, srfKey: string): Promise { try { if (this.isLocalStore) { return this.db.get(context, srfKey); } return this.cache.get(context, srfKey)!; } catch (error) { throw error; } } /** * 批量获取临时数据[打包包数据] * * @public * @param {IContext} context * @param {IParams} [params] * @param {string} [dataSet] * @return {*} {(Promise)} * @memberof DataBaseService */ public async getLocals( context: IContext, params?: IParam, dataSet?: string ): Promise { let items: T[] = []; const _this: any = this; if (_this[dataSet!]) { const res = await _this[dataSet!](context, params); if (res.success) { items = res.data; } } else { items = await this.selectLocal(context, params); } if (items && items.length > 0) { items = items.sort((a: any, b: any) => a.srfordervalue - b.srfordervalue); for (let i = 0; i < items.length; i++) { let item = items[i]; item = this.filterEntityData(item); items[i] = item; } } return items; } /** * 更新本地数据 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ public async updateLocal(context: IContext = {}, data: IParam): Promise { try { let _data = null; if (this.isLocalStore) { _data = await this.db.update(context, this.newEntity(data, context)); } else { _data = this.cache.update(context, this.newEntity(data, context)); } return _data as T; } catch (error) { throw error; } } /** * 删除本地数据 * * @param {IContext} [context={}] * @param {string} srfKey * @return {*} {Promise} * @memberof DataServiceBase */ public async removeLocal(context: IContext = {}, srfKey: string): Promise { try { let data: any = null; if (this.isLocalStore) { data = await this.db.remove(context, srfKey); } else { data = this.cache.delete(context, srfKey); } return data; } catch (error) { throw error; } } /** * 查询本地数据,根据属性 * * @param {IContext} context * @param {IParam} params 根据多实体属性查找,例:{ name: '张三', age: 18, parent: null } * @return {*} {Promise} * @memberof DataBaseService */ async selectLocal(context: IContext, params: IParam = {}): Promise { let items: T[] = []; if (this.isLocalStore) { items = await this.db.search(context); } else { items = this.cache.getList(context); } items = ascSort(items, 'srfordervalue'); if (notNilEmpty(params) || notNilEmpty(context)) { // 查询数据条件集 const data: any = {}; const nullData: any = {}; const undefinedData: any = {}; if (params.srfkey) { data.srfkey = equals(params.srfkey); } if (this.selectContextParam) { for (const key in this.selectContextParam) { if (this.selectContextParam.hasOwnProperty(key)) { const val = this.selectContextParam[key]; if (notNilEmpty(context[key])) { data[val] = equals(context[key]); } } } } delete params.srfkey; for (const key in params) { if (params.hasOwnProperty(key)) { const val = params[key]; if (val == null) { nullData[key] = equals(null); undefinedData[key] = equals(undefined); } else { data[key] = equals(val); } } } if (!isEmpty(data)) { // 返回柯里化函数,用于判断数据是否满足要求 const pred = where(data); const nullPred = where(nullData); const undefinedPred = where(undefinedData); items = items.filter((obj) => { if (isEmpty(nullData)) { if (pred(obj)) { return true; } } else { if (pred(obj) && (nullPred(obj) || undefinedPred(obj))) { return true; } } }); } } const list = items.map((obj) => clone(obj)); console.warn('select', params, list); return list; } /** * 搜索本地数据 * * @protected * @param {PSDEDQCondEngine | null} cond 查询实例 * @param {SearchFilter} filter 过滤对象 * @param {string[]} [queryParamKeys=this.quickSearchFields] 当前实体支持快速搜索的属性 * @return {*} {Promise} * @memberof DataBaseService */ // protected async searchLocal( // cond: PSDEDQCondEngine | null, // filter: SearchFilter, // queryParamKeys: string[] = this.quickSearchFields, // ): Promise { // let list = []; // // 处理srfpkey // let srfpkey = null; // if (filter.data && filter.data.srfpkey) { // srfpkey = filter.data.srfpkey; // delete filter.data.srfpkey // } // // 走查询条件 // if (cond) { // if (this.isLocalStore) { // list = await this.db.search(filter.context); // } else { // list = this.cache.getList(filter.context); // } // if (list?.length > 0) { // list = list.filter(obj => cond.test(obj, filter)); // } // } else { // list = await this.selectLocal(filter.context, srfpkey ? { srfpkey } : {}); // if (list?.length > 0) { // // 识别query查询 // const condition = filter.data; // if (condition != null && !isEmpty(condition)) { // if (queryParamKeys) { // list = list.filter(obj => { // const reg = new RegExp(filter.query); // for (let i = 0; i < queryParamKeys.length; i++) { // const key = queryParamKeys[i]; // const val: string = obj[key]; // if (reg.test(val)) { // return true; // } // } // }); // } // } // } // } // if (!isNil(filter.sortField) && !isEmpty(filter.sortField)) { // if (filter.sortMode === 'DESC') { // // 倒序 // list = descSort(list, filter.sortField); // } else { // // 正序 // list = ascSort(list, filter.sortField); // } // } // const { page, size } = filter; // const start = page * size; // const end = (page + 1) * size; // const items = list.slice(start, end).map((item: any) => clone(item)); // console.warn('search', cond, items); // const headers = new Headers({ // 'x-page': page.toString(), // 'x-per-page': size.toString(), // 'x-total': list.length.toString(), // }); // return new HttpResponse(items, { headers }); // } /** * 搜索本地数据 * * @protected * @param {PSDEDQCondEngine | null} cond * @param {SearchFilter} filter * @return {*} {Promise} * @memberof DataBaseService */ // protected searchAppLocal(cond: PSDEDQCondEngine | null, filter: SearchFilter): Promise { // return this.searchLocal(cond, filter); // } /** * 新建本地数据 * * @param {IContext} context * @param {T} entity * @return {*} {Promise} * @memberof DataBaseService */ createAppLocal(context: IContext, entity: T): Promise { return this.CreateTemp(context, entity); } /** * 获取本地数据[弃用] * * @param {IContext} context * @param {IParam} [params] * @return {*} {Promise} * @memberof DataBaseService */ getAppLocal(context: IContext, params?: IParam): Promise { return this.GetTemp(context, params); } /** * 获取默认值[弃用] * * @param {IContext} context * @param {*} [params] * @return {*} {Promise} * @memberof DataBaseService */ getDraftAppLocal(context: IContext, params?: any): Promise { return this.GetDraftTemp(context, params); } /** * 更新本地数据 * * @param {IContext} context * @param {T} [entity] * @return {*} {Promise} * @memberof DataBaseService */ updateAppLocal(context: IContext, entity: T): Promise { return this.UpdateTemp(context, entity); } /** * 删除本地数据 * * @param {IContext} context * @param {IParam} [params] * @return {*} {Promise} * @memberof DataBaseService */ async removeAppLocal( context: IContext, params?: IParam ): Promise { return this.RemoveTemp(context, params); } /** * 获取本地默认数据集 * * @param {IContext} context * @param {IParam} [params] * @return {*} {Promise} * @memberof DataBaseService */ // selectAppLocal(context: IContext, params?: IParam): Promise { // return this.FetchDefault(context, params); // } // async FetchDefault(context: IContext, params?: IParam): Promise { // try { // await this.beforeExecuteAction(context, params, ); // const res = await this.searchLocal(null, new SearchFilter(context, params)); // await this.afterExecuteAction(context, res.data, 'FetchDefault'); // return res; // } catch (err) { // return new HttpResponse(err, { // ok: false, // status: 500, // }); // } // } /** * FetchTempDefault接口方法 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @returns {Promise} * @memberof DataBaseService */ public async FetchTempDefault( context: any = {}, data: any = {}, isloading?: boolean ): Promise { try { if (context && context.srfsessionkey) { const tempData = await this.getLocals(context); return new HttpResponse(tempData); } else { return new HttpResponse([]); } } catch (error) { return new HttpResponse(error, null, 500); } } /** * 导入数据 * * @param {IContext} [context={}] 应用上下文 * @param {IParam} [data={}] 导入数据 * @return {*} {Promise} * @memberof DataServiceBase */ async importData( context: IContext = {}, data: IParam = {} ): Promise { let _data: IParam[] = []; if (data && data.importData) { _data = data.importData; } return Http.getInstance().post( `/${this.appEntityCodeNames.toLowerCase()}/import?config=${ data.name }&ignoreerror=${data.ignoreerror ? true : false}`, _data ); } /** * 本地获取默认值 * * @param {IContext} [context={}] * @param {IParam} data * @return {*} {Promise} * @memberof DataServiceBase */ async getDraftLocal(context: IContext = {}, data: IParam): Promise { return this.newEntity(data, context); } /** * 执行实体逻辑 * * @template T * @param {string} tag * @param {IContext} context * @param {IParam} viewParams * @param {IParam[]} data * @param {MouseEvent} event * @param {T} ability * @return {*} {Promise} * @memberof DataServiceBase */ public executeDELogic( tag: string, context: IContext, viewParams: IParam, data: IParam[], event: MouseEvent, ability: T ): Promise { throw new Error('Method not implemented.'); } /** * WFGetWFStep接口方法(根据系统实体查找当前适配的工作流模型步骤) * * @param {*} [context={}] * @param {*} [data={}] * @returns {Promise} * @memberof EntityService */ public async getWFStep( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance()[App.getProjectSetting().appRequestMode]( `/wfcore/${ this.systemName }-app-${this.appEntityCodeName.toLowerCase()}/${this.appEntityCodeName.toLowerCase()}/process-definitions-nodes` ); } /** * GetWFLink接口方法(根据业务主键和当前步骤获取操作路径) * * @param {*} [context={}] * @param {*} [data={}] * @returns {Promise} * @memberof EntityService */ public async getWFLink( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance()[App.getProjectSetting().appRequestMode]( `/wfcore/${this.systemName}-app-${ this.appName }/${this.appEntityCodeNames.toLowerCase()}/${ context[this.appEntityCodeName.toLowerCase()] }/usertasks/${data['taskDefinitionKey']}/ways` ); } /** * GetWFHistory接口方法(根据业务主键获取工作流程记录) * * @param {IContext} [context={}] * @param {IParam} [data={}] * @return {*} {Promise} * @memberof DataServiceBase */ public async GetWFHistory( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance()[App.getProjectSetting().appRequestMode]( `/wfcore/${this.systemName}-app-${ this.appName }/${this.appEntityCodeNames.toLowerCase()}/${ context[this.appEntityCodeName.toLowerCase()] }/process-instances/alls/history` ); } /** * WFSubmit接口方法 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @param {*} [localdata] * @returns {Promise} * @memberof EntityService */ public async WFSubmit( context: any = {}, data: any = {}, localdata?: any ): Promise { if (localdata && Object.keys(localdata).length > 0) { const requestData: any = {}; if (data.viewparams) { delete data.viewparams; } Object.assign(requestData, { activedata: data }); Object.assign(requestData, localdata); return Http.getInstance().post( `/wfcore/${this.systemName}-app-${ this.appName }/${this.appEntityCodeNames.toLowerCase()}/${ data[this.appEntityKeyCodeName.toLowerCase()] }/tasks/${localdata['taskId']}`, requestData ); } else { const requestData: any = {}; if (data.srfwfmemo) { requestData.srfwfmemo = JSON.parse(JSON.stringify(data)).srfwfmemo; delete data.srfwfmemo; } if (data.viewparams) { delete data.viewparams; } Object.assign(requestData, { wfdata: data }); Object.assign(requestData, { opdata: { srfwfiatag: context.srfwfiatag, srfwfstep: context.srfwfstep, }, }); return Http.getInstance().post( `/${this.systemName}/${ data[this.appEntityCodeNames.toLowerCase()] }/wfsubmit`, requestData ); } } /** * WFStart接口方法 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @param {*} [localdata] * @returns {Promise} * @memberof EntityService */ public async WFStart( context: IContext = {}, data: IParam = {}, localdata: IParam = {} ): Promise { if (localdata && Object.keys(localdata).length > 0) { const requestData: any = {}; Object.assign(requestData, { activedata: data }); Object.assign(requestData, localdata); return Http.getInstance().post( `/wfcore/${this.systemName}-app-${ this.appName }/${this.appEntityCodeNames.toLowerCase()}/${ data[this.appEntityKeyCodeName] }/process-instances`, requestData ); } else { const requestData: any = {}; Object.assign(requestData, { wfdata: data }); return Http.getInstance().post( `/${this.appEntityCodeNames.toLowerCase()}/${ data[this.appEntityKeyCodeName] }/wfstart`, requestData ); } } /** * 获取标准工作流版本信息 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @return {*} {Promise} * @memberof DataServiceBase */ public async getStandWorkflow( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance()[App.getProjectSetting().appRequestMode]( `/wfcore/${this.systemName.toLowerCase()}-app-${this.appName.toLowerCase()}/${this.appEntityCodeNames.toLowerCase()}/process-definitions` ); } /** * 前加签 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @return {*} {Promise} * @memberof EntityService */ public async BeforeSign( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance().post( `/wfcore/${this.systemName.toLowerCase()}-app-${this.appName.toLowerCase()}/${this.appEntityCodeNames.toLowerCase()}/${ context[this.appEntityCodeName] }/tasks/${context.taskId}/beforesign`, data ); } /** * 转办 * * @param {*} [context={}] * @param {*} [data={}] * @param {boolean} [isloading] * @return {*} {Promise} * @memberof EntityService */ public async TransFerTask( context: IContext = {}, data: IParam = {} ): Promise { return Http.getInstance().post( `/wfcore/${this.systemName.toLowerCase()}-app-${this.appName.toLowerCase()}/${this.appEntityCodeNames.toLowerCase()}/${ context[this.appEntityCodeName] }/tasks/${context.taskId}/transfer`, data ); } /** * @description 获取预定义代码表 * @param {string} tag * @param {*} [data={}] * @return {*} {Promise} * @memberof DataServiceBase */ public async getPredefinedCodelist(tag: string, data: any = {}): Promise { return Http.getInstance()[App.getProjectSetting().appRequestMode]( `/dictionaries/codelist/${tag}`, data ); } }