From 536c75493ce832f536b80bf3972c03ee5247c3f7 Mon Sep 17 00:00:00 2001 From: ly525 Date: Mon, 28 Jun 2021 12:42:36 +0800 Subject: [PATCH 1/3] feat(api): config response data path & msg path --- src/actions/api.js | 111 ++++++++++++++++----------------- src/ams/configs/alias/field.js | 24 +++---- src/utils/api.js | 60 ++++++++++++++++++ src/utils/index.js | 1 + 4 files changed, 124 insertions(+), 72 deletions(-) create mode 100644 src/utils/api.js diff --git a/src/actions/api.js b/src/actions/api.js index 1a5a76bd..07193016 100644 --- a/src/actions/api.js +++ b/src/actions/api.js @@ -1,5 +1,5 @@ import ams from '../ams'; -import { getQueryString, getType, isFn } from '../utils'; +import { getQueryString, getType, isFn, responseHandler } from '../utils'; import { httpRequestTypeExcludeGet } from '../ams/request'; /** @@ -112,19 +112,14 @@ export const read = ams.createApiAction({ }; }, success(res) { - const successCode = this.getConfig('resource.api.read.successCode') || this.getConfig('resource.api.successCode'); - if (res.data.code === successCode) { - const config = this.resource.api.read; - if (typeof config === 'object' && typeof config.transform === 'function') { - this.setBlockData(config.transform(res.data.data)); - } else if (typeof config === 'object' && typeof config.responseDataParse === 'function') { - this.setBlockData(config.responseDataParse(res.data)); - } else { - this.setBlockData(res.data.data); - } + const { message, code, isSuccess, data } = responseHandler.call(this, res, 'read'); + if (isSuccess) { + const { transform, responseDataParse } = this.resource.api.read || {}; + const handler = transform || responseDataParse || (data => data); + this.setBlockData(handler(data)); } else { - this.$message.error(`${res.data.msg}(${res.data.code})`); - throw '@read:' + res.data.code; + this.$message.error(`${message}(${code})`); + throw '@read:' + code; } return res; } @@ -160,16 +155,14 @@ export const update = ams.createApiAction({ }; }, success(res) { - // 默认successCode - const successCode = this.getConfig('resource.api.update.successCode') || this.getConfig('resource.api.successCode'); - if (res.data.code === successCode) { + const { isSuccess, message, code, data } = responseHandler.call(this, res, 'update'); + if (isSuccess) { this.$message.success('更新成功'); - if (typeof this.on['update-success'] === 'function') { - this.on['update-success'](res.data); - } + const onSuccess = this.on['update-success']; + if (isFn(onSuccess)) onSuccess(data); } else { - this.$message.error(`${res.data.msg}(${res.data.code})`); - throw '@update:' + res.data.code; + this.$message.error(`${message}(${code})`); + throw '@update:' + code; } return res; } @@ -206,16 +199,14 @@ export const deleteAction = ams.createApiAction({ }; }, success(res) { - // 默认successCode - const successCode = this.getConfig('resource.api.delete.successCode') || this.getConfig('resource.api.successCode'); - if (res.data.code === successCode) { + const { isSuccess, message, code, data } = responseHandler.call(this, res, 'delete'); + if (isSuccess) { this.$message.success('删除成功'); - if (typeof this.on['delete-success'] === 'function') { - this.on['delete-success'](res.data); - } + const onSuccess = this.on['delete-success']; + if (isFn(onSuccess)) onSuccess(data); } else { - this.$message.error(`${res.data.msg}(${res.data.code})`); - throw '@delete:' + res.data.code; + this.$message.error(`${message}(${code})`); + throw '@delete:' + code; } return res; } @@ -245,21 +236,21 @@ export const create = ams.createApiAction({ }; }, success(res) { - // 默认successCode - const successCode = this.getConfig('resource.api.create.successCode') || this.getConfig('resource.api.successCode'); - if (res.data.code === successCode) { + const { isSuccess, message, code, data } = responseHandler.call(this, res, 'create'); + if (isSuccess) { this.$message.success('创建成功'); - if (typeof this.on['create-success'] === 'function') { - this.on['create-success'](res.data); - } + const onSuccess = this.on['create-success']; + if (isFn(onSuccess)) onSuccess(data); } else { - this.$message.error(`${res.data.msg}(${res.data.code})`); - throw '@create code:' + res.data.code; + this.$message.error(`${message}(${code})`); + throw '@create code:' + code; } return res; } }); +// https://github.com/vipshop/ams/blob/5c8e0112c3b8e42c4bed9ff658767bbdbcf9bbd4/src/ams/request.js#L162 +// createApiAction -> src/ams/request.js export const list = ams.createApiAction({ getOptions(params) { // 使用传入页数,如搜索使用 @list:1 将页数重置为1 @@ -336,35 +327,39 @@ export const list = ams.createApiAction({ params: arg }; }, + /** + * + * @param {*} res { status: statusCode, data: JSON.parse(xhr.responseText) } + */ success(res) { - // 默认successCode - const successCode = this.getConfig('resource.api.list.successCode') || this.getConfig('resource.api.successCode'); - if ( - res.data.code === successCode && - res.data.data - ) { - const config = this.resource.api.list; - this.data.total = res.data.data.total; + const { message, code, isSuccess, data, getter } = responseHandler.call(this, res, 'list'); + if (isSuccess) { + const total = data[getter.totalPath]; + const list = data[getter.listPath]; + this.data.list = list; + this.data.total = total; + + const { transform, responseDataParse } = this.resource.api.list || {}; + if (isFn(transform)) { + this.data.list = transform(data); - if (typeof config === 'object' && typeof config.transform === 'function') { - this.data.list = config.transform(res.data.data.list) || []; - } else if (typeof config === 'object' && typeof config.responseDataParse === 'function') { - const convertResponseDataParse = config.responseDataParse(res.data); - if (getType(convertResponseDataParse) !== 'object') { + } else if (isFn(responseDataParse)) { + const parsedData = responseDataParse(data); + if (getType(parsedData) !== 'object') { console.error('responseDataParse中需要返回object类型,如{ list: [] }'); this.data.list = []; } else { - this.data = { ...this.data, ...config.responseDataParse(res.data) }; + this.data = { + ...this.data, + ...parsedData + }; } - } else { - this.data.list = res.data.data.list || []; - } - if (typeof this.on['list-success'] === 'function') { - this.on['list-success'](res.data); } + const onSuccess = this.on['list-success']; + if (isFn(onSuccess)) onSuccess(data); } else { - this.$message.error(`${res.data.msg}(${res.data.code})`); - throw '@list:' + res.data.code; + this.$message.error(`${message}(${code})`); + throw '@list:' + code; } return res; diff --git a/src/ams/configs/alias/field.js b/src/ams/configs/alias/field.js index ac5e7890..2af5fac2 100644 --- a/src/ams/configs/alias/field.js +++ b/src/ams/configs/alias/field.js @@ -1,4 +1,6 @@ -import { deepExtend, get } from '../../../utils'; +/* eslint-disable complexity,no-new,max-depth */ + +import { deepExtend, responseHandler } from '../../../utils'; import * as fieldGetSet from '../field-get-set'; import { httpRequestTypeExcludeGet } from '../../request'; @@ -171,19 +173,13 @@ export const SELECT_REMOTE = { $field.loading = true; const res = await remoteConfig.request.call(this, $field, query, isBackfill); $field.loading = false; - - let data = get(res.data, remoteConfig.dataPath); - let successCode; - - if (typeof remoteConfig.successCode !== 'undefined') { - successCode = remoteConfig.successCode; - } else { - successCode = this.getConfig('resource.api.successCode'); - } - if ( - res.data.code === successCode && - data - ) { + // eslint-disable-next-line no-unused-vars + const { isSuccess, data } = responseHandler.call(this, res, '', { + dataPath: remoteConfig.dataPath, // 'data.list', + successCode: remoteConfig.successCode || this.getConfig('resource.api.successCode'), + codePath: remoteConfig.codePath || this.getConfig('resource.api.code') || 'code' + }); + if (isSuccess && data) { const options = remoteConfig.transform.call(this, $field, data); const optionsEntity = options.reduce((obj, cur) => Object.assign(obj, { [cur.label]: cur.value }), {}); if (remoteConfig.isCache) { diff --git a/src/utils/api.js b/src/utils/api.js new file mode 100644 index 00000000..34362e70 --- /dev/null +++ b/src/utils/api.js @@ -0,0 +1,60 @@ +import { get as lodashGet } from 'lodash'; + +const defaultGetter = { + codePath: 'code', + successCode: 0, + dataPath: 'data', + totalPath: 'total', + listPath: 'list', + messagePath: 'msg', +}; + +/** + * 从 API Response 中获取相关字段,如是否成功、total、data 等 + * https://github.com/vipshop/ams/pull/125 + * + * @param {Object} response : api response data + * @param {String} action : read/update/list/delete 增删改查 + * @param {Object} actionGetter : 适配更多接口的返回值 + * + * ams 默认接口数据结构: https://vipshop.github.io/ams/api/api.html#%E9%80%9A%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84 + * + * -------常规请求---------- + * { + [codePath]: [successCode], + [dataPath]: String, + [messagePath]: String + * } + * + * + * ------- 列表请求---------- + * { + [codePath]: [successCode], + [dataPath]: { + [dataPath.listPath]: [], + [dataPath.totalPath]: Number, + }, + [messagePath]: String + * } + * + * + */ +export function responseHandler(response, action, actionGetter) { + const configGetter = this.getConfig(`resource.api.${action}.getter`); + const getter = { + ...defaultGetter, + ...actionGetter, + ...configGetter + }; + + const code = lodashGet(response.data, getter.codePath); // api response(success/result)对应的值 + // eslint-disable-next-line + const isSuccess = code == getter.successCode; + return { + code, + getter, + isSuccess, + data: lodashGet(response.data, getter.dataPath), + message: lodashGet(response.data, getter.messagePath), + }; +} \ No newline at end of file diff --git a/src/utils/index.js b/src/utils/index.js index 0d3a5bd2..f5c864ac 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -4,6 +4,7 @@ export * from './dom'; export * from './function'; export * from './tools'; export * from './localstorage'; +export * from './api'; export function get(object, path) { path = path.split('.'); From 1315770a1251b1d1a1c531c5b4d6a5739b03f94b Mon Sep 17 00:00:00 2001 From: ly525 Date: Mon, 28 Jun 2021 14:11:39 +0800 Subject: [PATCH 2/3] fix: transform data.list for list request --- src/actions/api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/actions/api.js b/src/actions/api.js index 07193016..18f9fd3d 100644 --- a/src/actions/api.js +++ b/src/actions/api.js @@ -341,8 +341,7 @@ export const list = ams.createApiAction({ const { transform, responseDataParse } = this.resource.api.list || {}; if (isFn(transform)) { - this.data.list = transform(data); - + this.data.list = transform(list); } else if (isFn(responseDataParse)) { const parsedData = responseDataParse(data); if (getType(parsedData) !== 'object') { From d7c752a4ff4f88e2b8ca15a85443f6ddec0e84e1 Mon Sep 17 00:00:00 2001 From: ly525 Date: Sat, 10 Jul 2021 23:42:37 +0800 Subject: [PATCH 3/3] fix: merge data with Object.assign --- src/actions/api.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/actions/api.js b/src/actions/api.js index 18f9fd3d..c2bfba6e 100644 --- a/src/actions/api.js +++ b/src/actions/api.js @@ -343,15 +343,17 @@ export const list = ams.createApiAction({ if (isFn(transform)) { this.data.list = transform(list); } else if (isFn(responseDataParse)) { - const parsedData = responseDataParse(data); + const parsedData = responseDataParse({ + ...res, + msg: message, + code, + data + }); if (getType(parsedData) !== 'object') { console.error('responseDataParse中需要返回object类型,如{ list: [] }'); this.data.list = []; } else { - this.data = { - ...this.data, - ...parsedData - }; + Object.assign(this.data, parsedData); } } const onSuccess = this.on['list-success'];