2020-06-21 17:47:49 +08:00

300 lines
9.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
// 重置configdataSourceMap状态会被重置
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);
}
}
}