import { transformArrayToMap, isJSFunction, transformStringToFunction, clone } from './index'; import { jsonp, mtop, request, get, post, bzb } from './request'; const DS_STATUS = { INIT: 'init', LOADING: 'loading', LOADED: 'loaded', ERROR: 'error' }; export default class DataHelper { constructor(comp, config = {}, appHelper, parser) { this.host = comp; this.config = config; this.parser = parser; this.ajaxList = (config && config.list) || []; this.ajaxMap = transformArrayToMap(this.ajaxList, 'id'); this.dataSourceMap = this.generateDataSourceMap(); this.appHelper = appHelper; } // 重置config,dataSourceMap状态会被重置; resetConfig(config = {}) { this.config = config; this.ajaxList = (config && config.list) || []; this.ajaxMap = transformArrayToMap(this.ajaxList, 'id'); this.dataSourceMap = this.generateDataSourceMap(); return this.dataSourceMap; } // 更新config,只会更新配置,状态保存; updateConfig(config = {}) { this.config = config; this.ajaxList = (config && config.list) || []; const ajaxMap = transformArrayToMap(this.ajaxList, 'id'); // 删除已经移除的接口 Object.keys(this.ajaxMap).forEach(key => { if (!ajaxMap[key]) { delete this.dataSourceMap[key]; } }); this.ajaxMap = ajaxMap; // 添加未加入到dataSourceMap中的接口 this.ajaxList.forEach(item => { if (!this.dataSourceMap[item.id]) { this.dataSourceMap[item.id] = { status: DS_STATUS.INIT, load: (...args) => { return this.getDataSource(item.id, ...args); } }; } }); return this.dataSourceMap; } generateDataSourceMap() { const res = {}; this.ajaxList.forEach(item => { res[item.id] = { status: DS_STATUS.INIT, load: (...args) => { return this.getDataSource(item.id, ...args); } }; }); return res; } updateDataSourceMap(id, data, error) { this.dataSourceMap[id].error = error ? error : undefined; this.dataSourceMap[id].data = data; this.dataSourceMap[id].status = error ? DS_STATUS.ERROR : DS_STATUS.LOADED; } getInitData() { const initSyncData = this.parser(this.ajaxList).filter(item => { if (item.isInit) { this.dataSourceMap[item.id].status = DS_STATUS.LOADING; return true; } return false; }); return this.asyncDataHandler(initSyncData).then(res => { let dataHandler = this.config.dataHandler; if (isJSFunction(dataHandler)) { dataHandler = transformStringToFunction(dataHandler.value); } if (!dataHandler || typeof dataHandler !== 'function') return res; try { return dataHandler.call(this.host, res); } catch (e) { console.error('请求数据处理函数运行出错', e); return; } }); } getDataSource(id, params, otherOptions, callback) { const req = this.parser(this.ajaxMap[id]); const options = req.options || {}; if (typeof otherOptions === 'function') { callback = otherOptions; otherOptions = {}; } const { headers, ...otherProps } = otherOptions || {}; if (!req) { console.warn(`getDataSource API named ${id} not exist`); return; } return this.asyncDataHandler([ { ...req, options: { ...options, // 支持参数为array的情况,当参数为array时,不做参数合并 params: Array.isArray(options.params) || Array.isArray(params) ? params || options.params : { ...options.params, ...params }, headers: { ...options.headers, ...headers }, ...otherProps } } ]) .then(res => { try { callback && callback(res && res[id]); } catch (e) { console.error('load请求回调函数报错', e); } return res && res[id]; }) .catch(err => { try { callback && callback(null, err); } catch (e) { console.error('load请求回调函数报错', e); } return err; }); } asyncDataHandler(asyncDataList) { return new Promise((resolve, reject) => { const allReq = []; const doserReq = []; const doserList = []; const beforeRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.beforeRequest; const afterRequest = this.appHelper && this.appHelper.utils && this.appHelper.utils.afterRequest; const csrfInput = document.getElementById('_csrf_token'); const _tb_token_ = csrfInput && csrfInput.value; asyncDataList.map(req => { const { id, type, options } = req; if (!id || !type) return; if (type === 'doServer') { const { uri, params } = options || {}; if (!uri) return; doserList.push(id); doserReq.push({ name: uri, package: 'cms', params }); } else { allReq.push(req); } }); if (doserReq.length > 0) { allReq.push({ type: 'doServer', options: { uri: '/nrsService.do', cors: true, method: 'POST', params: { data: JSON.stringify(doserReq), _tb_token_ } } }); } if (allReq.length === 0) resolve({}); const res = {}; Promise.all( allReq.map(item => { return new Promise(resolve => { const { type, id, dataHandler, options } = item; const doFetch = (type, options) => { this.fetchOne(type, options) .then(async data => { if (afterRequest) { this.appHelper.utils.afterRequest(item, data, undefined, async (data, error) => { await fetchHandler(data, error); }); } else { await fetchHandler(data, undefined); } }) .catch(async err => { if (afterRequest) { // 必须要这么调用,否则beforeRequest中的this会丢失 this.appHelper.utils.afterRequest(item, undefined, err, async (data, error) => { await fetchHandler(data, error); }); } else { await fetchHandler(undefined, err); } }); }; const fetchHandler = async (data, error) => { if (type === 'doServer') { if (!Array.isArray(data)) { data = [data]; } doserList.forEach(async (id, idx) => { const req = this.ajaxMap[id]; if (req) { res[id] = await this.dataHandler(id, req.dataHandler, data && data[idx], error); this.updateDataSourceMap(id, res[id], error); } }); } else { res[id] = await this.dataHandler(id, dataHandler, data, error); this.updateDataSourceMap(id, res[id], error); } resolve(); }; if (type === 'doServer') { doserList.forEach(item => { this.dataSourceMap[item].status = DS_STATUS.LOADING; }); } else { this.dataSourceMap[id].status = DS_STATUS.LOADING; } // 请求切片 if (beforeRequest) { // 必须要这么调用,否则beforeRequest中的this会丢失 this.appHelper.utils.beforeRequest(item, clone(options), options => doFetch(type, options)); } else { doFetch(type, options); } }); }) ) .then(() => { resolve(res); }) .catch(e => { reject(e); }); }); } async dataHandler(id, dataHandler, data, error) { if (isJSFunction(dataHandler)) { dataHandler = transformStringToFunction(dataHandler.value); } if (!dataHandler || typeof dataHandler !== 'function') return data; try { return await dataHandler.call(this.host, data, error); } catch (e) { console.error('[' + id + ']单个请求数据处理函数运行出错', e); return; } } fetchOne(type, options) { let { uri, method = 'GET', headers, params, ...otherProps } = options; otherProps = otherProps || {}; switch (type) { case 'mtop': method && (otherProps.method = method); return mtop(uri, params, otherProps); case 'jsonp': return jsonp(uri, params, otherProps); case 'bzb': return bzb(uri, params, { method, headers, ...otherProps }); default: method = method.toUpperCase(); if (method === 'GET') { return get(uri, params, headers, otherProps); } else if (method === 'POST') { return post(uri, params, headers, otherProps); } return request(uri, method, params, headers, otherProps); } } }